diff options
244 files changed, 24798 insertions, 2007 deletions
diff --git a/Documentation/networking/nfc.txt b/Documentation/networking/nfc.txt new file mode 100644 index 000000000000..b24c29bdae27 --- /dev/null +++ b/Documentation/networking/nfc.txt @@ -0,0 +1,128 @@ +Linux NFC subsystem +=================== + +The Near Field Communication (NFC) subsystem is required to standardize the +NFC device drivers development and to create an unified userspace interface. + +This document covers the architecture overview, the device driver interface +description and the userspace interface description. + +Architecture overview +--------------------- + +The NFC subsystem is responsible for: + - NFC adapters management; + - Polling for targets; + - Low-level data exchange; + +The subsystem is divided in some parts. The 'core' is responsible for +providing the device driver interface. On the other side, it is also +responsible for providing an interface to control operations and low-level +data exchange. + +The control operations are available to userspace via generic netlink. + +The low-level data exchange interface is provided by the new socket family +PF_NFC. The NFC_SOCKPROTO_RAW performs raw communication with NFC targets. + + + +--------------------------------------+ + | USER SPACE | + +--------------------------------------+ + ^ ^ + | low-level | control + | data exchange | operations + | | + | v + | +-----------+ + | AF_NFC | netlink | + | socket +-----------+ + | raw ^ + | | + v v + +---------+ +-----------+ + | rawsock | <--------> | core | + +---------+ +-----------+ + ^ + | + v + +-----------+ + | driver | + +-----------+ + +Device Driver Interface +----------------------- + +When registering on the NFC subsystem, the device driver must inform the core +of the set of supported NFC protocols and the set of ops callbacks. The ops +callbacks that must be implemented are the following: + +* start_poll - setup the device to poll for targets +* stop_poll - stop on progress polling operation +* activate_target - select and initialize one of the targets found +* deactivate_target - deselect and deinitialize the selected target +* data_exchange - send data and receive the response (transceive operation) + +Userspace interface +-------------------- + +The userspace interface is divided in control operations and low-level data +exchange operation. + +CONTROL OPERATIONS: + +Generic netlink is used to implement the interface to the control operations. +The operations are composed by commands and events, all listed below: + +* NFC_CMD_GET_DEVICE - get specific device info or dump the device list +* NFC_CMD_START_POLL - setup a specific device to polling for targets +* NFC_CMD_STOP_POLL - stop the polling operation in a specific device +* NFC_CMD_GET_TARGET - dump the list of targets found by a specific device + +* NFC_EVENT_DEVICE_ADDED - reports an NFC device addition +* NFC_EVENT_DEVICE_REMOVED - reports an NFC device removal +* NFC_EVENT_TARGETS_FOUND - reports START_POLL results when 1 or more targets +are found + +The user must call START_POLL to poll for NFC targets, passing the desired NFC +protocols through NFC_ATTR_PROTOCOLS attribute. The device remains in polling +state until it finds any target. However, the user can stop the polling +operation by calling STOP_POLL command. In this case, it will be checked if +the requester of STOP_POLL is the same of START_POLL. + +If the polling operation finds one or more targets, the event TARGETS_FOUND is +sent (including the device id). The user must call GET_TARGET to get the list of +all targets found by such device. Each reply message has target attributes with +relevant information such as the supported NFC protocols. + +All polling operations requested through one netlink socket are stopped when +it's closed. + +LOW-LEVEL DATA EXCHANGE: + +The userspace must use PF_NFC sockets to perform any data communication with +targets. All NFC sockets use AF_NFC: + +struct sockaddr_nfc { + sa_family_t sa_family; + __u32 dev_idx; + __u32 target_idx; + __u32 nfc_protocol; +}; + +To establish a connection with one target, the user must create an +NFC_SOCKPROTO_RAW socket and call the 'connect' syscall with the sockaddr_nfc +struct correctly filled. All information comes from NFC_EVENT_TARGETS_FOUND +netlink event. As a target can support more than one NFC protocol, the user +must inform which protocol it wants to use. + +Internally, 'connect' will result in an activate_target call to the driver. +When the socket is closed, the target is deactivated. + +The data format exchanged through the sockets is NFC protocol dependent. For +instance, when communicating with MIFARE tags, the data exchanged are MIFARE +commands and their responses. + +The first received package is the response to the first sent package and so +on. In order to allow valid "empty" responses, every data received has a NULL +header of 1 byte. diff --git a/drivers/Kconfig b/drivers/Kconfig index 61631edfecc2..a56b0b83872e 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -92,8 +92,6 @@ source "drivers/memstick/Kconfig" source "drivers/leds/Kconfig" -source "drivers/nfc/Kconfig" - source "drivers/accessibility/Kconfig" source "drivers/infiniband/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index a29527f4ded6..843cd31a849e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -120,3 +120,4 @@ obj-y += ieee802154/ obj-y += clk/ obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ +obj-$(CONFIG_NFC) += nfc/ diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 83e9adf46441..ae0a02e1b808 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -27,6 +27,12 @@ config BCMA_HOST_PCI bool "Support for BCMA on PCI-host bus" depends on BCMA_HOST_PCI_POSSIBLE +config BCMA_DRIVER_PCI_HOSTMODE + bool "Driver for PCI core working in hostmode" + depends on BCMA && MIPS + help + PCI core hostmode operation (external PCI bus). + config BCMA_DEBUG bool "BCMA debugging" depends on BCMA diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index cde0182bd1dc..a2161cceafb9 100644 --- a/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile @@ -1,6 +1,7 @@ bcma-y += main.o scan.o core.o sprom.o bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o bcma-y += driver_pci.o +bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o obj-$(CONFIG_BCMA) += bcma.o diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 4228736de0e8..e02ff21835c9 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -28,4 +28,8 @@ extern int __init bcma_host_pci_init(void); extern void __exit bcma_host_pci_exit(void); #endif /* CONFIG_BCMA_HOST_PCI */ +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE +void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc); +#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ + #endif diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index b0c19ede0d2e..dc6f34ac96a0 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -157,11 +157,47 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc) * Init. **************************************************/ -void bcma_core_pci_init(struct bcma_drv_pci *pc) +static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) { bcma_pcicore_serdes_workaround(pc); } +static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) +{ + struct bcma_bus *bus = pc->core->bus; + u16 chipid_top; + + chipid_top = (bus->chipinfo.id & 0xFF00); + if (chipid_top != 0x4700 && + chipid_top != 0x5300) + return false; + + if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI) + return false; + +#if 0 + /* TODO: on BCMA we use address from EROM instead of magic formula */ + u32 tmp; + return !mips_busprobe32(tmp, (bus->mmio + + (pc->core->core_index * BCMA_CORE_SIZE))); +#endif + + return true; +} + +void bcma_core_pci_init(struct bcma_drv_pci *pc) +{ + if (bcma_core_pci_is_in_hostmode(pc)) { +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE + bcma_core_pci_hostmode_init(pc); +#else + pr_err("Driver compiled without support for hostmode PCI\n"); +#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ + } else { + bcma_core_pci_clientmode_init(pc); + } +} + int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, bool enable) { diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c new file mode 100644 index 000000000000..eb332b75ce83 --- /dev/null +++ b/drivers/bcma/driver_pci_host.c @@ -0,0 +1,14 @@ +/* + * Broadcom specific AMBA + * PCI Core in hostmode + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include <linux/bcma/bcma.h> + +void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) +{ + pr_err("No support for PCI core in hostmode yet\n"); +} diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index ba15105cc23a..08a14a3d667e 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -7,6 +7,7 @@ #include "bcma_private.h" #include <linux/bcma/bcma.h> +#include <linux/slab.h> MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index c38e9e848995..ba682a0b2dd8 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -167,8 +167,8 @@ static int ath_ahb_probe(struct platform_device *pdev) * driver for it */ if (to_platform_device(sc->dev)->id == 0 && - (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) == - (BD_WLAN1|BD_WLAN0)) + (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) == + (BD_WLAN1 | BD_WLAN0)) __set_bit(ATH_STAT_2G_DISABLED, sc->status); } diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index f915f404302d..a08f17318e63 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -642,7 +642,7 @@ ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode) /* initial values for our ani parameters */ if (mode == ATH5K_ANI_MODE_OFF) { ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI off\n"); - } else if (mode == ATH5K_ANI_MODE_MANUAL_LOW) { + } else if (mode == ATH5K_ANI_MODE_MANUAL_LOW) { ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI manual low -> high sensitivity\n"); ath5k_ani_set_noise_immunity_level(ah, 0); diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index c4c02d5145c2..b1de4a09c8c8 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -39,40 +39,41 @@ #include "../ath.h" /* PCI IDs */ -#define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */ -#define PCI_DEVICE_ID_ATHEROS_AR5311 0x0011 /* AR5311 */ -#define PCI_DEVICE_ID_ATHEROS_AR5211 0x0012 /* AR5211 */ -#define PCI_DEVICE_ID_ATHEROS_AR5212 0x0013 /* AR5212 */ -#define PCI_DEVICE_ID_3COM_3CRDAG675 0x0013 /* 3CRDAG675 (Atheros AR5212) */ -#define PCI_DEVICE_ID_3COM_2_3CRPAG175 0x0013 /* 3CRPAG175 (Atheros AR5212) */ -#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 0x0207 /* AR5210 (Early) */ +#define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */ +#define PCI_DEVICE_ID_ATHEROS_AR5311 0x0011 /* AR5311 */ +#define PCI_DEVICE_ID_ATHEROS_AR5211 0x0012 /* AR5211 */ +#define PCI_DEVICE_ID_ATHEROS_AR5212 0x0013 /* AR5212 */ +#define PCI_DEVICE_ID_3COM_3CRDAG675 0x0013 /* 3CRDAG675 (Atheros AR5212) */ +#define PCI_DEVICE_ID_3COM_2_3CRPAG175 0x0013 /* 3CRPAG175 (Atheros AR5212) */ +#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 0x0207 /* AR5210 (Early) */ #define PCI_DEVICE_ID_ATHEROS_AR5212_IBM 0x1014 /* AR5212 (IBM MiniPCI) */ -#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 0x1107 /* AR5210 (no eeprom) */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 0x1113 /* AR5212 (no eeprom) */ -#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 0x1112 /* AR5211 (no eeprom) */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 0xf013 /* AR5212 (emulation board) */ -#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 0xff12 /* AR5211 (emulation board) */ -#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 0xf11b /* AR5211 (emulation board) */ -#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ -#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ -#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 0x0058 /* AR5312 WMAC (AP43-030) */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 0x0014 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 0x0015 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 0x0016 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 0x0017 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 0x0018 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 0x0019 /* AR5212 compatible */ -#define PCI_DEVICE_ID_ATHEROS_AR2413 0x001a /* AR2413 (Griffin-lite) */ -#define PCI_DEVICE_ID_ATHEROS_AR5413 0x001b /* AR5413 (Eagle) */ -#define PCI_DEVICE_ID_ATHEROS_AR5424 0x001c /* AR5424 (Condor PCI-E) */ -#define PCI_DEVICE_ID_ATHEROS_AR5416 0x0023 /* AR5416 */ -#define PCI_DEVICE_ID_ATHEROS_AR5418 0x0024 /* AR5418 */ +#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 0x1107 /* AR5210 (no eeprom) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 0x1113 /* AR5212 (no eeprom) */ +#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 0x1112 /* AR5211 (no eeprom) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 0xf013 /* AR5212 (emulation board) */ +#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 0xff12 /* AR5211 (emulation board) */ +#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 0xf11b /* AR5211 (emulation board) */ +#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ +#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ +#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 0x0058 /* AR5312 WMAC (AP43-030) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 0x0014 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 0x0015 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 0x0016 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 0x0017 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 0x0018 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 0x0019 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR2413 0x001a /* AR2413 (Griffin-lite) */ +#define PCI_DEVICE_ID_ATHEROS_AR5413 0x001b /* AR5413 (Eagle) */ +#define PCI_DEVICE_ID_ATHEROS_AR5424 0x001c /* AR5424 (Condor PCI-E) */ +#define PCI_DEVICE_ID_ATHEROS_AR5416 0x0023 /* AR5416 */ +#define PCI_DEVICE_ID_ATHEROS_AR5418 0x0024 /* AR5418 */ /****************************\ GENERIC DRIVER DEFINITIONS \****************************/ -#define ATH5K_PRINTF(fmt, ...) printk("%s: " fmt, __func__, ##__VA_ARGS__) +#define ATH5K_PRINTF(fmt, ...) \ + printk(KERN_WARNING "%s: " fmt, __func__, ##__VA_ARGS__) #define ATH5K_PRINTK(_sc, _level, _fmt, ...) \ printk(_level "ath5k %s: " _fmt, \ @@ -361,7 +362,7 @@ struct ath5k_srev_name { /* * Some of this information is based on Documentation from: * - * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG + * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG * * Modulation for Atheros' eXtended Range - range enhancing extension that is * supposed to double the distance an Atheros client device can keep a @@ -374,7 +375,7 @@ struct ath5k_srev_name { * they are exclusive. * */ -#define MODULATION_XR 0x00000200 +#define MODULATION_XR 0x00000200 /* * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s @@ -495,9 +496,9 @@ enum ath5k_tx_queue { */ enum ath5k_tx_queue_subtype { AR5K_WME_AC_BK = 0, /*Background traffic*/ - AR5K_WME_AC_BE, /*Best-effort (normal) traffic)*/ - AR5K_WME_AC_VI, /*Video traffic*/ - AR5K_WME_AC_VO, /*Voice traffic*/ + AR5K_WME_AC_BE, /*Best-effort (normal) traffic)*/ + AR5K_WME_AC_VI, /*Video traffic*/ + AR5K_WME_AC_VO, /*Voice traffic*/ }; /* @@ -616,8 +617,8 @@ struct ath5k_rx_status { #define AR5K_RXERR_FIFO 0x04 #define AR5K_RXERR_DECRYPT 0x08 #define AR5K_RXERR_MIC 0x10 -#define AR5K_RXKEYIX_INVALID ((u8) - 1) -#define AR5K_TXKEYIX_INVALID ((u32) - 1) +#define AR5K_RXKEYIX_INVALID ((u8) -1) +#define AR5K_TXKEYIX_INVALID ((u32) -1) /**************************\ @@ -678,12 +679,13 @@ struct ath5k_gain { #define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g operation) */ #define CHANNEL_XR 0x0800 /* XR channel */ -#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) -#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) -#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) -#define CHANNEL_X (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR) +#define CHANNEL_A (CHANNEL_5GHZ | CHANNEL_OFDM) +#define CHANNEL_B (CHANNEL_2GHZ | CHANNEL_CCK) +#define CHANNEL_G (CHANNEL_2GHZ | CHANNEL_OFDM) +#define CHANNEL_X (CHANNEL_5GHZ | CHANNEL_OFDM | CHANNEL_XR) -#define CHANNEL_ALL (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ) +#define CHANNEL_ALL (CHANNEL_OFDM | CHANNEL_CCK | \ + CHANNEL_2GHZ | CHANNEL_5GHZ) #define CHANNEL_MODES CHANNEL_ALL @@ -776,11 +778,11 @@ extern int ath5k_modparam_nohwcrypt; /* * Misc definitions */ -#define AR5K_RSSI_EP_MULTIPLIER (1<<7) +#define AR5K_RSSI_EP_MULTIPLIER (1 << 7) #define AR5K_ASSERT_ENTRY(_e, _s) do { \ if (_e >= _s) \ - return (false); \ + return false; \ } while (0) /* @@ -791,47 +793,47 @@ extern int ath5k_modparam_nohwcrypt; * enum ath5k_int - Hardware interrupt masks helpers * * @AR5K_INT_RX: mask to identify received frame interrupts, of type - * AR5K_ISR_RXOK or AR5K_ISR_RXERR + * AR5K_ISR_RXOK or AR5K_ISR_RXERR * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?) * @AR5K_INT_RXNOFRM: No frame received (?) * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The - * Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's - * LinkPtr is NULL. For more details, refer to: - * http://www.freepatentsonline.com/20030225739.html + * Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's + * LinkPtr is NULL. For more details, refer to: + * http://www.freepatentsonline.com/20030225739.html * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors). - * Note that Rx overrun is not always fatal, on some chips we can continue - * operation without reseting the card, that's why int_fatal is not - * common for all chips. + * Note that Rx overrun is not always fatal, on some chips we can continue + * operation without reseting the card, that's why int_fatal is not + * common for all chips. * @AR5K_INT_TX: mask to identify received frame interrupts, of type - * AR5K_ISR_TXOK or AR5K_ISR_TXERR + * AR5K_ISR_TXOK or AR5K_ISR_TXERR * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?) * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold - * We currently do increments on interrupt by - * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 + * We currently do increments on interrupt by + * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 * @AR5K_INT_MIB: Indicates the either Management Information Base counters or * one of the PHY error counters reached the maximum value and should be * read and cleared. * @AR5K_INT_RXPHY: RX PHY Error * @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a - * beacon that must be handled in software. The alternative is if you - * have VEOL support, in that case you let the hardware deal with things. + * beacon that must be handled in software. The alternative is if you + * have VEOL support, in that case you let the hardware deal with things. * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing - * beacons from the AP have associated with, we should probably try to - * reassociate. When in IBSS mode this might mean we have not received - * any beacons from any local stations. Note that every station in an - * IBSS schedules to send beacons at the Target Beacon Transmission Time - * (TBTT) with a random backoff. + * beacons from the AP have associated with, we should probably try to + * reassociate. When in IBSS mode this might mean we have not received + * any beacons from any local stations. Note that every station in an + * IBSS schedules to send beacons at the Target Beacon Transmission Time + * (TBTT) with a random backoff. * @AR5K_INT_BNR: Beacon Not Ready interrupt - ?? * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now - * until properly handled + * until properly handled * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA - * errors. These types of errors we can enable seem to be of type - * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. + * errors. These types of errors we can enable seem to be of type + * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. * @AR5K_INT_GLOBAL: Used to clear and set the IER * @AR5K_INT_NOCARD: signals the card has been removed * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same - * bit value + * bit value * * These are mapped to take advantage of some common bits * between the MACs, to be able to set intr properties @@ -968,9 +970,9 @@ enum ath5k_capability_type { AR5K_CAP_MCAST_KEYSRCH = 14, /* Supports multicast key search */ AR5K_CAP_TSF_ADJUST = 15, /* Supports beacon tsf adjust */ AR5K_CAP_XR = 16, /* Supports XR mode */ - AR5K_CAP_WME_TKIPMIC = 17, /* Supports TKIP MIC when using WMM */ - AR5K_CAP_CHAN_HALFRATE = 18, /* Supports half rate channels */ - AR5K_CAP_CHAN_QUARTERRATE = 19, /* Supports quarter rate channels */ + AR5K_CAP_WME_TKIPMIC = 17, /* Supports TKIP MIC when using WMM */ + AR5K_CAP_CHAN_HALFRATE = 18, /* Supports half rate channels */ + AR5K_CAP_CHAN_QUARTERRATE = 19, /* Supports quarter rate channels */ AR5K_CAP_RFSILENT = 20, /* Supports RFsilent */ }; @@ -1010,8 +1012,7 @@ struct ath5k_capabilities { /* size of noise floor history (keep it a power of two) */ #define ATH5K_NF_CAL_HIST_MAX 8 -struct ath5k_nfcal_hist -{ +struct ath5k_nfcal_hist { s16 index; /* current index into nfval */ s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */ }; @@ -1362,12 +1363,12 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) { - return &ah->common; + return &ah->common; } static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah) { - return &(ath5k_hw_common(ah)->regulatory); + return &(ath5k_hw_common(ah)->regulatory); } #ifdef CONFIG_ATHEROS_AR231X @@ -1378,7 +1379,7 @@ static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg) /* On AR2315 and AR2317 the PCI clock domain registers * are outside of the WMAC register space */ if (unlikely((reg >= 0x4000) && (reg < 0x5000) && - (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6))) + (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6))) return AR5K_AR2315_PCI_BASE + reg; return ah->ah_iobase + reg; diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 1588401de3c4..d6fbb57a5d98 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -104,6 +104,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah) */ int ath5k_hw_init(struct ath5k_softc *sc) { + static const u8 zero_mac[ETH_ALEN] = { }; struct ath5k_hw *ah = sc->ah; struct ath_common *common = ath5k_hw_common(ah); struct pci_dev *pdev = sc->pdev; @@ -191,7 +192,7 @@ int ath5k_hw_init(struct ath5k_softc *sc) break; case AR5K_SREV_RAD_5424: if (ah->ah_mac_version == AR5K_SREV_AR2425 || - ah->ah_mac_version == AR5K_SREV_AR2417){ + ah->ah_mac_version == AR5K_SREV_AR2417) { ah->ah_radio = AR5K_RF2425; ah->ah_single_chip = true; } else { @@ -210,28 +211,28 @@ int ath5k_hw_init(struct ath5k_softc *sc) ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, CHANNEL_2GHZ); } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) || - ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) || - ah->ah_phy_revision == AR5K_SREV_PHY_2425) { + ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) || + ah->ah_phy_revision == AR5K_SREV_PHY_2425) { ah->ah_radio = AR5K_RF2425; ah->ah_single_chip = true; ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425; } else if (srev == AR5K_SREV_AR5213A && - ah->ah_phy_revision == AR5K_SREV_PHY_5212B) { + ah->ah_phy_revision == AR5K_SREV_PHY_5212B) { ah->ah_radio = AR5K_RF5112; ah->ah_single_chip = false; ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B; } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4) || - ah->ah_mac_version == (AR5K_SREV_AR2315_R6 >> 4)) { + ah->ah_mac_version == (AR5K_SREV_AR2315_R6 >> 4)) { ah->ah_radio = AR5K_RF2316; ah->ah_single_chip = true; ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316; } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) || - ah->ah_phy_revision == AR5K_SREV_PHY_5413) { + ah->ah_phy_revision == AR5K_SREV_PHY_5413) { ah->ah_radio = AR5K_RF5413; ah->ah_single_chip = true; ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413; } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) || - ah->ah_phy_revision == AR5K_SREV_PHY_2413) { + ah->ah_phy_revision == AR5K_SREV_PHY_2413) { ah->ah_radio = AR5K_RF2413; ah->ah_single_chip = true; ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413; @@ -244,8 +245,7 @@ int ath5k_hw_init(struct ath5k_softc *sc) /* Return on unsuported chips (unsupported eeprom etc) */ - if ((srev >= AR5K_SREV_AR5416) && - (srev < AR5K_SREV_AR2425)) { + if ((srev >= AR5K_SREV_AR5416) && (srev < AR5K_SREV_AR2425)) { ATH5K_ERR(sc, "Device not yet supported.\n"); ret = -ENODEV; goto err; @@ -334,7 +334,7 @@ int ath5k_hw_init(struct ath5k_softc *sc) } /* MAC address is cleared until add_interface */ - ath5k_hw_set_lladdr(ah, (u8[ETH_ALEN]){}); + ath5k_hw_set_lladdr(ah, zero_mac); /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index a6623ddfdefe..28113e023c62 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -814,8 +814,7 @@ ath5k_desc_alloc(struct ath5k_softc *sc) INIT_LIST_HEAD(&sc->txbuf); sc->txbuf_len = ATH_TXBUF; - for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, - da += sizeof(*ds)) { + for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, da += sizeof(*ds)) { bf->desc = ds; bf->daddr = da; list_add_tail(&bf->list, &sc->txbuf); @@ -981,7 +980,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc) goto err; if (sc->opmode == NL80211_IFTYPE_AP || - sc->opmode == NL80211_IFTYPE_MESH_POINT) { + sc->opmode == NL80211_IFTYPE_MESH_POINT) { /* * Always burst out beacon and CAB traffic * (aifs = cwmin = cwmax = 0) @@ -1261,16 +1260,15 @@ ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) */ static int ath5k_common_padpos(struct sk_buff *skb) { - struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; __le16 frame_control = hdr->frame_control; int padpos = 24; - if (ieee80211_has_a4(frame_control)) { + if (ieee80211_has_a4(frame_control)) padpos += ETH_ALEN; - } - if (ieee80211_is_data_qos(frame_control)) { + + if (ieee80211_is_data_qos(frame_control)) padpos += IEEE80211_QOS_CTL_LEN; - } return padpos; } @@ -1284,13 +1282,13 @@ static int ath5k_add_padding(struct sk_buff *skb) int padpos = ath5k_common_padpos(skb); int padsize = padpos & 3; - if (padsize && skb->len>padpos) { + if (padsize && skb->len > padpos) { if (skb_headroom(skb) < padsize) return -1; skb_push(skb, padsize); - memmove(skb->data, skb->data+padsize, padpos); + memmove(skb->data, skb->data + padsize, padpos); return padsize; } @@ -1315,7 +1313,7 @@ static int ath5k_remove_padding(struct sk_buff *skb) int padpos = ath5k_common_padpos(skb); int padsize = padpos & 3; - if (padsize && skb->len>=padpos+padsize) { + if (padsize && skb->len >= padpos + padsize) { memmove(skb->data + padsize, skb->data, padpos); skb_pull(skb, padsize); return padsize; @@ -1449,10 +1447,11 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs) static void ath5k_set_current_imask(struct ath5k_softc *sc) { - enum ath5k_int imask = sc->imask; + enum ath5k_int imask; unsigned long flags; spin_lock_irqsave(&sc->irqlock, flags); + imask = sc->imask; if (sc->rx_pending) imask &= ~AR5K_INT_RX_ALL; if (sc->tx_pending) @@ -1710,7 +1709,7 @@ ath5k_tasklet_tx(unsigned long data) int i; struct ath5k_softc *sc = (void *)data; - for (i=0; i < AR5K_NUM_TX_QUEUES; i++) + for (i = 0; i < AR5K_NUM_TX_QUEUES; i++) if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) ath5k_tx_processq(sc, &sc->txqs[i]); @@ -1901,7 +1900,7 @@ ath5k_beacon_send(struct ath5k_softc *sc) avf = (void *)vif->drv_priv; bf = avf->bbuf; if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION || - sc->opmode == NL80211_IFTYPE_MONITOR)) { + sc->opmode == NL80211_IFTYPE_MONITOR)) { ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); return; } @@ -1918,7 +1917,7 @@ ath5k_beacon_send(struct ath5k_softc *sc) /* refresh the beacon for AP or MESH mode */ if (sc->opmode == NL80211_IFTYPE_AP || - sc->opmode == NL80211_IFTYPE_MESH_POINT) + sc->opmode == NL80211_IFTYPE_MESH_POINT) ath5k_beacon_update(sc->hw, vif); trace_ath5k_tx(sc, bf->skb, &sc->txqs[sc->bhalq]); @@ -1977,7 +1976,7 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) hw_tsf = ath5k_hw_get_tsf64(ah); hw_tu = TSF_TO_TU(hw_tsf); -#define FUDGE AR5K_TUNE_SW_BEACON_RESP + 3 +#define FUDGE (AR5K_TUNE_SW_BEACON_RESP + 3) /* We use FUDGE to make sure the next TBTT is ahead of the current TU. * Since we later subtract AR5K_TUNE_SW_BEACON_RESP (10) in the timer * configuration we need to make sure it is bigger than that. */ @@ -2199,13 +2198,12 @@ ath5k_intr(int irq, void *dev_id) ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "rx overrun, resetting\n"); ieee80211_queue_work(sc->hw, &sc->reset_work); - } - else + } else ath5k_schedule_rx(sc); } else { - if (status & AR5K_INT_SWBA) { + if (status & AR5K_INT_SWBA) tasklet_hi_schedule(&sc->beacontq); - } + if (status & AR5K_INT_RXEOL) { /* * NB: the hardware should re-read the link when @@ -2357,7 +2355,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work) * Initialization routines * \*************************/ -int +int __devinit ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = sc->hw; @@ -2487,7 +2485,7 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops) /* Multi chip radio (RF5111 - RF2111) -> * report both 2GHz/5GHz radios */ else if (sc->ah->ah_radio_5ghz_revision && - sc->ah->ah_radio_2ghz_revision){ + sc->ah->ah_radio_2ghz_revision) { ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", ath5k_chip_name(AR5K_VERSION_RAD, sc->ah->ah_radio_5ghz_revision), @@ -2712,8 +2710,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan, fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0; - ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast, - skip_pcu); + ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast, skip_pcu); if (ret) { ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); goto err; @@ -2771,7 +2768,7 @@ static void ath5k_reset_work(struct work_struct *work) mutex_unlock(&sc->lock); } -static int +static int __devinit ath5k_init(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index b294f3305011..e71494ee3290 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -96,8 +96,7 @@ struct ath5k_txq { /* * State for LED triggers */ -struct ath5k_led -{ +struct ath5k_led { char name[ATH5K_LED_MAX_NAME_LEN + 1]; /* name of the LED in sysfs */ struct ath5k_softc *sc; /* driver state */ struct led_classdev led_dev; /* led classdev */ @@ -154,9 +153,9 @@ struct ath5k_statistics { }; #if CHAN_DEBUG -#define ATH_CHAN_MAX (26+26+26+200+200) +#define ATH_CHAN_MAX (26 + 26 + 26 + 200 + 200) #else -#define ATH_CHAN_MAX (14+14+14+252+20) +#define ATH_CHAN_MAX (14 + 14 + 14 + 252 + 20) #endif struct ath5k_vif { @@ -251,7 +250,7 @@ struct ath5k_softc { unsigned int nexttbtt; /* next beacon time in TU */ struct ath5k_txq *cabq; /* content after beacon */ - int power_level; /* Requested tx power in dbm */ + int power_level; /* Requested tx power in dbm */ bool assoc; /* associate state */ bool enable_beacon; /* true if beacons are on */ diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 0bf7313b8a17..ae1112bfa1c1 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -205,35 +205,35 @@ static ssize_t read_file_beacon(struct file *file, char __user *user_buf, u64 tsf; v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tintval: %d\tTIM: 0x%x\n", "AR5K_BEACON", v, v & AR5K_BEACON_PERIOD, (v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n", + len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n", "AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP)); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n", + len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n\n", "AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT)); v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n", "AR5K_TIMER0 (TBTT)", v, v); v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n", "AR5K_TIMER1 (DMA)", v, v >> 3); v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n", "AR5K_TIMER2 (SWBA)", v, v >> 3); v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3); - len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n", "AR5K_TIMER3 (ATIM)", v, v); tsf = ath5k_hw_get_tsf64(sc->ah); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "TSF\t\t0x%016llx\tTU: %08x\n", (unsigned long long)tsf, TSF_TO_TU(tsf)); @@ -323,16 +323,16 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf, unsigned int len = 0; unsigned int i; - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "DEBUG LEVEL: 0x%08x\n\n", sc->debug.level); for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) { - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "%10s %c 0x%08x - %s\n", dbg_info[i].name, sc->debug.level & dbg_info[i].level ? '+' : ' ', dbg_info[i].level, dbg_info[i].desc); } - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "%10s %c 0x%08x - %s\n", dbg_info[i].name, sc->debug.level == dbg_info[i].level ? '+' : ' ', dbg_info[i].level, dbg_info[i].desc); @@ -384,60 +384,60 @@ static ssize_t read_file_antenna(struct file *file, char __user *user_buf, unsigned int i; unsigned int v; - len += snprintf(buf+len, sizeof(buf)-len, "antenna mode\t%d\n", + len += snprintf(buf + len, sizeof(buf) - len, "antenna mode\t%d\n", sc->ah->ah_ant_mode); - len += snprintf(buf+len, sizeof(buf)-len, "default antenna\t%d\n", + len += snprintf(buf + len, sizeof(buf) - len, "default antenna\t%d\n", sc->ah->ah_def_ant); - len += snprintf(buf+len, sizeof(buf)-len, "tx antenna\t%d\n", + len += snprintf(buf + len, sizeof(buf) - len, "tx antenna\t%d\n", sc->ah->ah_tx_ant); - len += snprintf(buf+len, sizeof(buf)-len, "\nANTENNA\t\tRX\tTX\n"); + len += snprintf(buf + len, sizeof(buf) - len, "\nANTENNA\t\tRX\tTX\n"); for (i = 1; i < ARRAY_SIZE(sc->stats.antenna_rx); i++) { - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "[antenna %d]\t%d\t%d\n", i, sc->stats.antenna_rx[i], sc->stats.antenna_tx[i]); } - len += snprintf(buf+len, sizeof(buf)-len, "[invalid]\t%d\t%d\n", + len += snprintf(buf + len, sizeof(buf) - len, "[invalid]\t%d\t%d\n", sc->stats.antenna_rx[0], sc->stats.antenna_tx[0]); v = ath5k_hw_reg_read(sc->ah, AR5K_DEFAULT_ANTENNA); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "\nAR5K_DEFAULT_ANTENNA\t0x%08x\n", v); v = ath5k_hw_reg_read(sc->ah, AR5K_STA_ID1); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "AR5K_STA_ID1_DEFAULT_ANTENNA\t%d\n", (v & AR5K_STA_ID1_DEFAULT_ANTENNA) != 0); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "AR5K_STA_ID1_DESC_ANTENNA\t%d\n", (v & AR5K_STA_ID1_DESC_ANTENNA) != 0); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "AR5K_STA_ID1_RTS_DEF_ANTENNA\t%d\n", (v & AR5K_STA_ID1_RTS_DEF_ANTENNA) != 0); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "AR5K_STA_ID1_SELFGEN_DEF_ANT\t%d\n", (v & AR5K_STA_ID1_SELFGEN_DEF_ANT) != 0); v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_AGCCTL); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "\nAR5K_PHY_AGCCTL_OFDM_DIV_DIS\t%d\n", (v & AR5K_PHY_AGCCTL_OFDM_DIV_DIS) != 0); v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_RESTART); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "AR5K_PHY_RESTART_DIV_GC\t\t%x\n", (v & AR5K_PHY_RESTART_DIV_GC) >> AR5K_PHY_RESTART_DIV_GC_S); v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_FAST_ANT_DIV); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "AR5K_PHY_FAST_ANT_DIV_EN\t%d\n", (v & AR5K_PHY_FAST_ANT_DIV_EN) != 0); v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_0); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "\nAR5K_PHY_ANT_SWITCH_TABLE_0\t0x%08x\n", v); v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_1); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "AR5K_PHY_ANT_SWITCH_TABLE_1\t0x%08x\n", v); if (len > sizeof(buf)) @@ -494,36 +494,36 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, unsigned int len = 0; u32 filt = ath5k_hw_get_rx_filter(sc->ah); - len += snprintf(buf+len, sizeof(buf)-len, "bssid-mask: %pM\n", + len += snprintf(buf + len, sizeof(buf) - len, "bssid-mask: %pM\n", sc->bssidmask); - len += snprintf(buf+len, sizeof(buf)-len, "filter-flags: 0x%x ", + len += snprintf(buf + len, sizeof(buf) - len, "filter-flags: 0x%x ", filt); if (filt & AR5K_RX_FILTER_UCAST) - len += snprintf(buf+len, sizeof(buf)-len, " UCAST"); + len += snprintf(buf + len, sizeof(buf) - len, " UCAST"); if (filt & AR5K_RX_FILTER_MCAST) - len += snprintf(buf+len, sizeof(buf)-len, " MCAST"); + len += snprintf(buf + len, sizeof(buf) - len, " MCAST"); if (filt & AR5K_RX_FILTER_BCAST) - len += snprintf(buf+len, sizeof(buf)-len, " BCAST"); + len += snprintf(buf + len, sizeof(buf) - len, " BCAST"); if (filt & AR5K_RX_FILTER_CONTROL) - len += snprintf(buf+len, sizeof(buf)-len, " CONTROL"); + len += snprintf(buf + len, sizeof(buf) - len, " CONTROL"); if (filt & AR5K_RX_FILTER_BEACON) - len += snprintf(buf+len, sizeof(buf)-len, " BEACON"); + len += snprintf(buf + len, sizeof(buf) - len, " BEACON"); if (filt & AR5K_RX_FILTER_PROM) - len += snprintf(buf+len, sizeof(buf)-len, " PROM"); + len += snprintf(buf + len, sizeof(buf) - len, " PROM"); if (filt & AR5K_RX_FILTER_XRPOLL) - len += snprintf(buf+len, sizeof(buf)-len, " XRPOLL"); + len += snprintf(buf + len, sizeof(buf) - len, " XRPOLL"); if (filt & AR5K_RX_FILTER_PROBEREQ) - len += snprintf(buf+len, sizeof(buf)-len, " PROBEREQ"); + len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ"); if (filt & AR5K_RX_FILTER_PHYERR_5212) - len += snprintf(buf+len, sizeof(buf)-len, " PHYERR-5212"); + len += snprintf(buf + len, sizeof(buf) - len, " PHYERR-5212"); if (filt & AR5K_RX_FILTER_RADARERR_5212) - len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5212"); + len += snprintf(buf + len, sizeof(buf) - len, " RADARERR-5212"); if (filt & AR5K_RX_FILTER_PHYERR_5211) - snprintf(buf+len, sizeof(buf)-len, " PHYERR-5211"); + snprintf(buf + len, sizeof(buf) - len, " PHYERR-5211"); if (filt & AR5K_RX_FILTER_RADARERR_5211) - len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5211"); + len += snprintf(buf + len, sizeof(buf) - len, " RADARERR-5211"); - len += snprintf(buf+len, sizeof(buf)-len, "\nopmode: %s (%d)\n", + len += snprintf(buf + len, sizeof(buf) - len, "\nopmode: %s (%d)\n", ath_opmode_to_string(sc->opmode), sc->opmode); if (len > sizeof(buf)) @@ -550,65 +550,65 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, unsigned int len = 0; int i; - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "RX\n---------------------\n"); - len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%u\t(%u%%)\n", + len += snprintf(buf + len, sizeof(buf) - len, "CRC\t%u\t(%u%%)\n", st->rxerr_crc, st->rx_all_count > 0 ? - st->rxerr_crc*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%u\t(%u%%)\n", + st->rxerr_crc * 100 / st->rx_all_count : 0); + len += snprintf(buf + len, sizeof(buf) - len, "PHY\t%u\t(%u%%)\n", st->rxerr_phy, st->rx_all_count > 0 ? - st->rxerr_phy*100/st->rx_all_count : 0); + st->rxerr_phy * 100 / st->rx_all_count : 0); for (i = 0; i < 32; i++) { if (st->rxerr_phy_code[i]) - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, " phy_err[%u]\t%u\n", i, st->rxerr_phy_code[i]); } - len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%u\t(%u%%)\n", + len += snprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n", st->rxerr_fifo, st->rx_all_count > 0 ? - st->rxerr_fifo*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%u\t(%u%%)\n", + st->rxerr_fifo * 100 / st->rx_all_count : 0); + len += snprintf(buf + len, sizeof(buf) - len, "decrypt\t%u\t(%u%%)\n", st->rxerr_decrypt, st->rx_all_count > 0 ? - st->rxerr_decrypt*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%u\t(%u%%)\n", + st->rxerr_decrypt * 100 / st->rx_all_count : 0); + len += snprintf(buf + len, sizeof(buf) - len, "MIC\t%u\t(%u%%)\n", st->rxerr_mic, st->rx_all_count > 0 ? - st->rxerr_mic*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "process\t%u\t(%u%%)\n", + st->rxerr_mic * 100 / st->rx_all_count : 0); + len += snprintf(buf + len, sizeof(buf) - len, "process\t%u\t(%u%%)\n", st->rxerr_proc, st->rx_all_count > 0 ? - st->rxerr_proc*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%u\t(%u%%)\n", + st->rxerr_proc * 100 / st->rx_all_count : 0); + len += snprintf(buf + len, sizeof(buf) - len, "jumbo\t%u\t(%u%%)\n", st->rxerr_jumbo, st->rx_all_count > 0 ? - st->rxerr_jumbo*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%u]\n", + st->rxerr_jumbo * 100 / st->rx_all_count : 0); + len += snprintf(buf + len, sizeof(buf) - len, "[RX all\t%u]\n", st->rx_all_count); - len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%u\n", + len += snprintf(buf + len, sizeof(buf) - len, "RX-all-bytes\t%u\n", st->rx_bytes_count); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "\nTX\n---------------------\n"); - len += snprintf(buf+len, sizeof(buf)-len, "retry\t%u\t(%u%%)\n", + len += snprintf(buf + len, sizeof(buf) - len, "retry\t%u\t(%u%%)\n", st->txerr_retry, st->tx_all_count > 0 ? - st->txerr_retry*100/st->tx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%u\t(%u%%)\n", + st->txerr_retry * 100 / st->tx_all_count : 0); + len += snprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n", st->txerr_fifo, st->tx_all_count > 0 ? - st->txerr_fifo*100/st->tx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "filter\t%u\t(%u%%)\n", + st->txerr_fifo * 100 / st->tx_all_count : 0); + len += snprintf(buf + len, sizeof(buf) - len, "filter\t%u\t(%u%%)\n", st->txerr_filt, st->tx_all_count > 0 ? - st->txerr_filt*100/st->tx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%u]\n", + st->txerr_filt * 100 / st->tx_all_count : 0); + len += snprintf(buf + len, sizeof(buf) - len, "[TX all\t%u]\n", st->tx_all_count); - len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%u\n", + len += snprintf(buf + len, sizeof(buf) - len, "TX-all-bytes\t%u\n", st->tx_bytes_count); if (len > sizeof(buf)) @@ -667,89 +667,93 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, char buf[700]; unsigned int len = 0; - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "HW has PHY error counters:\t%s\n", sc->ah->ah_capabilities.cap_has_phyerr_counters ? "yes" : "no"); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "HW max spur immunity level:\t%d\n", as->max_spur_level); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "\nANI state\n--------------------------------------------\n"); - len += snprintf(buf+len, sizeof(buf)-len, "operating mode:\t\t\t"); + len += snprintf(buf + len, sizeof(buf) - len, "operating mode:\t\t\t"); switch (as->ani_mode) { case ATH5K_ANI_MODE_OFF: - len += snprintf(buf+len, sizeof(buf)-len, "OFF\n"); + len += snprintf(buf + len, sizeof(buf) - len, "OFF\n"); break; case ATH5K_ANI_MODE_MANUAL_LOW: - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "MANUAL LOW\n"); break; case ATH5K_ANI_MODE_MANUAL_HIGH: - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "MANUAL HIGH\n"); break; case ATH5K_ANI_MODE_AUTO: - len += snprintf(buf+len, sizeof(buf)-len, "AUTO\n"); + len += snprintf(buf + len, sizeof(buf) - len, "AUTO\n"); break; default: - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "??? (not good)\n"); break; } - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "noise immunity level:\t\t%d\n", as->noise_imm_level); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "spur immunity level:\t\t%d\n", as->spur_level); - len += snprintf(buf+len, sizeof(buf)-len, "firstep level:\t\t\t%d\n", + len += snprintf(buf + len, sizeof(buf) - len, + "firstep level:\t\t\t%d\n", as->firstep_level); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "OFDM weak signal detection:\t%s\n", as->ofdm_weak_sig ? "on" : "off"); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "CCK weak signal detection:\t%s\n", as->cck_weak_sig ? "on" : "off"); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "\nMIB INTERRUPTS:\t\t%u\n", st->mib_intr); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "beacon RSSI average:\t%d\n", (int)ewma_read(&sc->ah->ah_beacon_rssi_avg)); #define CC_PRINT(_struct, _field) \ _struct._field, \ _struct.cycles > 0 ? \ - _struct._field*100/_struct.cycles : 0 + _struct._field * 100 / _struct.cycles : 0 - len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n", + len += snprintf(buf + len, sizeof(buf) - len, + "profcnt tx\t\t%u\t(%d%%)\n", CC_PRINT(as->last_cc, tx_frame)); - len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n", + len += snprintf(buf + len, sizeof(buf) - len, + "profcnt rx\t\t%u\t(%d%%)\n", CC_PRINT(as->last_cc, rx_frame)); - len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n", + len += snprintf(buf + len, sizeof(buf) - len, + "profcnt busy\t\t%u\t(%d%%)\n", CC_PRINT(as->last_cc, rx_busy)); #undef CC_PRINT - len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n", + len += snprintf(buf + len, sizeof(buf) - len, "profcnt cycles\t\t%u\n", as->last_cc.cycles); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "listen time\t\t%d\tlast: %d\n", as->listen_time, as->last_listen); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "OFDM errors\t\t%u\tlast: %u\tsum: %u\n", as->ofdm_errors, as->last_ofdm_errors, as->sum_ofdm_errors); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "CCK errors\t\t%u\tlast: %u\tsum: %u\n", as->cck_errors, as->last_cck_errors, as->sum_cck_errors); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "AR5K_PHYERR_CNT1\t%x\t(=%d)\n", ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1), ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1))); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "AR5K_PHYERR_CNT2\t%x\t(=%d)\n", ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2), ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - @@ -827,13 +831,13 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf, struct ath5k_buf *bf, *bf0; int i, n; - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "available txbuffers: %d\n", sc->txbuf_len); for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) { txq = &sc->txqs[i]; - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, "%02d: %ssetup\n", i, txq->setup ? "" : "not "); if (!txq->setup) @@ -845,9 +849,9 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf, n++; spin_unlock_bh(&txq->lock); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, " len: %d bufs: %d\n", txq->txq_len, n); - len += snprintf(buf+len, sizeof(buf)-len, + len += snprintf(buf + len, sizeof(buf) - len, " stuck: %d\n", txq->txq_stuck); } @@ -894,7 +898,7 @@ ath5k_debug_init_device(struct ath5k_softc *sc) phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir); if (!phydir) - return; + return; debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc, &fops_debug); diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 21091c26a9a5..02e2e3f71b08 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -258,7 +258,7 @@ static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) /* For 2413+ order PCU to drop packets using * QUIET mechanism */ if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) && - pending){ + pending) { /* Set periodicity and duration */ ath5k_hw_reg_write(ah, AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)| diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 1fef84f87c78..f97a540e2199 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -223,14 +223,14 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, ah->ah_ant_ctl[mode][AR5K_ANT_CTL] = (ee->ee_ant_control[mode][0] << 4); ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_A] = - ee->ee_ant_control[mode][1] | - (ee->ee_ant_control[mode][2] << 6) | + ee->ee_ant_control[mode][1] | + (ee->ee_ant_control[mode][2] << 6) | (ee->ee_ant_control[mode][3] << 12) | (ee->ee_ant_control[mode][4] << 18) | (ee->ee_ant_control[mode][5] << 24); ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_B] = - ee->ee_ant_control[mode][6] | - (ee->ee_ant_control[mode][7] << 6) | + ee->ee_ant_control[mode][6] | + (ee->ee_ant_control[mode][7] << 6) | (ee->ee_ant_control[mode][8] << 12) | (ee->ee_ant_control[mode][9] << 18) | (ee->ee_ant_control[mode][10] << 24); @@ -255,7 +255,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, ee->ee_n_piers[mode] = 0; AR5K_EEPROM_READ(o++, val); ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - switch(mode) { + switch (mode) { case AR5K_EEPROM_MODE_11A: ee->ee_ob[mode][3] = (val >> 5) & 0x7; ee->ee_db[mode][3] = (val >> 2) & 0x7; @@ -349,7 +349,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, /* Note: >= v5 have bg freq piers on another location * so these freq piers are ignored for >= v5 (should be 0xff * anyway) */ - switch(mode) { + switch (mode) { case AR5K_EEPROM_MODE_11A: if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1) break; @@ -422,7 +422,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) goto done; - switch (mode){ + switch (mode) { case AR5K_EEPROM_MODE_11A: ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f; @@ -436,7 +436,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7; ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff; - if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2) + if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >= 2) ee->ee_pd_gain_overlap = (val >> 9) & 0xf; break; case AR5K_EEPROM_MODE_11G: @@ -516,7 +516,7 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, u16 val; ee->ee_n_piers[mode] = 0; - while(i < max) { + while (i < max) { AR5K_EEPROM_READ(o++, val); freq1 = val & 0xff; @@ -602,7 +602,7 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; struct ath5k_chan_pcal_info *pcal; - switch(mode) { + switch (mode) { case AR5K_EEPROM_MODE_11B: pcal = ee->ee_pwr_cal_b; break; @@ -644,10 +644,12 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) static inline void ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) { - static const u16 intercepts3[] = - { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; - static const u16 intercepts3_2[] = - { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; + static const u16 intercepts3[] = { + 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 + }; + static const u16 intercepts3_2[] = { + 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 + }; const u16 *ip; int i; @@ -691,14 +693,12 @@ ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) if (!chinfo[pier].pd_curves) continue; - for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { + for (pdg = 0; pdg < AR5K_EEPROM_N_PD_CURVES; pdg++) { struct ath5k_pdgain_info *pd = &chinfo[pier].pd_curves[pdg]; - if (pd != NULL) { - kfree(pd->pd_step); - kfree(pd->pd_pwr); - } + kfree(pd->pd_step); + kfree(pd->pd_pwr); } kfree(chinfo[pier].pd_curves); @@ -798,7 +798,7 @@ ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) u16 val; offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); - switch(mode) { + switch (mode) { case AR5K_EEPROM_MODE_11A: if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) return 0; @@ -1165,7 +1165,7 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) { u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4); - switch(mode) { + switch (mode) { case AR5K_EEPROM_MODE_11G: if (AR5K_EEPROM_HDR_11B(ee->ee_header)) offset += ath5k_pdgains_size_2413(ee, @@ -1622,8 +1622,8 @@ ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) offset += AR5K_EEPROM_GROUPS_START(ee->ee_version); rep = ee->ee_ctl_pwr; - for(i = 0; i < ee->ee_ctls; i++) { - switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) { + for (i = 0; i < ee->ee_ctls; i++) { + switch (ee->ee_ctl[i] & AR5K_CTL_MODE_M) { case AR5K_CTL_11A: case AR5K_CTL_TURBO: ctl_mode = AR5K_EEPROM_MODE_11A; diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 6511c27d938e..6d440e0ba149 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -223,7 +223,7 @@ #define AR5K_EEPROM_CCK_OFDM_DELTA 15 #define AR5K_EEPROM_N_IQ_CAL 2 /* 5GHz/2GHz */ -enum ath5k_eeprom_freq_bands{ +enum ath5k_eeprom_freq_bands { AR5K_EEPROM_BAND_5GHZ = 0, AR5K_EEPROM_BAND_2GHZ = 1, AR5K_EEPROM_N_FREQ_BANDS, diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c index e49340d18df4..4bfdc2e20dfa 100644 --- a/drivers/net/wireless/ath/ath5k/initvals.c +++ b/drivers/net/wireless/ath/ath5k/initvals.c @@ -113,8 +113,8 @@ static const struct ath5k_ini ar5210_ini[] = { { AR5K_PHY(28), 0x0000000f }, { AR5K_PHY(29), 0x00000080 }, { AR5K_PHY(30), 0x00000004 }, - { AR5K_PHY(31), 0x00000018 }, /* 0x987c */ - { AR5K_PHY(64), 0x00000000 }, /* 0x9900 */ + { AR5K_PHY(31), 0x00000018 }, /* 0x987c */ + { AR5K_PHY(64), 0x00000000 }, /* 0x9900 */ { AR5K_PHY(65), 0x00000000 }, { AR5K_PHY(66), 0x00000000 }, { AR5K_PHY(67), 0x00800000 }, @@ -549,7 +549,7 @@ static const struct ath5k_ini ar5212_ini_common_start[] = { { AR5K_DIAG_SW_5211, 0x00000000 }, { AR5K_ADDAC_TEST, 0x00000000 }, { AR5K_DEFAULT_ANTENNA, 0x00000000 }, - { AR5K_FRAME_CTL_QOSM, 0x000fc78f }, + { AR5K_FRAME_CTL_QOSM, 0x000fc78f }, { AR5K_XRMODE, 0x2a82301a }, { AR5K_XRDELAY, 0x05dc01e0 }, { AR5K_XRTIMEOUT, 0x1f402710 }, @@ -760,9 +760,9 @@ static const struct ath5k_ini_mode rf5111_ini_mode_end[] = { static const struct ath5k_ini rf5111_ini_common_end[] = { { AR5K_DCU_FP, 0x00000000 }, - { AR5K_PHY_AGC, 0x00000000 }, - { AR5K_PHY_ADC_CTL, 0x00022ffe }, - { 0x983c, 0x00020100 }, + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY_ADC_CTL, 0x00022ffe }, + { 0x983c, 0x00020100 }, { AR5K_PHY_GAIN_OFFSET, 0x1284613c }, { AR5K_PHY_PAPD_PROBE, 0x00004883 }, { 0x9940, 0x00000004 }, diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 576edf2965dc..127bfbd35172 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -43,16 +43,16 @@ #include "ath5k.h" #include "base.h" -#define ATH_SDEVICE(subv,subd) \ +#define ATH_SDEVICE(subv, subd) \ .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ .subvendor = (subv), .subdevice = (subd) -#define ATH_LED(pin,polarity) .driver_data = (((pin) << 8) | (polarity)) +#define ATH_LED(pin, polarity) .driver_data = (((pin) << 8) | (polarity)) #define ATH_PIN(data) ((data) >> 8) #define ATH_POLARITY(data) ((data) & 0xff) /* Devices we match on for LED config info (typically laptops) */ -static const struct pci_device_id ath5k_led_devices[] = { +static DEFINE_PCI_DEVICE_TABLE(ath5k_led_devices) = { /* AR5211 */ { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) }, /* HP Compaq nc6xx, nc4000, nx6000 */ @@ -157,7 +157,7 @@ void ath5k_unregister_leds(struct ath5k_softc *sc) ath5k_unregister_led(&sc->tx_led); } -int ath5k_init_leds(struct ath5k_softc *sc) +int __devinit ath5k_init_leds(struct ath5k_softc *sc) { int ret = 0; struct ieee80211_hw *hw = sc->hw; diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 296c316a8341..cd60f0a2f0ea 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -234,7 +234,7 @@ ath5k_pci_probe(struct pci_dev *pdev, mem = pci_iomap(pdev, 0, 0); if (!mem) { - dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; + dev_err(&pdev->dev, "cannot remap PCI memory region\n"); ret = -EIO; goto err_reg; } @@ -297,7 +297,9 @@ ath5k_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM_SLEEP static int ath5k_pci_suspend(struct device *dev) { - struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev)); + struct pci_dev *pdev = to_pci_dev(dev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; ath5k_led_off(sc); return 0; @@ -306,7 +308,8 @@ static int ath5k_pci_suspend(struct device *dev) static int ath5k_pci_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct ath5k_softc *sc = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; /* * Suspend/Resume resets the PCI configuration space, so we have to diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 712a9ac4000e..aecd72417490 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -534,9 +534,9 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) local_irq_restore(flags); - WARN_ON( i == ATH5K_MAX_TSF_READ ); + WARN_ON(i == ATH5K_MAX_TSF_READ); - return (((u64)tsf_upper1 << 32) | tsf_lower); + return ((u64)tsf_upper1 << 32) | tsf_lower; } /** diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 55441913344d..7e2867689e11 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -173,7 +173,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, data = ath5k_hw_bitswap(val, num_bits); for (bits_shifted = 0, bits_left = num_bits; bits_left > 0; - position = 0, entry++) { + position = 0, entry++) { last_bit = (position + bits_left > 8) ? 8 : position + bits_left; @@ -472,7 +472,7 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) level[0] = 0; level[1] = (step == 63) ? 50 : step + 4; level[2] = (step != 63) ? 64 : level[0]; - level[3] = level[2] + 50 ; + level[3] = level[2] + 50; ah->ah_gain.g_high = level[3] - (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); @@ -549,7 +549,7 @@ static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) for (ah->ah_gain.g_target = ah->ah_gain.g_current; ah->ah_gain.g_target <= ah->ah_gain.g_low && - ah->ah_gain.g_step_idx < go->go_steps_count-1; + ah->ah_gain.g_step_idx < go->go_steps_count - 1; g_step = &go->go_step[ah->ah_gain.g_step_idx]) ah->ah_gain.g_target -= 2 * (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - @@ -614,7 +614,7 @@ enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) ath5k_hw_rf_gainf_corr(ah); ah->ah_gain.g_current = ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? - (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : + (ah->ah_gain.g_current - ah->ah_gain.g_f_corr) : 0; } @@ -1331,7 +1331,7 @@ void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor) { struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist; - hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX-1); + hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX - 1); hist->nfval[hist->index] = noise_floor; } @@ -1344,10 +1344,10 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort)); for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) { for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) { - if (sort[j] > sort[j-1]) { + if (sort[j] > sort[j - 1]) { tmp = sort[j]; - sort[j] = sort[j-1]; - sort[j-1] = tmp; + sort[j] = sort[j - 1]; + sort[j - 1] = tmp; } } } @@ -1355,7 +1355,7 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, "cal %d:%d\n", i, sort[i]); } - return sort[(ATH5K_NF_CAL_HIST_MAX-1) / 2]; + return sort[(ATH5K_NF_CAL_HIST_MAX - 1) / 2]; } /* @@ -2080,7 +2080,7 @@ ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, * always 1 instead of 1.25, 1.75 etc). We scale up by 100 * to have some accuracy both for 0.5 and 0.25 steps. */ - ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left)); + ratio = ((100 * y_right - 100 * y_left) / (x_right - x_left)); /* Now scale down to be in range */ result = y_left + (ratio * (target - x_left) / 100); @@ -2159,7 +2159,7 @@ ath5k_create_power_curve(s16 pmin, s16 pmax, u8 *vpd_table, u8 type) { u8 idx[2] = { 0, 1 }; - s16 pwr_i = 2*pmin; + s16 pwr_i = 2 * pmin; int i; if (num_points < 2) @@ -2437,7 +2437,7 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, } if (edge_pwr) - ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr); + ah->ah_txpower.txp_max_pwr = 4 * min(edge_pwr, max_chan_pwr); } @@ -2456,7 +2456,7 @@ static void ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min, s16 *table_max) { - u8 *pcdac_out = ah->ah_txpower.txp_pd_table; + u8 *pcdac_out = ah->ah_txpower.txp_pd_table; u8 *pcdac_tmp = ah->ah_txpower.tmpL[0]; u8 pcdac_0, pcdac_n, pcdac_i, pwr_idx, i; s16 min_pwr, max_pwr; @@ -2475,8 +2475,8 @@ ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min, /* Copy values from pcdac_tmp */ pwr_idx = min_pwr; - for (i = 0 ; pwr_idx <= max_pwr && - pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) { + for (i = 0; pwr_idx <= max_pwr && + pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) { pcdac_out[pcdac_i++] = pcdac_tmp[i]; pwr_idx++; } @@ -2502,7 +2502,7 @@ static void ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, s16 *table_max, u8 pdcurves) { - u8 *pcdac_out = ah->ah_txpower.txp_pd_table; + u8 *pcdac_out = ah->ah_txpower.txp_pd_table; u8 *pcdac_low_pwr; u8 *pcdac_high_pwr; u8 *pcdac_tmp; @@ -2552,7 +2552,7 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, } /* This is used when setting tx power*/ - ah->ah_txpower.txp_min_idx = min_pwr_idx/2; + ah->ah_txpower.txp_min_idx = min_pwr_idx / 2; /* Fill Power to PCDAC table backwards */ pwr = max_pwr_idx; @@ -2561,10 +2561,10 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, * edge flag and set pcdac_tmp to lower * power curve.*/ if (edge_flag == 0x40 && - (2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) { + (2 * pwr <= (table_max[1] - table_min[0]) || pwr == 0)) { edge_flag = 0x00; pcdac_tmp = pcdac_low_pwr; - pwr = mid_pwr_idx/2; + pwr = mid_pwr_idx / 2; } /* Don't go below 1, extrapolate below if we have @@ -2596,7 +2596,7 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, static void ath5k_write_pcdac_table(struct ath5k_hw *ah) { - u8 *pcdac_out = ah->ah_txpower.txp_pd_table; + u8 *pcdac_out = ah->ah_txpower.txp_pd_table; int i; /* @@ -2604,8 +2604,8 @@ ath5k_write_pcdac_table(struct ath5k_hw *ah) */ for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { ath5k_hw_reg_write(ah, - (((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) | - (((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16), + (((pcdac_out[2 * i + 0] << 8 | 0xff) & 0xffff) << 0) | + (((pcdac_out[2 * i + 1] << 8 | 0xff) & 0xffff) << 16), AR5K_PHY_PCDAC_TXPOWER(i)); } } @@ -2789,10 +2789,10 @@ ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode) */ for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { ath5k_hw_reg_write(ah, - ((pdadc_out[4*i + 0] & 0xff) << 0) | - ((pdadc_out[4*i + 1] & 0xff) << 8) | - ((pdadc_out[4*i + 2] & 0xff) << 16) | - ((pdadc_out[4*i + 3] & 0xff) << 24), + ((pdadc_out[4 * i + 0] & 0xff) << 0) | + ((pdadc_out[4 * i + 1] & 0xff) << 8) | + ((pdadc_out[4 * i + 2] & 0xff) << 16) | + ((pdadc_out[4 * i + 3] & 0xff) << 24), AR5K_PHY_PDADC_TXPOWER(i)); } } diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index d12b827033c1..994d29ace34d 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -72,7 +72,7 @@ #define AR5K_CFG_SWRD 0x00000004 /* Byte-swap RX descriptor */ #define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer */ #define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register access */ -#define AR5K_CFG_IBSS 0x00000020 /* 0-BSS, 1-IBSS [5211+] */ +#define AR5K_CFG_IBSS 0x00000020 /* 0-BSS, 1-IBSS [5211+] */ #define AR5K_CFG_PHY_OK 0x00000100 /* [5211+] */ #define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */ #define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (Disable dynamic clock) */ @@ -303,7 +303,7 @@ #define AR5K_ISR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ #define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ #define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ -#define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ +#define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ #define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ #define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */ #define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */ @@ -397,7 +397,7 @@ #define AR5K_IMR_BRSSI 0x00020000 /* Beacon rssi below threshold (?) */ #define AR5K_IMR_BMISS 0x00040000 /* Beacon missed*/ #define AR5K_IMR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ -#define AR5K_IMR_BNR 0x00100000 /* Beacon not ready [5211+] */ +#define AR5K_IMR_BNR 0x00100000 /* Beacon not ready [5211+] */ #define AR5K_IMR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ #define AR5K_IMR_RXCHIRP 0x00200000 /* CHIRP Received [5212+]*/ #define AR5K_IMR_SSERR 0x00200000 /* Signaled System Error [5210] */ @@ -1328,16 +1328,16 @@ #define AR5K_RX_FILTER_5211 0x803c /* Register Address [5211+] */ #define AR5K_RX_FILTER (ah->ah_version == AR5K_AR5210 ? \ AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211) -#define AR5K_RX_FILTER_UCAST 0x00000001 /* Don't filter unicast frames */ -#define AR5K_RX_FILTER_MCAST 0x00000002 /* Don't filter multicast frames */ -#define AR5K_RX_FILTER_BCAST 0x00000004 /* Don't filter broadcast frames */ -#define AR5K_RX_FILTER_CONTROL 0x00000008 /* Don't filter control frames */ -#define AR5K_RX_FILTER_BEACON 0x00000010 /* Don't filter beacon frames */ -#define AR5K_RX_FILTER_PROM 0x00000020 /* Set promiscuous mode */ -#define AR5K_RX_FILTER_XRPOLL 0x00000040 /* Don't filter XR poll frame [5212+] */ +#define AR5K_RX_FILTER_UCAST 0x00000001 /* Don't filter unicast frames */ +#define AR5K_RX_FILTER_MCAST 0x00000002 /* Don't filter multicast frames */ +#define AR5K_RX_FILTER_BCAST 0x00000004 /* Don't filter broadcast frames */ +#define AR5K_RX_FILTER_CONTROL 0x00000008 /* Don't filter control frames */ +#define AR5K_RX_FILTER_BEACON 0x00000010 /* Don't filter beacon frames */ +#define AR5K_RX_FILTER_PROM 0x00000020 /* Set promiscuous mode */ +#define AR5K_RX_FILTER_XRPOLL 0x00000040 /* Don't filter XR poll frame [5212+] */ #define AR5K_RX_FILTER_PROBEREQ 0x00000080 /* Don't filter probe requests [5212+] */ #define AR5K_RX_FILTER_PHYERR_5212 0x00000100 /* Don't filter phy errors [5212+] */ -#define AR5K_RX_FILTER_RADARERR_5212 0x00000200 /* Don't filter phy radar errors [5212+] */ +#define AR5K_RX_FILTER_RADARERR_5212 0x00000200 /* Don't filter phy radar errors [5212+] */ #define AR5K_RX_FILTER_PHYERR_5211 0x00000040 /* [5211] */ #define AR5K_RX_FILTER_RADARERR_5211 0x00000080 /* [5211] */ #define AR5K_RX_FILTER_PHYERR \ @@ -1461,7 +1461,7 @@ * ADDAC test register [5211+] */ #define AR5K_ADDAC_TEST 0x8054 /* Register Address */ -#define AR5K_ADDAC_TEST_TXCONT 0x00000001 /* Test continuous tx */ +#define AR5K_ADDAC_TEST_TXCONT 0x00000001 /* Test continuous tx */ #define AR5K_ADDAC_TEST_TST_MODE 0x00000002 /* Test mode */ #define AR5K_ADDAC_TEST_LOOP_EN 0x00000004 /* Enable loop */ #define AR5K_ADDAC_TEST_LOOP_LEN 0x00000008 /* Loop length (field) */ @@ -2038,7 +2038,7 @@ #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S 24 /* Low thresholds */ -#define AR5K_PHY_WEAK_OFDM_LOW_THR 0x986c +#define AR5K_PHY_WEAK_OFDM_LOW_THR 0x986c #define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN 0x00000001 #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT 0x00003f00 #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S 8 @@ -2259,12 +2259,13 @@ #define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* Illegal length */ #define AR5K_PHY_FRAME_CTL_SERVICE_ERR 0x20000000 #define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* TX underrun */ -#define AR5K_PHY_FRAME_CTL_INI AR5K_PHY_FRAME_CTL_SERVICE_ERR | \ - AR5K_PHY_FRAME_CTL_TXURN_ERR | \ - AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \ - AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \ - AR5K_PHY_FRAME_CTL_PARITY_ERR | \ - AR5K_PHY_FRAME_CTL_TIMING_ERR +#define AR5K_PHY_FRAME_CTL_INI \ + (AR5K_PHY_FRAME_CTL_SERVICE_ERR | \ + AR5K_PHY_FRAME_CTL_TXURN_ERR | \ + AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \ + AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \ + AR5K_PHY_FRAME_CTL_PARITY_ERR | \ + AR5K_PHY_FRAME_CTL_TIMING_ERR) /* * PHY Tx Power adjustment register [5212A+] @@ -2281,22 +2282,22 @@ #define AR5K_PHY_RADAR 0x9954 #define AR5K_PHY_RADAR_ENABLE 0x00000001 #define AR5K_PHY_RADAR_DISABLE 0x00000000 -#define AR5K_PHY_RADAR_INBANDTHR 0x0000003e /* Inband threshold +#define AR5K_PHY_RADAR_INBANDTHR 0x0000003e /* Inband threshold 5-bits, units unknown {0..31} (? MHz ?) */ #define AR5K_PHY_RADAR_INBANDTHR_S 1 -#define AR5K_PHY_RADAR_PRSSI_THR 0x00000fc0 /* Pulse RSSI/SNR threshold +#define AR5K_PHY_RADAR_PRSSI_THR 0x00000fc0 /* Pulse RSSI/SNR threshold 6-bits, dBm range {0..63} in dBm units. */ #define AR5K_PHY_RADAR_PRSSI_THR_S 6 -#define AR5K_PHY_RADAR_PHEIGHT_THR 0x0003f000 /* Pulse height threshold +#define AR5K_PHY_RADAR_PHEIGHT_THR 0x0003f000 /* Pulse height threshold 6-bits, dBm range {0..63} in dBm units. */ #define AR5K_PHY_RADAR_PHEIGHT_THR_S 12 -#define AR5K_PHY_RADAR_RSSI_THR 0x00fc0000 /* Radar RSSI/SNR threshold. +#define AR5K_PHY_RADAR_RSSI_THR 0x00fc0000 /* Radar RSSI/SNR threshold. 6-bits, dBm range {0..63} in dBm units. */ #define AR5K_PHY_RADAR_RSSI_THR_S 18 diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 1676a3e3dc3d..19aefdb75416 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -25,7 +25,7 @@ #include <asm/unaligned.h> -#include <linux/pci.h> /* To determine if a card is pci-e */ +#include <linux/pci.h> /* To determine if a card is pci-e */ #include <linux/log2.h> #include <linux/platform_device.h> #include "ath5k.h" @@ -142,10 +142,10 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) /* Set 32MHz USEC counter */ if ((ah->ah_radio == AR5K_RF5112) || - (ah->ah_radio == AR5K_RF5413) || - (ah->ah_radio == AR5K_RF2316) || - (ah->ah_radio == AR5K_RF2317)) - /* Remain on 40MHz clock ? */ + (ah->ah_radio == AR5K_RF5413) || + (ah->ah_radio == AR5K_RF2316) || + (ah->ah_radio == AR5K_RF2317)) + /* Remain on 40MHz clock ? */ sclock = 40 - 1; else sclock = 32 - 1; @@ -375,7 +375,7 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) { u32 mask = flags ? flags : ~0U; - volatile __iomem u32 *reg; + u32 __iomem *reg; u32 regval; u32 val = 0; diff --git a/drivers/net/wireless/ath/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h index 16b67e84906d..5d11c23b4297 100644 --- a/drivers/net/wireless/ath/ath5k/rfbuffer.h +++ b/drivers/net/wireless/ath/ath5k/rfbuffer.h @@ -254,7 +254,7 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = { /* RFX112 (Derby 1) */ -/* BANK 6 len pos col */ +/* BANK 6 len pos col */ #define AR5K_RF5112_OB_2GHZ { 3, 269, 0 } #define AR5K_RF5112_DB_2GHZ { 3, 272, 0 } @@ -495,7 +495,7 @@ static const struct ath5k_ini_rfbuffer rfb_5112a[] = { /* BANK 2 len pos col */ #define AR5K_RF2413_RF_TURBO { 1, 1, 2 } -/* BANK 6 len pos col */ +/* BANK 6 len pos col */ #define AR5K_RF2413_OB_2GHZ { 3, 168, 0 } #define AR5K_RF2413_DB_2GHZ { 3, 165, 0 } diff --git a/drivers/net/wireless/ath/ath5k/rfgain.h b/drivers/net/wireless/ath/ath5k/rfgain.h index 1354d8c392c8..70c9a45609f0 100644 --- a/drivers/net/wireless/ath/ath5k/rfgain.h +++ b/drivers/net/wireless/ath/ath5k/rfgain.h @@ -452,7 +452,7 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = { /* Check if our current measurement is inside our * current variable attenuation window */ -#define AR5K_GAIN_CHECK_ADJUST(_g) \ +#define AR5K_GAIN_CHECK_ADJUST(_g) \ ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) struct ath5k_gain_opt_step { diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c index 929c68cdf8ab..d8ad0e45e1c4 100644 --- a/drivers/net/wireless/ath/ath5k/sysfs.c +++ b/drivers/net/wireless/ath/ath5k/sysfs.c @@ -10,18 +10,22 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - struct ath5k_softc *sc = dev_get_drvdata(dev); \ - return snprintf(buf, PAGE_SIZE, "%d\n", get); \ + struct ieee80211_hw *hw = dev_get_drvdata(dev); \ + struct ath5k_softc *sc = hw->priv; \ + return snprintf(buf, PAGE_SIZE, "%d\n", get); \ } \ \ static ssize_t ath5k_attr_store_##name(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct ath5k_softc *sc = dev_get_drvdata(dev); \ - int val; \ + struct ieee80211_hw *hw = dev_get_drvdata(dev); \ + struct ath5k_softc *sc = hw->priv; \ + int val, ret; \ \ - val = (int)simple_strtoul(buf, NULL, 10); \ + ret = kstrtoint(buf, 10, &val); \ + if (ret < 0) \ + return ret; \ set(sc->ah, val); \ return count; \ } \ @@ -33,8 +37,9 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - struct ath5k_softc *sc = dev_get_drvdata(dev); \ - return snprintf(buf, PAGE_SIZE, "%d\n", get); \ + struct ieee80211_hw *hw = dev_get_drvdata(dev); \ + struct ath5k_softc *sc = hw->priv; \ + return snprintf(buf, PAGE_SIZE, "%d\n", get); \ } \ static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL) diff --git a/drivers/net/wireless/ath/ath5k/trace.h b/drivers/net/wireless/ath/ath5k/trace.h index 2de68adb6240..235e0768ce1d 100644 --- a/drivers/net/wireless/ath/ath5k/trace.h +++ b/drivers/net/wireless/ath/ath5k/trace.h @@ -12,9 +12,6 @@ static inline void trace_ ## name(proto) {} struct sk_buff; -#define PRIV_ENTRY __field(struct ath5k_softc *, priv) -#define PRIV_ASSIGN __entry->priv = priv - #undef TRACE_SYSTEM #define TRACE_SYSTEM ath5k @@ -22,12 +19,12 @@ TRACE_EVENT(ath5k_rx, TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb), TP_ARGS(priv, skb), TP_STRUCT__entry( - PRIV_ENTRY + __field(struct ath5k_softc *, priv) __field(unsigned long, skbaddr) __dynamic_array(u8, frame, skb->len) ), TP_fast_assign( - PRIV_ASSIGN; + __entry->priv = priv; __entry->skbaddr = (unsigned long) skb; memcpy(__get_dynamic_array(frame), skb->data, skb->len); ), @@ -43,14 +40,14 @@ TRACE_EVENT(ath5k_tx, TP_ARGS(priv, skb, q), TP_STRUCT__entry( - PRIV_ENTRY + __field(struct ath5k_softc *, priv) __field(unsigned long, skbaddr) __field(u8, qnum) __dynamic_array(u8, frame, skb->len) ), TP_fast_assign( - PRIV_ASSIGN; + __entry->priv = priv; __entry->skbaddr = (unsigned long) skb; __entry->qnum = (u8) q->qnum; memcpy(__get_dynamic_array(frame), skb->data, skb->len); @@ -69,7 +66,7 @@ TRACE_EVENT(ath5k_tx_complete, TP_ARGS(priv, skb, q, ts), TP_STRUCT__entry( - PRIV_ENTRY + __field(struct ath5k_softc *, priv) __field(unsigned long, skbaddr) __field(u8, qnum) __field(u8, ts_status) @@ -78,7 +75,7 @@ TRACE_EVENT(ath5k_tx_complete, ), TP_fast_assign( - PRIV_ASSIGN; + __entry->priv = priv; __entry->skbaddr = (unsigned long) skb; __entry->qnum = (u8) q->qnum; __entry->ts_status = ts->ts_status; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index e8ac70da5ac7..2339728a7306 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -653,8 +653,8 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = { {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, - {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, @@ -761,7 +761,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x0000a3ec, 0x20202020}, {0x0000a3f0, 0x00000000}, {0x0000a3f4, 0x00000246}, - {0x0000a3f8, 0x0cdbd380}, + {0x0000a3f8, 0x0c9bd380}, {0x0000a3fc, 0x000f0f01}, {0x0000a400, 0x8fa91f01}, {0x0000a404, 0x00000000}, @@ -780,7 +780,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x0000a43c, 0x00100000}, {0x0000a440, 0x00000000}, {0x0000a444, 0x00000000}, - {0x0000a448, 0x06000080}, + {0x0000a448, 0x05000080}, {0x0000a44c, 0x00000001}, {0x0000a450, 0x00010000}, {0x0000a458, 0x00000000}, @@ -1500,8 +1500,6 @@ static const u32 ar9300_2p2_mac_core[][2] = { {0x0000816c, 0x00000000}, {0x000081c0, 0x00000000}, {0x000081c4, 0x33332210}, - {0x000081c8, 0x00000000}, - {0x000081cc, 0x00000000}, {0x000081ec, 0x00000000}, {0x000081f0, 0x00000000}, {0x000081f4, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 04e6be04acf9..575e185f454f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -229,6 +229,7 @@ static void ar9003_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen, static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_status *ts) { + struct ar9003_txc *txc = (struct ar9003_txc *) ds; struct ar9003_txs *ads; u32 status; @@ -238,7 +239,11 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, if ((status & AR_TxDone) == 0) return -EINPROGRESS; - ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; + ts->qid = MS(ads->ds_info, AR_TxQcuNum); + if (!txc || (MS(txc->info, AR_TxQcuNum) == ts->qid)) + ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; + else + return -ENOENT; if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) || (MS(ads->ds_info, AR_TxRxDesc) != 1)) { @@ -254,7 +259,6 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_seqnum = MS(status, AR_SeqNum); ts->tid = MS(status, AR_TxTid); - ts->qid = MS(ads->ds_info, AR_TxQcuNum); ts->desc_id = MS(ads->status1, AR_TxDescId); ts->ts_tstamp = ads->status4; ts->ts_status = 0; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 8f6d11dfa371..f80d1d633980 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -21,6 +21,36 @@ void ar9003_paprd_enable(struct ath_hw *ah, bool val) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath9k_channel *chan = ah->curchan; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + + /* + * 3 bits for modalHeader5G.papdRateMaskHt20 + * is used for sub-band disabling of PAPRD. + * 5G band is divided into 3 sub-bands -- upper, + * middle, lower. + * if bit 30 of modalHeader5G.papdRateMaskHt20 is set + * -- disable PAPRD for upper band 5GHz + * if bit 29 of modalHeader5G.papdRateMaskHt20 is set + * -- disable PAPRD for middle band 5GHz + * if bit 28 of modalHeader5G.papdRateMaskHt20 is set + * -- disable PAPRD for lower band 5GHz + */ + + if (IS_CHAN_5GHZ(chan)) { + if (chan->channel >= UPPER_5G_SUB_BAND_START) { + if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20) + & BIT(30)) + val = false; + } else if (chan->channel >= MID_5G_SUB_BAND_START) { + if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20) + & BIT(29)) + val = false; + } else { + if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20) + & BIT(28)) + val = false; + } + } if (val) { ah->paprd_table_write_done = true; @@ -236,7 +266,7 @@ static void ar9003_paprd_get_gain_table(struct ath_hw *ah) memset(entry, 0, sizeof(ah->paprd_gain_table_entries)); memset(index, 0, sizeof(ah->paprd_gain_table_index)); - for (i = 0; i < 32; i++) { + for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) { entry[i] = REG_READ(ah, reg); index[i] = (entry[i] >> 24) & 0xff; reg += 4; @@ -246,13 +276,13 @@ static void ar9003_paprd_get_gain_table(struct ath_hw *ah) static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, int target_power) { - int olpc_gain_delta = 0; + int olpc_gain_delta = 0, cl_gain_mod; int alpha_therm, alpha_volt; int therm_cal_value, volt_cal_value; int therm_value, volt_value; int thermal_gain_corr, voltage_gain_corr; int desired_scale, desired_gain = 0; - u32 reg; + u32 reg_olpc = 0, reg_cl_gain = 0; REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); @@ -271,15 +301,29 @@ static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE); - if (chain == 0) - reg = AR_PHY_TPC_11_B0; - else if (chain == 1) - reg = AR_PHY_TPC_11_B1; - else - reg = AR_PHY_TPC_11_B2; + switch (chain) { + case 0: + reg_olpc = AR_PHY_TPC_11_B0; + reg_cl_gain = AR_PHY_CL_TAB_0; + break; + case 1: + reg_olpc = AR_PHY_TPC_11_B1; + reg_cl_gain = AR_PHY_CL_TAB_1; + break; + case 2: + reg_olpc = AR_PHY_TPC_11_B2; + reg_cl_gain = AR_PHY_CL_TAB_2; + break; + default: + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "Invalid chainmask: %d\n", chain); + break; + } - olpc_gain_delta = REG_READ_FIELD(ah, reg, + olpc_gain_delta = REG_READ_FIELD(ah, reg_olpc, AR_PHY_TPC_11_OLPC_GAIN_DELTA); + cl_gain_mod = REG_READ_FIELD(ah, reg_cl_gain, + AR_PHY_CL_TAB_CL_GAIN_MOD); if (olpc_gain_delta >= 128) olpc_gain_delta = olpc_gain_delta - 256; @@ -289,7 +333,7 @@ static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) + (128 / 2)) / 128; desired_gain = target_power - olpc_gain_delta - thermal_gain_corr - - voltage_gain_corr + desired_scale; + voltage_gain_corr + desired_scale + cl_gain_mod; return desired_gain; } @@ -727,7 +771,7 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) desired_gain = ar9003_get_desired_gain(ah, chain, train_power); gain_index = 0; - for (i = 0; i < 32; i++) { + for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) { if (ah->paprd_gain_table_index[i] >= desired_gain) break; gain_index++; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 9eb3aa211688..6de3f0bc18e6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -1121,6 +1121,9 @@ #define AR_PHY_POWERTX_RATE8_POWERTXHT40_5 0x3F00 #define AR_PHY_POWERTX_RATE8_POWERTXHT40_5_S 8 +#define AR_PHY_CL_TAB_CL_GAIN_MOD 0x1f +#define AR_PHY_CL_TAB_CL_GAIN_MOD_S 0 + void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); #endif /* AR9003_PHY_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 56a0ac4ddc62..964fb971fd6a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -100,6 +100,11 @@ enum buffer_type { #define ATH_TXSTATUS_RING_SIZE 64 +#define DS2PHYS(_dd, _ds) \ + ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) +#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) +#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) + struct ath_descdma { void *dd_desc; dma_addr_t dd_desc_paddr; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 0174cdb65a83..e19a230dfff9 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -360,6 +360,7 @@ void ath_beacon_tasklet(unsigned long data) struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf = NULL; struct ieee80211_vif *vif; + struct ath_tx_status ts; int slot; u32 bfaddr, bc = 0; @@ -384,7 +385,9 @@ void ath_beacon_tasklet(unsigned long data) ath_dbg(common, ATH_DBG_BSTUCK, "beacon is officially stuck\n"); sc->sc_flags |= SC_OP_TSF_RESET; + spin_lock(&sc->sc_pcu_lock); ath_reset(sc, true); + spin_unlock(&sc->sc_pcu_lock); } return; @@ -464,6 +467,11 @@ void ath_beacon_tasklet(unsigned long data) ath9k_hw_txstart(ah, sc->beacon.beaconq); sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + spin_lock_bh(&sc->sc_pcu_lock); + ath9k_hw_txprocdesc(ah, bf->bf_desc, (void *)&ts); + spin_unlock_bh(&sc->sc_pcu_lock); + } } } diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 260f1f37a60e..8028fe90f666 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -49,6 +49,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { .driver_info = AR9280_USB }, /* Netgear WNDA3200 */ { USB_DEVICE(0x083A, 0xA704), .driver_info = AR9280_USB }, /* SMC Networks */ + { USB_DEVICE(0x0411, 0x017f), + .driver_info = AR9280_USB }, /* Sony UWA-BR100 */ { USB_DEVICE(0x0cf3, 0x20ff), .driver_info = STORAGE_DEVICE }, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 61e6d3950718..3bea7ea86f0a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -754,6 +754,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; hw->wiphy->interface_modes = diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 7b7796895432..7212acb2bd6c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1294,11 +1294,16 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, u32 rfilt; mutex_lock(&priv->mutex); - ath9k_htc_ps_wakeup(priv); - changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; + if (priv->op_flags & OP_INVALID) { + ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_ANY, + "Unable to configure filter on invalid state\n"); + return; + } + ath9k_htc_ps_wakeup(priv); + priv->rxfilter = *total_flags; rfilt = ath9k_htc_calcrxfilter(priv); ath9k_hw_setrxfilter(priv->ah, rfilt); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 818acdd1ba90..a1c317455bc0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -143,6 +143,8 @@ #define AR_KEYTABLE_SIZE 128 #define POWER_UP_TIME 10000 #define SPUR_RSSI_THRESH 40 +#define UPPER_5G_SUB_BAND_START 5700 +#define MID_5G_SUB_BAND_START 5400 #define CAB_TIMEOUT_VAL 10 #define BEACON_TIMEOUT_VAL 10 diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 50103b2792b5..ce297173e0d3 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -298,10 +298,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head, const char *name, int nbuf, int ndesc, bool is_tx) { -#define DS2PHYS(_dd, _ds) \ - ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) -#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) -#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) struct ath_common *common = ath9k_hw_common(sc->sc_ah); u8 *ds; struct ath_buf *bf; @@ -396,9 +392,6 @@ fail2: fail: memset(dd, 0, sizeof(*dd)); return error; -#undef ATH_DESC_4KB_BOUND_CHECK -#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED -#undef DS2PHYS } void ath9k_init_crypto(struct ath_softc *sc) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5ae303b11e68..9098aaad97a9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -617,8 +617,11 @@ void ath_hw_check(struct work_struct *work) ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); if (busy >= 99) { - if (++sc->hw_busy_count >= 3) + if (++sc->hw_busy_count >= 3) { + spin_lock_bh(&sc->sc_pcu_lock); ath_reset(sc, true); + spin_unlock_bh(&sc->sc_pcu_lock); + } } else if (busy >= 0) sc->hw_busy_count = 0; @@ -637,7 +640,9 @@ static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) /* Rx is hung for more than 500ms. Reset it */ ath_dbg(common, ATH_DBG_RESET, "Possible RX hang, resetting"); + spin_lock_bh(&sc->sc_pcu_lock); ath_reset(sc, true); + spin_unlock_bh(&sc->sc_pcu_lock); count = 0; } } else @@ -674,7 +679,9 @@ void ath9k_tasklet(unsigned long data) if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_BB_WATCHDOG)) { + spin_lock(&sc->sc_pcu_lock); ath_reset(sc, true); + spin_unlock(&sc->sc_pcu_lock); return; } @@ -980,7 +987,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) del_timer_sync(&common->ani.timer); ath9k_ps_wakeup(sc); - spin_lock_bh(&sc->sc_pcu_lock); ieee80211_stop_queues(hw); @@ -1023,7 +1029,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) } ieee80211_wake_queues(hw); - spin_unlock_bh(&sc->sc_pcu_lock); /* Start ANI */ if (!common->disable_ani) @@ -2326,9 +2331,9 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) ath9k_ps_wakeup(sc); spin_lock_bh(&sc->sc_pcu_lock); drain_txq = ath_drain_all_txq(sc, false); - spin_unlock_bh(&sc->sc_pcu_lock); if (!drain_txq) ath_reset(sc, false); + spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); ieee80211_wake_queues(hw); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index b8cbfc707213..3bad0b2cf9a3 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -278,6 +278,12 @@ static int ath_pci_suspend(struct device *device) ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); + /* The device has to be moved to FULLSLEEP forcibly. + * Otherwise the chip never moved to full sleep, + * when no interface is up. + */ + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index ec012b4317af..9283440a0210 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -565,11 +565,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_unlock(); - if (needreset) { - spin_unlock_bh(&sc->sc_pcu_lock); + if (needreset) ath_reset(sc, false); - spin_lock_bh(&sc->sc_pcu_lock); - } } static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, @@ -664,7 +661,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, * TODO - this could be improved to be dependent on the rate. * The hardware can keep up at lower rates, but not higher rates */ - if (fi->keyix != ATH9K_TXKEYIX_INVALID) + if ((fi->keyix != ATH9K_TXKEYIX_INVALID) && + !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) ndelim += ATH_AGGR_ENCRYPTDELIM; /* @@ -2169,7 +2167,9 @@ static void ath_tx_complete_poll_work(struct work_struct *work) if (needreset) { ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, "tx hung, resetting the chip\n"); + spin_lock_bh(&sc->sc_pcu_lock); ath_reset(sc, true); + spin_unlock_bh(&sc->sc_pcu_lock); } ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 4da01a9f5680..f9a4655ea0b8 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -67,6 +67,8 @@ #define PAYLOAD_MAX (CARL9170_MAX_CMD_LEN / 4 - 1) +static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 3, 2, 1, 0 }; + enum carl9170_rf_init_mode { CARL9170_RFI_NONE, CARL9170_RFI_WARM, @@ -440,7 +442,6 @@ struct ar9170 { enum carl9170_ps_off_override_reasons { PS_OFF_VIF = BIT(0), PS_OFF_BCN = BIT(1), - PS_OFF_5GHZ = BIT(2), }; struct carl9170_ba_stats { diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 221957c5d373..39ddea5794f7 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -237,7 +237,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) ar->disable_offload = true; } - if (SUPP(CARL9170FW_PSM)) + if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM)) ar->hw->flags |= IEEE80211_HW_SUPPORTS_PS; if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE)) { diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h index 30449d21b762..0a6dec529b59 100644 --- a/drivers/net/wireless/ath/carl9170/fwcmd.h +++ b/drivers/net/wireless/ath/carl9170/fwcmd.h @@ -4,7 +4,7 @@ * Firmware command interface definitions * * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com> + * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com> * * 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 @@ -54,6 +54,7 @@ enum carl9170_cmd_oids { CARL9170_CMD_BCN_CTRL = 0x05, CARL9170_CMD_READ_TSF = 0x06, CARL9170_CMD_RX_FILTER = 0x07, + CARL9170_CMD_WOL = 0x08, /* CAM */ CARL9170_CMD_EKEY = 0x10, @@ -180,6 +181,21 @@ struct carl9170_bcn_ctrl_cmd { #define CARL9170_BCN_CTRL_DRAIN 0 #define CARL9170_BCN_CTRL_CAB_TRIGGER 1 +struct carl9170_wol_cmd { + __le32 flags; + u8 mac[6]; + u8 bssid[6]; + __le32 null_interval; + __le32 free_for_use2; + __le32 mask; + u8 pattern[32]; +} __packed; + +#define CARL9170_WOL_CMD_SIZE 60 + +#define CARL9170_WOL_DISCONNECT 1 +#define CARL9170_WOL_MAGIC_PKT 2 + struct carl9170_cmd_head { union { struct { @@ -203,6 +219,7 @@ struct carl9170_cmd { struct carl9170_write_reg wreg; struct carl9170_rf_init rf_init; struct carl9170_psm psm; + struct carl9170_wol_cmd wol; struct carl9170_bcn_ctrl_cmd bcn_ctrl; struct carl9170_rx_filter_cmd rx_filter; u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN]; diff --git a/drivers/net/wireless/ath/carl9170/fwdesc.h b/drivers/net/wireless/ath/carl9170/fwdesc.h index 921066822dd5..7ba62bb77054 100644 --- a/drivers/net/wireless/ath/carl9170/fwdesc.h +++ b/drivers/net/wireless/ath/carl9170/fwdesc.h @@ -3,7 +3,7 @@ * * Firmware descriptor format * - * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com> + * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com> * * 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 @@ -72,6 +72,9 @@ enum carl9170fw_feature_list { /* Wake up on WLAN */ CARL9170FW_WOL, + /* Firmware supports PSM in the 5GHZ Band */ + CARL9170FW_FIXED_5GHZ_PSM, + /* KEEP LAST */ __CARL9170FW_FEATURE_NUM }; @@ -82,6 +85,7 @@ enum carl9170fw_feature_list { #define DBG_MAGIC "DBG\0" #define CHK_MAGIC "CHK\0" #define TXSQ_MAGIC "TXSQ" +#define WOL_MAGIC "WOL\0" #define LAST_MAGIC "LAST" #define CARL9170FW_SET_DAY(d) (((d) - 1) % 31) @@ -104,7 +108,7 @@ struct carl9170fw_desc_head { (sizeof(struct carl9170fw_desc_head)) #define CARL9170FW_OTUS_DESC_MIN_VER 6 -#define CARL9170FW_OTUS_DESC_CUR_VER 6 +#define CARL9170FW_OTUS_DESC_CUR_VER 7 struct carl9170fw_otus_desc { struct carl9170fw_desc_head head; __le32 feature_set; @@ -186,6 +190,16 @@ struct carl9170fw_txsq_desc { #define CARL9170FW_TXSQ_DESC_SIZE \ (sizeof(struct carl9170fw_txsq_desc)) +#define CARL9170FW_WOL_DESC_MIN_VER 1 +#define CARL9170FW_WOL_DESC_CUR_VER 1 +struct carl9170fw_wol_desc { + struct carl9170fw_desc_head head; + + __le32 supported_triggers; /* CARL9170_WOL_ */ +} __packed; +#define CARL9170FW_WOL_DESC_SIZE \ + (sizeof(struct carl9170fw_wol_desc)) + #define CARL9170FW_LAST_DESC_MIN_VER 1 #define CARL9170FW_LAST_DESC_CUR_VER 2 struct carl9170fw_last_desc { diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h index 4e30762dd903..261f89351070 100644 --- a/drivers/net/wireless/ath/carl9170/hw.h +++ b/drivers/net/wireless/ath/carl9170/hw.h @@ -4,7 +4,7 @@ * Register map, hardware-specific definitions * * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com> + * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com> * * 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 @@ -357,7 +357,18 @@ #define AR9170_MAC_REG_DMA_WLAN_STATUS (AR9170_MAC_REG_BASE + 0xd38) #define AR9170_MAC_REG_DMA_STATUS (AR9170_MAC_REG_BASE + 0xd3c) - +#define AR9170_MAC_REG_DMA_TXQ_LAST_ADDR (AR9170_MAC_REG_BASE + 0xd40) +#define AR9170_MAC_REG_DMA_TXQ0_LAST_ADDR (AR9170_MAC_REG_BASE + 0xd40) +#define AR9170_MAC_REG_DMA_TXQ1_LAST_ADDR (AR9170_MAC_REG_BASE + 0xd44) +#define AR9170_MAC_REG_DMA_TXQ2_LAST_ADDR (AR9170_MAC_REG_BASE + 0xd48) +#define AR9170_MAC_REG_DMA_TXQ3_LAST_ADDR (AR9170_MAC_REG_BASE + 0xd4c) +#define AR9170_MAC_REG_DMA_TXQ4_LAST_ADDR (AR9170_MAC_REG_BASE + 0xd50) +#define AR9170_MAC_REG_DMA_TXQ0Q1_LEN (AR9170_MAC_REG_BASE + 0xd54) +#define AR9170_MAC_REG_DMA_TXQ2Q3_LEN (AR9170_MAC_REG_BASE + 0xd58) +#define AR9170_MAC_REG_DMA_TXQ4_LEN (AR9170_MAC_REG_BASE + 0xd5c) + +#define AR9170_MAC_REG_DMA_TXQX_LAST_ADDR (AR9170_MAC_REG_BASE + 0xd74) +#define AR9170_MAC_REG_DMA_TXQX_FAIL_ADDR (AR9170_MAC_REG_BASE + 0xd78) #define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xd7c) #define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f #define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0 diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 54d093c2ab44..a61cf6781d5e 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -345,11 +345,11 @@ static int carl9170_op_start(struct ieee80211_hw *hw) carl9170_zap_queues(ar); /* reset QoS defaults */ - CARL9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT */ - CARL9170_FILL_QUEUE(ar->edcf[1], 2, 7, 15, 94); /* VIDEO */ - CARL9170_FILL_QUEUE(ar->edcf[2], 2, 3, 7, 47); /* VOICE */ - CARL9170_FILL_QUEUE(ar->edcf[3], 7, 15, 1023, 0); /* BACKGROUND */ - CARL9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ + CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_VO], 2, 3, 7, 47); + CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_VI], 2, 7, 15, 94); + CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_BE], 3, 15, 1023, 0); + CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_BK], 7, 15, 1023, 0); + CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_SPECIAL], 2, 3, 7, 0); ar->current_factor = ar->current_density = -1; /* "The first key is unique." */ @@ -1484,6 +1484,13 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, } } +static bool carl9170_tx_frames_pending(struct ieee80211_hw *hw) +{ + struct ar9170 *ar = hw->priv; + + return !!atomic_read(&ar->tx_total_queued); +} + static const struct ieee80211_ops carl9170_ops = { .start = carl9170_op_start, .stop = carl9170_op_stop, @@ -1504,6 +1511,7 @@ static const struct ieee80211_ops carl9170_ops = { .get_survey = carl9170_op_get_survey, .get_stats = carl9170_op_get_stats, .ampdu_action = carl9170_op_ampdu_action, + .tx_frames_pending = carl9170_tx_frames_pending, }; void *carl9170_alloc(size_t priv_size) @@ -1577,6 +1585,7 @@ void *carl9170_alloc(size_t priv_size) IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SIGNAL_DBM; if (!modparam_noht) { diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c index b6ae0e179c8d..da1ab962ee48 100644 --- a/drivers/net/wireless/ath/carl9170/phy.c +++ b/drivers/net/wireless/ath/carl9170/phy.c @@ -1783,12 +1783,6 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, } } - /* FIXME: PSM does not work in 5GHz Band */ - if (channel->band == IEEE80211_BAND_5GHZ) - ar->ps.off_override |= PS_OFF_5GHZ; - else - ar->ps.off_override &= ~PS_OFF_5GHZ; - ar->channel = channel; ar->ht_settings = new_ht; return 0; diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index ec21ea9fd8d5..dc99030ea8b6 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -472,7 +472,7 @@ static struct sk_buff *carl9170_rx_copy_data(u8 *buf, int len) u8 *qc = ieee80211_get_qos_ctl(hdr); reserved += NET_IP_ALIGN; - if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) reserved += NET_IP_ALIGN; } diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 2fb53d067512..333b69ef2ae2 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -112,6 +112,8 @@ static struct usb_device_id carl9170_usb_ids[] = { { USB_DEVICE(0x04bb, 0x093f) }, /* NEC WL300NU-G */ { USB_DEVICE(0x0409, 0x0249) }, + /* NEC WL300NU-AG */ + { USB_DEVICE(0x0409, 0x02b4) }, /* AVM FRITZ!WLAN USB Stick N */ { USB_DEVICE(0x057c, 0x8401) }, /* AVM FRITZ!WLAN USB Stick N 2.4 */ diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index 15095c035169..64703778cfea 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H #define CARL9170FW_VERSION_YEAR 11 -#define CARL9170FW_VERSION_MONTH 1 -#define CARL9170FW_VERSION_DAY 22 -#define CARL9170FW_VERSION_GIT "1.9.2" +#define CARL9170FW_VERSION_MONTH 6 +#define CARL9170FW_VERSION_DAY 30 +#define CARL9170FW_VERSION_GIT "1.9.4" #endif /* __CARL9170_SHARED_VERSION_H */ diff --git a/drivers/net/wireless/ath/carl9170/wlan.h b/drivers/net/wireless/ath/carl9170/wlan.h index 9e1324b67e08..ea17995b32f4 100644 --- a/drivers/net/wireless/ath/carl9170/wlan.h +++ b/drivers/net/wireless/ath/carl9170/wlan.h @@ -4,7 +4,7 @@ * RX/TX meta descriptor format * * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> - * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com> + * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com> * * 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 @@ -278,7 +278,7 @@ struct ar9170_tx_frame { struct carl9170_tx_superframe { struct carl9170_tx_superdesc s; struct ar9170_tx_frame f; -} __packed; +} __packed __aligned(4); #endif /* __CARL9170FW__ */ @@ -328,7 +328,7 @@ struct _carl9170_tx_superframe { struct _carl9170_tx_superdesc s; struct _ar9170_tx_hwdesc f; u8 frame_data[0]; -} __packed; +} __packed __aligned(4); #define CARL9170_TX_SUPERDESC_LEN 24 #define AR9170_TX_HWDESC_LEN 8 @@ -404,16 +404,6 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) (t->DAidx & 0xc0) >> 6; } -enum ar9170_txq { - AR9170_TXQ_BE, - - AR9170_TXQ_VI, - AR9170_TXQ_VO, - AR9170_TXQ_BK, - - __AR9170_NUM_TXQ, -}; - /* * This is an workaround for several undocumented bugs. * Don't mess with the QoS/AC <-> HW Queue map, if you don't @@ -431,7 +421,14 @@ enum ar9170_txq { * result, this makes the device pretty much useless * for any serious 802.11n setup. */ -static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 2, 1, 0, 3 }; +enum ar9170_txq { + AR9170_TXQ_BK = 0, /* TXQ0 */ + AR9170_TXQ_BE, /* TXQ1 */ + AR9170_TXQ_VI, /* TXQ2 */ + AR9170_TXQ_VO, /* TXQ3 */ + + __AR9170_NUM_TXQ, +}; #define AR9170_TXQ_DEPTH 32 diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index d5add69aac8f..d2293dcc117f 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -90,6 +90,12 @@ config B43_SDIO #Data transfers to the device via PIO. We want it as a fallback even # if we can do DMA. +config B43_BCMA_PIO + bool + depends on B43_BCMA + select BCMA_BLOCKIO + default y + config B43_PIO bool depends on B43 @@ -125,6 +131,14 @@ config B43_PHY_HT Say N, this is BROKEN and crashes driver. +config B43_PHY_LCN + bool "Support for LCN-PHY devices (BROKEN)" + depends on B43 && BROKEN + ---help--- + Support for the LCN-PHY. + + Say N, this is BROKEN and crashes driver. + # This config option automatically enables b43 LEDS support, # if it's possible. config B43_LEDS diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 900dc9c8c688..4648bbf76abc 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -11,7 +11,9 @@ b43-$(CONFIG_B43_PHY_N) += phy_n.o b43-$(CONFIG_B43_PHY_LP) += phy_lp.o b43-$(CONFIG_B43_PHY_LP) += tables_lpphy.o b43-$(CONFIG_B43_PHY_HT) += phy_ht.o +b43-$(CONFIG_B43_PHY_HT) += tables_phy_ht.o b43-$(CONFIG_B43_PHY_HT) += radio_2059.o +b43-$(CONFIG_B43_PHY_LCN) += phy_lcn.o tables_phy_lcn.o b43-y += sysfs.o b43-y += xmit.o b43-y += lo.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 666515e348b5..08a28270bbb3 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -726,7 +726,6 @@ enum { /* Data structure for one wireless device (802.11 core) */ struct b43_wldev { - struct ssb_device *sdev; /* TODO: remove when b43_bus_dev is ready */ struct b43_bus_dev *dev; struct b43_wl *wl; diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c index 4200713eb597..a5e61a9fb539 100644 --- a/drivers/net/wireless/b43/bus.c +++ b/drivers/net/wireless/b43/bus.c @@ -23,6 +23,106 @@ #include "b43.h" #include "bus.h" +/* BCMA */ +#ifdef CONFIG_B43_BCMA +static int b43_bus_bcma_bus_may_powerdown(struct b43_bus_dev *dev) +{ + return 0; /* bcma_bus_may_powerdown(dev->bdev->bus); */ +} +static int b43_bus_bcma_bus_powerup(struct b43_bus_dev *dev, + bool dynamic_pctl) +{ + return 0; /* bcma_bus_powerup(dev->sdev->bus, dynamic_pctl); */ +} +static int b43_bus_bcma_device_is_enabled(struct b43_bus_dev *dev) +{ + return bcma_core_is_enabled(dev->bdev); +} +static void b43_bus_bcma_device_enable(struct b43_bus_dev *dev, + u32 core_specific_flags) +{ + bcma_core_enable(dev->bdev, core_specific_flags); +} +static void b43_bus_bcma_device_disable(struct b43_bus_dev *dev, + u32 core_specific_flags) +{ + bcma_core_disable(dev->bdev, core_specific_flags); +} +static u16 b43_bus_bcma_read16(struct b43_bus_dev *dev, u16 offset) +{ + return bcma_read16(dev->bdev, offset); +} +static u32 b43_bus_bcma_read32(struct b43_bus_dev *dev, u16 offset) +{ + return bcma_read32(dev->bdev, offset); +} +static +void b43_bus_bcma_write16(struct b43_bus_dev *dev, u16 offset, u16 value) +{ + bcma_write16(dev->bdev, offset, value); +} +static +void b43_bus_bcma_write32(struct b43_bus_dev *dev, u16 offset, u32 value) +{ + bcma_write32(dev->bdev, offset, value); +} +static +void b43_bus_bcma_block_read(struct b43_bus_dev *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + bcma_block_read(dev->bdev, buffer, count, offset, reg_width); +} +static +void b43_bus_bcma_block_write(struct b43_bus_dev *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + bcma_block_write(dev->bdev, buffer, count, offset, reg_width); +} + +struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core) +{ + struct b43_bus_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->bus_type = B43_BUS_BCMA; + dev->bdev = core; + + dev->bus_may_powerdown = b43_bus_bcma_bus_may_powerdown; + dev->bus_powerup = b43_bus_bcma_bus_powerup; + dev->device_is_enabled = b43_bus_bcma_device_is_enabled; + dev->device_enable = b43_bus_bcma_device_enable; + dev->device_disable = b43_bus_bcma_device_disable; + + dev->read16 = b43_bus_bcma_read16; + dev->read32 = b43_bus_bcma_read32; + dev->write16 = b43_bus_bcma_write16; + dev->write32 = b43_bus_bcma_write32; + dev->block_read = b43_bus_bcma_block_read; + dev->block_write = b43_bus_bcma_block_write; + + dev->dev = &core->dev; + dev->dma_dev = core->dma_dev; + dev->irq = core->irq; + + /* + dev->board_vendor = core->bus->boardinfo.vendor; + dev->board_type = core->bus->boardinfo.type; + dev->board_rev = core->bus->boardinfo.rev; + */ + + dev->chip_id = core->bus->chipinfo.id; + dev->chip_rev = core->bus->chipinfo.rev; + dev->chip_pkg = core->bus->chipinfo.pkg; + + dev->bus_sprom = &core->bus->sprom; + + dev->core_id = core->id.id; + dev->core_rev = core->id.rev; + + return dev; +} +#endif /* CONFIG_B43_BCMA */ /* SSB */ #ifdef CONFIG_B43_SSB @@ -125,3 +225,32 @@ struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev) return dev; } #endif /* CONFIG_B43_SSB */ + +void *b43_bus_get_wldev(struct b43_bus_dev *dev) +{ + switch (dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + return bcma_get_drvdata(dev->bdev); +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + return ssb_get_drvdata(dev->sdev); +#endif + } + return NULL; +} + +void b43_bus_set_wldev(struct b43_bus_dev *dev, void *wldev) +{ + switch (dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + bcma_set_drvdata(dev->bdev, wldev); +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + ssb_set_drvdata(dev->sdev, wldev); +#endif + } +} diff --git a/drivers/net/wireless/b43/bus.h b/drivers/net/wireless/b43/bus.h index 79a5ab4270c3..184c95659279 100644 --- a/drivers/net/wireless/b43/bus.h +++ b/drivers/net/wireless/b43/bus.h @@ -2,12 +2,16 @@ #define B43_BUS_H_ enum b43_bus_type { +#ifdef CONFIG_B43_BCMA + B43_BUS_BCMA, +#endif B43_BUS_SSB, }; struct b43_bus_dev { enum b43_bus_type bus_type; union { + struct bcma_device *bdev; struct ssb_device *sdev; }; @@ -57,6 +61,10 @@ static inline bool b43_bus_host_is_sdio(struct b43_bus_dev *dev) dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO); } +struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core); struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev); +void *b43_bus_get_wldev(struct b43_bus_dev *dev); +void b43_bus_set_wldev(struct b43_bus_dev *dev, void *data); + #endif /* B43_BUS_H_ */ diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index d02cf8300e3e..ce572aebeffd 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1055,7 +1055,14 @@ int b43_dma_init(struct b43_wldev *dev) err = b43_dma_set_mask(dev, dmamask); if (err) return err; - dma->translation = ssb_dma_translation(dev->sdev); + + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + dma->translation = ssb_dma_translation(dev->dev->sdev); + break; +#endif + } err = -ENOMEM; /* setup TX DMA channels. */ @@ -1600,6 +1607,7 @@ void b43_dma_rx(struct b43_dmaring *ring) dma_rx(ring, &slot); update_max_used_slots(ring, ++used_slots); } + wmb(); ops->set_current_rxslot(ring, slot); ring->current_slot = slot; } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 834df5a3fb6a..8bcda5084dec 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1155,6 +1155,21 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) } } +#ifdef CONFIG_B43_BCMA +static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode) +{ + u32 flags = 0; + + if (gmode) + flags = B43_BCMA_IOCTL_GMODE; + flags |= B43_BCMA_IOCTL_PHY_CLKEN; + flags |= B43_BCMA_IOCTL_PHY_BW_20MHZ; /* Make 20 MHz def */ + b43_device_enable(dev, flags); + + /* TODO: reset PHY */ +} +#endif + static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, bool gmode) { struct ssb_device *sdev = dev->dev->sdev; @@ -1187,7 +1202,18 @@ void b43_wireless_core_reset(struct b43_wldev *dev, bool gmode) { u32 macctl; - b43_ssb_wireless_core_reset(dev, gmode); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + b43_bcma_wireless_core_reset(dev, gmode); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + b43_ssb_wireless_core_reset(dev, gmode); + break; +#endif + } /* Turn Analog ON, but only if we already know the PHY-type. * This protects against very early setup where we don't know the @@ -1938,7 +1964,7 @@ static irqreturn_t b43_do_interrupt(struct b43_wldev *dev) return IRQ_NONE; reason &= dev->irq_mask; if (!reason) - return IRQ_HANDLED; + return IRQ_NONE; dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) & 0x0001DC00; @@ -2133,21 +2159,43 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) u32 tmshigh; int err; + /* Files for HT and LCN were found by trying one by one */ + /* Get microcode */ - if ((rev >= 5) && (rev <= 10)) + if ((rev >= 5) && (rev <= 10)) { filename = "ucode5"; - else if ((rev >= 11) && (rev <= 12)) + } else if ((rev >= 11) && (rev <= 12)) { filename = "ucode11"; - else if (rev == 13) + } else if (rev == 13) { filename = "ucode13"; - else if (rev == 14) + } else if (rev == 14) { filename = "ucode14"; - else if (rev == 15) + } else if (rev == 15) { filename = "ucode15"; - else if ((rev >= 16) && (rev <= 20)) - filename = "ucode16_mimo"; - else - goto err_no_ucode; + } else { + switch (dev->phy.type) { + case B43_PHYTYPE_N: + if (rev >= 16) + filename = "ucode16_mimo"; + else + goto err_no_ucode; + break; + case B43_PHYTYPE_HT: + if (rev == 29) + filename = "ucode29_mimo"; + else + goto err_no_ucode; + break; + case B43_PHYTYPE_LCN: + if (rev == 24) + filename = "ucode24_mimo"; + else + goto err_no_ucode; + break; + default: + goto err_no_ucode; + } + } err = b43_do_request_fw(ctx, filename, &fw->ucode); if (err) goto err_load; @@ -2206,6 +2254,18 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) else goto err_no_initvals; break; + case B43_PHYTYPE_HT: + if (rev == 29) + filename = "ht0initvals29"; + else + goto err_no_initvals; + break; + case B43_PHYTYPE_LCN: + if (rev == 24) + filename = "lcn0initvals24"; + else + goto err_no_initvals; + break; default: goto err_no_initvals; } @@ -2253,6 +2313,18 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) else goto err_no_initvals; break; + case B43_PHYTYPE_HT: + if (rev == 29) + filename = "ht0bsinitvals29"; + else + goto err_no_initvals; + break; + case B43_PHYTYPE_LCN: + if (rev == 24) + filename = "lcn0bsinitvals24"; + else + goto err_no_initvals; + break; default: goto err_no_initvals; } @@ -2624,11 +2696,24 @@ static int b43_gpio_init(struct b43_wldev *dev) if (dev->dev->core_rev >= 2) mask |= 0x0010; /* FIXME: This is redundant. */ - gpiodev = b43_ssb_gpio_dev(dev); - if (gpiodev) - ssb_write32(gpiodev, B43_GPIO_CONTROL, - (ssb_read32(gpiodev, B43_GPIO_CONTROL) - & mask) | set); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL, + (bcma_cc_read32(&dev->dev->bdev->bus->drv_cc, + BCMA_CC_GPIOCTL) & mask) | set); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + gpiodev = b43_ssb_gpio_dev(dev); + if (gpiodev) + ssb_write32(gpiodev, B43_GPIO_CONTROL, + (ssb_read32(gpiodev, B43_GPIO_CONTROL) + & mask) | set); + break; +#endif + } return 0; } @@ -2638,9 +2723,21 @@ static void b43_gpio_cleanup(struct b43_wldev *dev) { struct ssb_device *gpiodev; - gpiodev = b43_ssb_gpio_dev(dev); - if (gpiodev) - ssb_write32(gpiodev, B43_GPIO_CONTROL, 0); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL, + 0); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + gpiodev = b43_ssb_gpio_dev(dev); + if (gpiodev) + ssb_write32(gpiodev, B43_GPIO_CONTROL, 0); + break; +#endif + } } /* http://bcm-specs.sipsolutions.net/EnableMac */ @@ -2712,12 +2809,30 @@ out: /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on) { - u32 tmslow = ssb_read32(dev->sdev, SSB_TMSLOW); - if (on) - tmslow |= B43_TMSLOW_MACPHYCLKEN; - else - tmslow &= ~B43_TMSLOW_MACPHYCLKEN; - ssb_write32(dev->sdev, SSB_TMSLOW, tmslow); + u32 tmp; + + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + tmp = bcma_read32(dev->dev->bdev, BCMA_IOCTL); + if (on) + tmp |= B43_BCMA_IOCTL_MACPHYCLKEN; + else + tmp &= ~B43_BCMA_IOCTL_MACPHYCLKEN; + bcma_write32(dev->dev->bdev, BCMA_IOCTL, tmp); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); + if (on) + tmp |= B43_TMSLOW_MACPHYCLKEN; + else + tmp &= ~B43_TMSLOW_MACPHYCLKEN; + ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); + break; +#endif + } } static void b43_adjust_opmode(struct b43_wldev *dev) @@ -2956,8 +3071,20 @@ static int b43_chip_init(struct b43_wldev *dev) b43_mac_phy_clock_set(dev, true); - b43_write16(dev, B43_MMIO_POWERUP_DELAY, - dev->sdev->bus->chipco.fast_pwrup_delay); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + /* FIXME: 0xE74 is quite common, but should be read from CC */ + b43_write16(dev, B43_MMIO_POWERUP_DELAY, 0xE74); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + b43_write16(dev, B43_MMIO_POWERUP_DELAY, + dev->dev->sdev->bus->chipco.fast_pwrup_delay); + break; +#endif + } err = 0; b43dbg(dev->wl, "Chip initialized\n"); @@ -3473,21 +3600,33 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) static void b43_put_phy_into_reset(struct b43_wldev *dev) { - struct ssb_device *sdev = dev->sdev; - u32 tmslow; + u32 tmp; - tmslow = ssb_read32(sdev, SSB_TMSLOW); - tmslow &= ~B43_TMSLOW_GMODE; - tmslow |= B43_TMSLOW_PHYRESET; - tmslow |= SSB_TMSLOW_FGC; - ssb_write32(sdev, SSB_TMSLOW, tmslow); - msleep(1); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + b43err(dev->wl, + "Putting PHY into reset not supported on BCMA\n"); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); + tmp &= ~B43_TMSLOW_GMODE; + tmp |= B43_TMSLOW_PHYRESET; + tmp |= SSB_TMSLOW_FGC; + ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); + msleep(1); + + tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); + tmp &= ~SSB_TMSLOW_FGC; + tmp |= B43_TMSLOW_PHYRESET; + ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); + msleep(1); - tmslow = ssb_read32(sdev, SSB_TMSLOW); - tmslow &= ~SSB_TMSLOW_FGC; - tmslow |= B43_TMSLOW_PHYRESET; - ssb_write32(sdev, SSB_TMSLOW, tmslow); - msleep(1); + break; +#endif + } } static const char *band_to_string(enum ieee80211_band band) @@ -4104,6 +4243,12 @@ static int b43_phy_versioning(struct b43_wldev *dev) unsupported = 1; break; #endif +#ifdef CONFIG_B43_PHY_LCN + case B43_PHYTYPE_LCN: + if (phy_rev > 1) + unsupported = 1; + break; +#endif default: unsupported = 1; }; @@ -4117,22 +4262,42 @@ static int b43_phy_versioning(struct b43_wldev *dev) analog_type, phy_type, phy_rev); /* Get RADIO versioning */ - if (dev->dev->chip_id == 0x4317) { - if (dev->dev->chip_rev == 0) - tmp = 0x3205017F; - else if (dev->dev->chip_rev == 1) - tmp = 0x4205017F; - else - tmp = 0x5205017F; + if (dev->dev->core_rev >= 24) { + u16 radio24[3]; + + for (tmp = 0; tmp < 3; tmp++) { + b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp); + radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA); + } + + /* Broadcom uses "id" for our "ver" and has separated "ver" */ + /* radio_ver = (radio24[0] & 0xF0) >> 4; */ + + radio_manuf = 0x17F; + radio_ver = (radio24[2] << 8) | radio24[1]; + radio_rev = (radio24[0] & 0xF); } else { - b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); - tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); - b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); - tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16; - } - radio_manuf = (tmp & 0x00000FFF); - radio_ver = (tmp & 0x0FFFF000) >> 12; - radio_rev = (tmp & 0xF0000000) >> 28; + if (dev->dev->chip_id == 0x4317) { + if (dev->dev->chip_rev == 0) + tmp = 0x3205017F; + else if (dev->dev->chip_rev == 1) + tmp = 0x4205017F; + else + tmp = 0x5205017F; + } else { + b43_write16(dev, B43_MMIO_RADIO_CONTROL, + B43_RADIOCTL_ID); + tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); + b43_write16(dev, B43_MMIO_RADIO_CONTROL, + B43_RADIOCTL_ID); + tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) + << 16; + } + radio_manuf = (tmp & 0x00000FFF); + radio_ver = (tmp & 0x0FFFF000) >> 12; + radio_rev = (tmp & 0xF0000000) >> 28; + } + if (radio_manuf != 0x17F /* Broadcom */) unsupported = 1; switch (phy_type) { @@ -4164,6 +4329,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (radio_ver != 0x2059) unsupported = 1; break; + case B43_PHYTYPE_LCN: + if (radio_ver != 0x2064) + unsupported = 1; + break; default: B43_WARN_ON(1); } @@ -4347,7 +4516,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) /* Initialize a wireless core */ static int b43_wireless_core_init(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->sdev->bus; struct ssb_sprom *sprom = dev->dev->bus_sprom; struct b43_phy *phy = &dev->phy; int err; @@ -4366,7 +4534,20 @@ static int b43_wireless_core_init(struct b43_wldev *dev) phy->ops->prepare_structs(dev); /* Enable IRQ routing to this device. */ - ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->sdev); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci, + dev->dev->bdev, true); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + ssb_pcicore_dev_irqvecs_enable(&dev->dev->sdev->bus->pcicore, + dev->dev->sdev); + break; +#endif + } b43_imcfglo_timeouts_workaround(dev); b43_bluetooth_coext_disable(dev); @@ -4397,8 +4578,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev) if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW) hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */ #ifdef CONFIG_SSB_DRIVER_PCICORE - if ((bus->bustype == SSB_BUSTYPE_PCI) && - (bus->pcicore.dev->id.revision <= 10)) + if (dev->dev->bus_type == B43_BUS_SSB && + dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI && + dev->dev->sdev->bus->pcicore.dev->id.revision <= 10) hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */ #endif hf &= ~B43_HF_SKCFPUP; @@ -4764,8 +4946,7 @@ static void b43_wireless_core_detach(struct b43_wldev *dev) static int b43_wireless_core_attach(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; - struct ssb_bus *bus = dev->sdev->bus; - struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL; + struct pci_dev *pdev = NULL; int err; bool have_2ghz_phy = 0, have_5ghz_phy = 0; @@ -4776,20 +4957,38 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) * that in core_init(), too. */ +#ifdef CONFIG_B43_SSB + if (dev->dev->bus_type == B43_BUS_SSB && + dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI) + pdev = dev->dev->sdev->bus->host_pci; +#endif + err = b43_bus_powerup(dev, 0); if (err) { b43err(wl, "Bus powerup failed\n"); goto out; } - /* Get the PHY type. */ - if (dev->dev->core_rev >= 5) { - u32 tmshigh; - tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH); - have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY); - have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY); - } else - B43_WARN_ON(1); + /* Get the PHY type. */ + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + /* FIXME */ + have_2ghz_phy = 1; + have_5ghz_phy = 0; + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + if (dev->dev->core_rev >= 5) { + u32 tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH); + have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY); + have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY); + } else + B43_WARN_ON(1); + break; +#endif + } dev->phy.gmode = have_2ghz_phy; dev->phy.radio_on = 1; @@ -4815,6 +5014,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) #endif case B43_PHYTYPE_G: case B43_PHYTYPE_N: + case B43_PHYTYPE_HT: + case B43_PHYTYPE_LCN: have_2ghz_phy = 1; break; default: @@ -4877,13 +5078,13 @@ static void b43_one_core_detach(struct b43_bus_dev *dev) /* Do not cancel ieee80211-workqueue based work here. * See comment in b43_remove(). */ - wldev = ssb_get_drvdata(dev->sdev); + wldev = b43_bus_get_wldev(dev); wl = wldev->wl; b43_debugfs_remove_device(wldev); b43_wireless_core_detach(wldev); list_del(&wldev->list); wl->nr_devs--; - ssb_set_drvdata(dev->sdev, NULL); + b43_bus_set_wldev(dev, NULL); kfree(wldev); } @@ -4898,7 +5099,6 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl) wldev->use_pio = b43_modparam_pio; wldev->dev = dev; - wldev->sdev = dev->sdev; /* TODO: Remove when not needed */ wldev->wl = wl; b43_set_status(wldev, B43_STAT_UNINIT); wldev->bad_frames_preempt = modparam_bad_frames_preempt; @@ -4910,7 +5110,7 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl) list_add(&wldev->list, &wl->devlist); wl->nr_devs++; - ssb_set_drvdata(dev->sdev, wldev); + b43_bus_set_wldev(dev, wldev); b43_debugfs_add_device(wldev); out: @@ -4959,9 +5159,9 @@ static void b43_wireless_exit(struct b43_bus_dev *dev, struct b43_wl *wl) ieee80211_free_hw(hw); } -static struct b43_wl *b43_wireless_init(struct ssb_device *dev) +static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) { - struct ssb_sprom *sprom = &dev->bus->sprom; + struct ssb_sprom *sprom = dev->bus_sprom; struct ieee80211_hw *hw; struct b43_wl *wl; @@ -5003,14 +5203,21 @@ static struct b43_wl *b43_wireless_init(struct ssb_device *dev) skb_queue_head_init(&wl->tx_queue); b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n", - dev->bus->chip_id, dev->id.revision); + dev->chip_id, dev->core_rev); return wl; } #ifdef CONFIG_B43_BCMA static int b43_bcma_probe(struct bcma_device *core) { + struct b43_bus_dev *dev; + + dev = b43_bus_dev_bcma_init(core); + if (!dev) + return -ENODEV; + b43err(NULL, "BCMA is not supported yet!"); + kfree(dev); return -EOPNOTSUPP; } @@ -5045,7 +5252,7 @@ int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id) /* Probing the first core. Must setup common struct b43_wl */ first = 1; b43_sprom_fixup(sdev->bus); - wl = b43_wireless_init(sdev); + wl = b43_wireless_init(dev); if (IS_ERR(wl)) { err = PTR_ERR(wl); goto out; diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 9705950f059a..101957512bcc 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -32,6 +32,7 @@ #include "phy_n.h" #include "phy_lp.h" #include "phy_ht.h" +#include "phy_lcn.h" #include "b43.h" #include "main.h" @@ -65,6 +66,11 @@ int b43_phy_allocate(struct b43_wldev *dev) phy->ops = &b43_phyops_ht; #endif break; + case B43_PHYTYPE_LCN: +#ifdef CONFIG_B43_PHY_LCN + phy->ops = &b43_phyops_lcn; +#endif + break; } if (B43_WARN_ON(!phy->ops)) return -ENODEV; diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 47dcb800a3c3..aa77ba612a92 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -195,6 +195,7 @@ struct b43_phy_g; struct b43_phy_n; struct b43_phy_lp; struct b43_phy_ht; +struct b43_phy_lcn; struct b43_phy { /* Hardware operation callbacks. */ @@ -219,6 +220,8 @@ struct b43_phy { struct b43_phy_lp *lp; /* HT-PHY specific information */ struct b43_phy_ht *ht; + /* LCN-PHY specific information */ + struct b43_phy_lcn *lcn; }; /* Band support flags. */ diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index 72f01ce8b42c..29821036badf 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -24,9 +24,14 @@ #include "b43.h" #include "phy_ht.h" +#include "tables_phy_ht.h" #include "radio_2059.h" #include "main.h" +/************************************************** + * Radio 2059. + **************************************************/ + static void b43_radio_2059_channel_setup(struct b43_wldev *dev, const struct b43_phy_ht_channeltab_e_radio2059 *e) { @@ -56,7 +61,7 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev, b43_radio_write(dev, 0x98, e->radio_syn98); for (i = 0; i < 2; i++) { - routing = i ? 0x800 : 0x400; + routing = i ? R2059_RXRX1 : R2059_TXRX0; b43_radio_write(dev, routing | 0x4a, e->radio_rxtx4a); b43_radio_write(dev, routing | 0x58, e->radio_rxtx58); b43_radio_write(dev, routing | 0x5a, e->radio_rxtx5a); @@ -78,11 +83,120 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev, udelay(300); } +static void b43_radio_2059_init(struct b43_wldev *dev) +{ + const u16 routing[] = { R2059_SYN, R2059_TXRX0, R2059_RXRX1 }; + const u16 radio_values[3][2] = { + { 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 }, + }; + u16 i, j; + + b43_radio_write(dev, R2059_ALL | 0x51, 0x0070); + b43_radio_write(dev, R2059_ALL | 0x5a, 0x0003); + + for (i = 0; i < ARRAY_SIZE(routing); i++) + b43_radio_set(dev, routing[i] | 0x146, 0x3); + + b43_radio_set(dev, 0x2e, 0x0078); + b43_radio_set(dev, 0xc0, 0x0080); + msleep(2); + b43_radio_mask(dev, 0x2e, ~0x0078); + b43_radio_mask(dev, 0xc0, ~0x0080); + + if (1) { /* FIXME */ + b43_radio_set(dev, R2059_RXRX1 | 0x4, 0x1); + udelay(10); + b43_radio_set(dev, R2059_RXRX1 | 0x0BF, 0x1); + b43_radio_maskset(dev, R2059_RXRX1 | 0x19B, 0x3, 0x2); + + b43_radio_set(dev, R2059_RXRX1 | 0x4, 0x2); + udelay(100); + b43_radio_mask(dev, R2059_RXRX1 | 0x4, ~0x2); + + for (i = 0; i < 10000; i++) { + if (b43_radio_read(dev, R2059_RXRX1 | 0x145) & 1) { + i = 0; + break; + } + udelay(100); + } + if (i) + b43err(dev->wl, "radio 0x945 timeout\n"); + + b43_radio_mask(dev, R2059_RXRX1 | 0x4, ~0x1); + b43_radio_set(dev, 0xa, 0x60); + + for (i = 0; i < 3; i++) { + b43_radio_write(dev, 0x17F, radio_values[i][0]); + b43_radio_write(dev, 0x13D, 0x6E); + b43_radio_write(dev, 0x13E, radio_values[i][1]); + b43_radio_write(dev, 0x13C, 0x55); + + for (j = 0; j < 10000; j++) { + if (b43_radio_read(dev, 0x140) & 2) { + j = 0; + break; + } + udelay(500); + } + if (j) + b43err(dev->wl, "radio 0x140 timeout\n"); + + b43_radio_write(dev, 0x13C, 0x15); + } + + b43_radio_mask(dev, 0x17F, ~0x1); + } + + b43_radio_mask(dev, 0x11, 0x0008); +} + +/************************************************** + * Channel switching ops. + **************************************************/ + static void b43_phy_ht_channel_setup(struct b43_wldev *dev, const struct b43_phy_ht_channeltab_e_phy *e, struct ieee80211_channel *new_channel) { - /* TODO */ + bool old_band_5ghz; + u8 i; + + old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */ + if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) { + /* TODO */ + } else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) { + /* TODO */ + } + + b43_phy_write(dev, B43_PHY_HT_BW1, e->bw1); + b43_phy_write(dev, B43_PHY_HT_BW2, e->bw2); + b43_phy_write(dev, B43_PHY_HT_BW3, e->bw3); + b43_phy_write(dev, B43_PHY_HT_BW4, e->bw4); + b43_phy_write(dev, B43_PHY_HT_BW5, e->bw5); + b43_phy_write(dev, B43_PHY_HT_BW6, e->bw6); + + /* TODO: some ops on PHY regs 0x0B0 and 0xC0A */ + + /* TODO: separated function? */ + for (i = 0; i < 3; i++) { + u16 mask; + u32 tmp = b43_httab_read(dev, B43_HTTAB32(26, 0xE8)); + + if (0) /* FIXME */ + mask = 0x2 << (i * 4); + else + mask = 0; + b43_phy_mask(dev, B43_PHY_EXTG(0x108), mask); + + b43_httab_write(dev, B43_HTTAB16(7, 0x110 + i), tmp >> 16); + b43_httab_write(dev, B43_HTTAB8(13, 0x63 + (i * 4)), + tmp & 0xFF); + b43_httab_write(dev, B43_HTTAB8(13, 0x73 + (i * 4)), + tmp & 0xFF); + } + + b43_phy_write(dev, 0x017e, 0x3830); } static int b43_phy_ht_set_channel(struct b43_wldev *dev, @@ -139,6 +253,13 @@ static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev) memset(phy_ht, 0, sizeof(*phy_ht)); } +static int b43_phy_ht_op_init(struct b43_wldev *dev) +{ + b43_phy_ht_tables_init(dev); + + return 0; +} + static void b43_phy_ht_op_free(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -162,6 +283,11 @@ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev, b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, ~0, 0x1); b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, ~0); b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, ~0, 0x2); + + if (dev->phy.radio_ver == 0x2059) + b43_radio_2059_init(dev); + else + B43_WARN_ON(1); } } @@ -247,6 +373,16 @@ static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg, b43_write16(dev, B43_MMIO_RADIO24_DATA, value); } +static enum b43_txpwr_result +b43_phy_ht_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi) +{ + return B43_TXPWR_RES_DONE; +} + +static void b43_phy_ht_op_adjust_txpower(struct b43_wldev *dev) +{ +} + /************************************************** * PHY ops struct. **************************************************/ @@ -255,9 +391,7 @@ const struct b43_phy_operations b43_phyops_ht = { .allocate = b43_phy_ht_op_allocate, .free = b43_phy_ht_op_free, .prepare_structs = b43_phy_ht_op_prepare_structs, - /* .init = b43_phy_ht_op_init, - */ .phy_read = b43_phy_ht_op_read, .phy_write = b43_phy_ht_op_write, .phy_maskset = b43_phy_ht_op_maskset, @@ -267,8 +401,6 @@ const struct b43_phy_operations b43_phyops_ht = { .switch_analog = b43_phy_ht_op_switch_analog, .switch_channel = b43_phy_ht_op_switch_channel, .get_default_chan = b43_phy_ht_op_get_default_chan, - /* .recalc_txpower = b43_phy_ht_op_recalc_txpower, .adjust_txpower = b43_phy_ht_op_adjust_txpower, - */ }; diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h index afa448d6571e..7ad7affc8df0 100644 --- a/drivers/net/wireless/b43/phy_ht.h +++ b/drivers/net/wireless/b43/phy_ht.h @@ -4,9 +4,16 @@ #include "phy_common.h" +#define B43_PHY_HT_BANDCTL 0x009 /* Band control */ #define B43_PHY_HT_TABLE_ADDR 0x072 /* Table address */ #define B43_PHY_HT_TABLE_DATALO 0x073 /* Table data low */ #define B43_PHY_HT_TABLE_DATAHI 0x074 /* Table data high */ +#define B43_PHY_HT_BW1 0x1CE +#define B43_PHY_HT_BW2 0x1CF +#define B43_PHY_HT_BW3 0x1D0 +#define B43_PHY_HT_BW4 0x1D1 +#define B43_PHY_HT_BW5 0x1D2 +#define B43_PHY_HT_BW6 0x1D3 #define B43_PHY_HT_RF_CTL1 B43_PHY_EXTG(0x010) @@ -20,7 +27,12 @@ /* Values for PHY registers used on channel switching */ struct b43_phy_ht_channeltab_e_phy { - /* TODO */ + u16 bw1; + u16 bw2; + u16 bw3; + u16 bw4; + u16 bw5; + u16 bw6; }; diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c new file mode 100644 index 000000000000..9f7dbbd5ced6 --- /dev/null +++ b/drivers/net/wireless/b43/phy_lcn.c @@ -0,0 +1,52 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n LCN-PHY support + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include <linux/slab.h> + +#include "b43.h" +#include "phy_lcn.h" +#include "tables_phy_lcn.h" +#include "main.h" + +/************************************************** + * PHY ops struct. + **************************************************/ + +const struct b43_phy_operations b43_phyops_lcn = { + /* + .allocate = b43_phy_lcn_op_allocate, + .free = b43_phy_lcn_op_free, + .prepare_structs = b43_phy_lcn_op_prepare_structs, + .init = b43_phy_lcn_op_init, + .phy_read = b43_phy_lcn_op_read, + .phy_write = b43_phy_lcn_op_write, + .phy_maskset = b43_phy_lcn_op_maskset, + .radio_read = b43_phy_lcn_op_radio_read, + .radio_write = b43_phy_lcn_op_radio_write, + .software_rfkill = b43_phy_lcn_op_software_rfkill, + .switch_analog = b43_phy_lcn_op_switch_analog, + .switch_channel = b43_phy_lcn_op_switch_channel, + .get_default_chan = b43_phy_lcn_op_get_default_chan, + .recalc_txpower = b43_phy_lcn_op_recalc_txpower, + .adjust_txpower = b43_phy_lcn_op_adjust_txpower, + */ +}; diff --git a/drivers/net/wireless/b43/phy_lcn.h b/drivers/net/wireless/b43/phy_lcn.h new file mode 100644 index 000000000000..c046c2a6cab4 --- /dev/null +++ b/drivers/net/wireless/b43/phy_lcn.h @@ -0,0 +1,14 @@ +#ifndef B43_PHY_LCN_H_ +#define B43_PHY_LCN_H_ + +#include "phy_common.h" + + +struct b43_phy_lcn { +}; + + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_lcn; + +#endif /* B43_PHY_LCN_H_ */
\ No newline at end of file diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index e7dfdac9e4d7..95c28f584ed9 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -603,17 +603,33 @@ static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force) { - u32 tmslow; + u32 tmp; if (dev->phy.type != B43_PHYTYPE_N) return; - tmslow = ssb_read32(dev->sdev, SSB_TMSLOW); - if (force) - tmslow |= SSB_TMSLOW_FGC; - else - tmslow &= ~SSB_TMSLOW_FGC; - ssb_write32(dev->sdev, SSB_TMSLOW, tmslow); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + tmp = bcma_read32(dev->dev->bdev, BCMA_IOCTL); + if (force) + tmp |= BCMA_IOCTL_FGC; + else + tmp &= ~BCMA_IOCTL_FGC; + bcma_write32(dev->dev->bdev, BCMA_IOCTL, tmp); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); + if (force) + tmp |= SSB_TMSLOW_FGC; + else + tmp &= ~SSB_TMSLOW_FGC; + ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); + break; +#endif + } } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */ @@ -958,8 +974,21 @@ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init) b43_phy_write(dev, B43_NPHY_GPIO_LOOEN, 0); b43_phy_write(dev, B43_NPHY_GPIO_HIOEN, 0); - ssb_chipco_gpio_control(&dev->sdev->bus->chipco, 0xFC00, - 0xFC00); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, + 0xFC00, 0xFC00); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + ssb_chipco_gpio_control(&dev->dev->sdev->bus->chipco, + 0xFC00, 0xFC00); + break; +#endif + } + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) & ~B43_MACCTL_GPOUTSMSK); @@ -3600,7 +3629,20 @@ int b43_phy_initn(struct b43_wldev *dev) if ((dev->phy.rev >= 3) && (sprom->boardflags_lo & B43_BFL_EXTLNA) && (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) { - chipco_set32(&dev->sdev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40); + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + bcma_cc_set32(&dev->dev->bdev->bus->drv_cc, + BCMA_CC_CHIPCTL, 0x40); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + chipco_set32(&dev->dev->sdev->bus->chipco, + SSB_CHIPCO_CHIPCTL, 0x40); + break; +#endif + } } nphy->deaf_count = 0; b43_nphy_tables_init(dev); diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c index 55d7da74f15a..23dea4ba8219 100644 --- a/drivers/net/wireless/b43/radio_2059.c +++ b/drivers/net/wireless/b43/radio_2059.c @@ -23,6 +23,141 @@ #include "b43.h" #include "radio_2059.h" +#define RADIOREGS(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \ + r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \ + r20, r21, r22, r23, r24, r25, r26, r27, r28) \ + .radio_syn16 = r00, \ + .radio_syn17 = r01, \ + .radio_syn22 = r02, \ + .radio_syn25 = r03, \ + .radio_syn27 = r04, \ + .radio_syn28 = r05, \ + .radio_syn29 = r06, \ + .radio_syn2c = r07, \ + .radio_syn2d = r08, \ + .radio_syn37 = r09, \ + .radio_syn41 = r10, \ + .radio_syn43 = r11, \ + .radio_syn47 = r12, \ + .radio_syn4a = r13, \ + .radio_syn58 = r14, \ + .radio_syn5a = r15, \ + .radio_syn6a = r16, \ + .radio_syn6d = r17, \ + .radio_syn6e = r18, \ + .radio_syn92 = r19, \ + .radio_syn98 = r20, \ + .radio_rxtx4a = r21, \ + .radio_rxtx58 = r22, \ + .radio_rxtx5a = r23, \ + .radio_rxtx6a = r24, \ + .radio_rxtx6d = r25, \ + .radio_rxtx6e = r26, \ + .radio_rxtx92 = r27, \ + .radio_rxtx98 = r28 + +#define PHYREGS(r0, r1, r2, r3, r4, r5) \ + .phy_regs.bw1 = r0, \ + .phy_regs.bw2 = r1, \ + .phy_regs.bw3 = r2, \ + .phy_regs.bw4 = r3, \ + .phy_regs.bw5 = r4, \ + .phy_regs.bw6 = r5 + +static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radio2059[] = { + { .freq = 2412, + RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, + 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { .freq = 2417, + RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, + 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { .freq = 2422, + RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, + 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { .freq = 2427, + RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, + 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { .freq = 2432, + RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, + 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { .freq = 2437, + RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, + 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { .freq = 2442, + RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { .freq = 2447, + RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { .freq = 2452, + RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { .freq = 2457, + RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, + 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { .freq = 2462, + RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, + 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { .freq = 2467, + RADIOREGS(0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, + 0x09, 0x0f, 0x05, 0x00, 0x05, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b), + }, + { .freq = 2472, + RADIOREGS(0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, + 0x09, 0x0f, 0x05, 0x00, 0x05, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03, + 0x00, 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), + }, +}; + const struct b43_phy_ht_channeltab_e_radio2059 *b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq) { diff --git a/drivers/net/wireless/b43/radio_2059.h b/drivers/net/wireless/b43/radio_2059.h index c2874b145266..e4d69e55e9fe 100644 --- a/drivers/net/wireless/b43/radio_2059.h +++ b/drivers/net/wireless/b43/radio_2059.h @@ -5,6 +5,11 @@ #include "phy_ht.h" +#define R2059_SYN 0x000 +#define R2059_TXRX0 0x400 +#define R2059_RXRX1 0x800 +#define R2059_ALL 0xC00 + /* Values for various registers uploaded on channel switching */ struct b43_phy_ht_channeltab_e_radio2059 { /* The channel frequency in MHz */ diff --git a/drivers/net/wireless/b43/tables_phy_ht.c b/drivers/net/wireless/b43/tables_phy_ht.c new file mode 100644 index 000000000000..603938657b15 --- /dev/null +++ b/drivers/net/wireless/b43/tables_phy_ht.c @@ -0,0 +1,750 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n HT-PHY data tables + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "tables_phy_ht.h" +#include "phy_common.h" +#include "phy_ht.h" + +static const u16 b43_httab_0x12[] = { + 0x0000, 0x0008, 0x000a, 0x0010, 0x0012, 0x0019, + 0x001a, 0x001c, 0x0080, 0x0088, 0x008a, 0x0090, + 0x0092, 0x0099, 0x009a, 0x009c, 0x0100, 0x0108, + 0x010a, 0x0110, 0x0112, 0x0119, 0x011a, 0x011c, + 0x0180, 0x0188, 0x018a, 0x0190, 0x0192, 0x0199, + 0x019a, 0x019c, 0x0000, 0x0098, 0x00a0, 0x00a8, + 0x009a, 0x00a2, 0x00aa, 0x0120, 0x0128, 0x0128, + 0x0130, 0x0138, 0x0138, 0x0140, 0x0122, 0x012a, + 0x012a, 0x0132, 0x013a, 0x013a, 0x0142, 0x01a8, + 0x01b0, 0x01b8, 0x01b0, 0x01b8, 0x01c0, 0x01c8, + 0x01c0, 0x01c8, 0x01d0, 0x01d0, 0x01d8, 0x01aa, + 0x01b2, 0x01ba, 0x01b2, 0x01ba, 0x01c2, 0x01ca, + 0x01c2, 0x01ca, 0x01d2, 0x01d2, 0x01da, 0x0001, + 0x0002, 0x0004, 0x0009, 0x000c, 0x0011, 0x0014, + 0x0018, 0x0020, 0x0021, 0x0022, 0x0024, 0x0081, + 0x0082, 0x0084, 0x0089, 0x008c, 0x0091, 0x0094, + 0x0098, 0x00a0, 0x00a1, 0x00a2, 0x00a4, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, +}; + +static const u16 b43_httab_0x27[] = { + 0x0009, 0x000e, 0x0011, 0x0014, 0x0017, 0x001a, + 0x001d, 0x0020, 0x0009, 0x000e, 0x0011, 0x0014, + 0x0017, 0x001a, 0x001d, 0x0020, 0x0009, 0x000e, + 0x0011, 0x0014, 0x0017, 0x001a, 0x001d, 0x0020, + 0x0009, 0x000e, 0x0011, 0x0014, 0x0017, 0x001a, + 0x001d, 0x0020, +}; + +static const u16 b43_httab_0x26[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, +}; + +static const u32 b43_httab_0x25[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u32 b43_httab_0x2f[] = { + 0x00035700, 0x0002cc9a, 0x00026666, 0x0001581f, + 0x0001581f, 0x0001581f, 0x0001581f, 0x0001581f, + 0x0001581f, 0x0001581f, 0x0001581f, 0x00035700, + 0x0002cc9a, 0x00026666, 0x0001581f, 0x0001581f, + 0x0001581f, 0x0001581f, 0x0001581f, 0x0001581f, + 0x0001581f, 0x0001581f, +}; + +static const u16 b43_httab_0x1a[] = { + 0x0055, 0x0054, 0x0054, 0x0053, 0x0052, 0x0052, + 0x0051, 0x0051, 0x0050, 0x004f, 0x004f, 0x004e, + 0x004e, 0x004d, 0x004c, 0x004c, 0x004b, 0x004a, + 0x0049, 0x0049, 0x0048, 0x0047, 0x0046, 0x0046, + 0x0045, 0x0044, 0x0043, 0x0042, 0x0041, 0x0040, + 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003a, + 0x0039, 0x0038, 0x0037, 0x0036, 0x0035, 0x0033, + 0x0032, 0x0031, 0x002f, 0x002e, 0x002c, 0x002b, + 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, 0x001f, + 0x001d, 0x001a, 0x0018, 0x0015, 0x0012, 0x000e, + 0x000b, 0x0007, 0x0002, 0x00fd, +}; + +static const u16 b43_httab_0x1b[] = { + 0x0055, 0x0054, 0x0054, 0x0053, 0x0052, 0x0052, + 0x0051, 0x0051, 0x0050, 0x004f, 0x004f, 0x004e, + 0x004e, 0x004d, 0x004c, 0x004c, 0x004b, 0x004a, + 0x0049, 0x0049, 0x0048, 0x0047, 0x0046, 0x0046, + 0x0045, 0x0044, 0x0043, 0x0042, 0x0041, 0x0040, + 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003a, + 0x0039, 0x0038, 0x0037, 0x0036, 0x0035, 0x0033, + 0x0032, 0x0031, 0x002f, 0x002e, 0x002c, 0x002b, + 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, 0x001f, + 0x001d, 0x001a, 0x0018, 0x0015, 0x0012, 0x000e, + 0x000b, 0x0007, 0x0002, 0x00fd, +}; + +static const u16 b43_httab_0x1c[] = { + 0x0055, 0x0054, 0x0054, 0x0053, 0x0052, 0x0052, + 0x0051, 0x0051, 0x0050, 0x004f, 0x004f, 0x004e, + 0x004e, 0x004d, 0x004c, 0x004c, 0x004b, 0x004a, + 0x0049, 0x0049, 0x0048, 0x0047, 0x0046, 0x0046, + 0x0045, 0x0044, 0x0043, 0x0042, 0x0041, 0x0040, + 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003a, + 0x0039, 0x0038, 0x0037, 0x0036, 0x0035, 0x0033, + 0x0032, 0x0031, 0x002f, 0x002e, 0x002c, 0x002b, + 0x0029, 0x0027, 0x0025, 0x0023, 0x0021, 0x001f, + 0x001d, 0x001a, 0x0018, 0x0015, 0x0012, 0x000e, + 0x000b, 0x0007, 0x0002, 0x00fd, +}; + +static const u32 b43_httab_0x1a_0xc0[] = { + 0x5bf70044, 0x5bf70042, 0x5bf70040, 0x5bf7003e, + 0x5bf7003c, 0x5bf7003b, 0x5bf70039, 0x5bf70037, + 0x5bf70036, 0x5bf70034, 0x5bf70033, 0x5bf70031, + 0x5bf70030, 0x5ba70044, 0x5ba70042, 0x5ba70040, + 0x5ba7003e, 0x5ba7003c, 0x5ba7003b, 0x5ba70039, + 0x5ba70037, 0x5ba70036, 0x5ba70034, 0x5ba70033, + 0x5b770044, 0x5b770042, 0x5b770040, 0x5b77003e, + 0x5b77003c, 0x5b77003b, 0x5b770039, 0x5b770037, + 0x5b770036, 0x5b770034, 0x5b770033, 0x5b770031, + 0x5b770030, 0x5b77002f, 0x5b77002d, 0x5b77002c, + 0x5b470044, 0x5b470042, 0x5b470040, 0x5b47003e, + 0x5b47003c, 0x5b47003b, 0x5b470039, 0x5b470037, + 0x5b470036, 0x5b470034, 0x5b470033, 0x5b470031, + 0x5b470030, 0x5b47002f, 0x5b47002d, 0x5b47002c, + 0x5b47002b, 0x5b47002a, 0x5b270044, 0x5b270042, + 0x5b270040, 0x5b27003e, 0x5b27003c, 0x5b27003b, + 0x5b270039, 0x5b270037, 0x5b270036, 0x5b270034, + 0x5b270033, 0x5b270031, 0x5b270030, 0x5b27002f, + 0x5b170044, 0x5b170042, 0x5b170040, 0x5b17003e, + 0x5b17003c, 0x5b17003b, 0x5b170039, 0x5b170037, + 0x5b170036, 0x5b170034, 0x5b170033, 0x5b170031, + 0x5b170030, 0x5b17002f, 0x5b17002d, 0x5b17002c, + 0x5b17002b, 0x5b17002a, 0x5b170028, 0x5b170027, + 0x5b170026, 0x5b170025, 0x5b170024, 0x5b170023, + 0x5b070044, 0x5b070042, 0x5b070040, 0x5b07003e, + 0x5b07003c, 0x5b07003b, 0x5b070039, 0x5b070037, + 0x5b070036, 0x5b070034, 0x5b070033, 0x5b070031, + 0x5b070030, 0x5b07002f, 0x5b07002d, 0x5b07002c, + 0x5b07002b, 0x5b07002a, 0x5b070028, 0x5b070027, + 0x5b070026, 0x5b070025, 0x5b070024, 0x5b070023, + 0x5b070022, 0x5b070021, 0x5b070020, 0x5b07001f, + 0x5b07001e, 0x5b07001d, 0x5b07001d, 0x5b07001c, +}; + +static const u32 b43_httab_0x1a_0x140[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u32 b43_httab_0x1b_0x140[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u32 b43_httab_0x1c_0x140[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u16 b43_httab_0x1a_0x1c0[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, +}; + +static const u16 b43_httab_0x1b_0x1c0[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, +}; + +static const u16 b43_httab_0x1c_0x1c0[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, +}; + +static const u16 b43_httab_0x1a_0x240[] = { + 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, + 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, + 0x0036, 0x002a, 0x002a, 0x002a, 0x002a, 0x002a, + 0x002a, 0x002a, 0x002a, 0x002a, 0x002a, 0x002a, + 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, + 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, + 0x001e, 0x001e, 0x001e, 0x001e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x01fc, 0x01fc, + 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, + 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, +}; + +static const u16 b43_httab_0x1b_0x240[] = { + 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, + 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, + 0x0036, 0x002a, 0x002a, 0x002a, 0x002a, 0x002a, + 0x002a, 0x002a, 0x002a, 0x002a, 0x002a, 0x002a, + 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, + 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, + 0x001e, 0x001e, 0x001e, 0x001e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x01fc, 0x01fc, + 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, + 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, +}; + +static const u16 b43_httab_0x1c_0x240[] = { + 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, + 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, 0x0036, + 0x0036, 0x002a, 0x002a, 0x002a, 0x002a, 0x002a, + 0x002a, 0x002a, 0x002a, 0x002a, 0x002a, 0x002a, + 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, + 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, 0x001e, + 0x001e, 0x001e, 0x001e, 0x001e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x01fc, 0x01fc, + 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, + 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, 0x01fc, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, 0x01ee, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, 0x01d6, + 0x01d6, 0x01d6, +}; + +static const u32 b43_httab_0x1f[] = { + 0x00000000, 0x00000000, 0x00016023, 0x00006028, + 0x00034036, 0x0003402e, 0x0007203c, 0x0006e037, + 0x00070030, 0x0009401f, 0x0009a00f, 0x000b600d, + 0x000c8007, 0x000ce007, 0x00101fff, 0x00121ff9, + 0x0012e004, 0x0014dffc, 0x0016dff6, 0x0018dfe9, + 0x001b3fe5, 0x001c5fd0, 0x001ddfc2, 0x001f1fb6, + 0x00207fa4, 0x00219f8f, 0x0022ff7d, 0x00247f6c, + 0x0024df5b, 0x00267f4b, 0x0027df3b, 0x0029bf3b, + 0x002b5f2f, 0x002d3f2e, 0x002f5f2a, 0x002fff15, + 0x00315f0b, 0x0032defa, 0x0033beeb, 0x0034fed9, + 0x00353ec5, 0x00361eb0, 0x00363e9b, 0x0036be87, + 0x0036be70, 0x0038fe67, 0x0044beb2, 0x00513ef3, + 0x00595f11, 0x00669f3d, 0x0078dfdf, 0x00a143aa, + 0x01642fff, 0x0162afff, 0x01620fff, 0x0160cfff, + 0x015f0fff, 0x015dafff, 0x015bcfff, 0x015bcfff, + 0x015b4fff, 0x015acfff, 0x01590fff, 0x0156cfff, +}; + +static const u32 b43_httab_0x21[] = { + 0x00000000, 0x00000000, 0x00016023, 0x00006028, + 0x00034036, 0x0003402e, 0x0007203c, 0x0006e037, + 0x00070030, 0x0009401f, 0x0009a00f, 0x000b600d, + 0x000c8007, 0x000ce007, 0x00101fff, 0x00121ff9, + 0x0012e004, 0x0014dffc, 0x0016dff6, 0x0018dfe9, + 0x001b3fe5, 0x001c5fd0, 0x001ddfc2, 0x001f1fb6, + 0x00207fa4, 0x00219f8f, 0x0022ff7d, 0x00247f6c, + 0x0024df5b, 0x00267f4b, 0x0027df3b, 0x0029bf3b, + 0x002b5f2f, 0x002d3f2e, 0x002f5f2a, 0x002fff15, + 0x00315f0b, 0x0032defa, 0x0033beeb, 0x0034fed9, + 0x00353ec5, 0x00361eb0, 0x00363e9b, 0x0036be87, + 0x0036be70, 0x0038fe67, 0x0044beb2, 0x00513ef3, + 0x00595f11, 0x00669f3d, 0x0078dfdf, 0x00a143aa, + 0x01642fff, 0x0162afff, 0x01620fff, 0x0160cfff, + 0x015f0fff, 0x015dafff, 0x015bcfff, 0x015bcfff, + 0x015b4fff, 0x015acfff, 0x01590fff, 0x0156cfff, +}; + +static const u32 b43_httab_0x23[] = { + 0x00000000, 0x00000000, 0x00016023, 0x00006028, + 0x00034036, 0x0003402e, 0x0007203c, 0x0006e037, + 0x00070030, 0x0009401f, 0x0009a00f, 0x000b600d, + 0x000c8007, 0x000ce007, 0x00101fff, 0x00121ff9, + 0x0012e004, 0x0014dffc, 0x0016dff6, 0x0018dfe9, + 0x001b3fe5, 0x001c5fd0, 0x001ddfc2, 0x001f1fb6, + 0x00207fa4, 0x00219f8f, 0x0022ff7d, 0x00247f6c, + 0x0024df5b, 0x00267f4b, 0x0027df3b, 0x0029bf3b, + 0x002b5f2f, 0x002d3f2e, 0x002f5f2a, 0x002fff15, + 0x00315f0b, 0x0032defa, 0x0033beeb, 0x0034fed9, + 0x00353ec5, 0x00361eb0, 0x00363e9b, 0x0036be87, + 0x0036be70, 0x0038fe67, 0x0044beb2, 0x00513ef3, + 0x00595f11, 0x00669f3d, 0x0078dfdf, 0x00a143aa, + 0x01642fff, 0x0162afff, 0x01620fff, 0x0160cfff, + 0x015f0fff, 0x015dafff, 0x015bcfff, 0x015bcfff, + 0x015b4fff, 0x015acfff, 0x01590fff, 0x0156cfff, +}; + +static const u32 b43_httab_0x20[] = { + 0x0b5e002d, 0x0ae2002f, 0x0a3b0032, 0x09a70035, + 0x09220038, 0x08ab003b, 0x081f003f, 0x07a20043, + 0x07340047, 0x06d2004b, 0x067a004f, 0x06170054, + 0x05bf0059, 0x0571005e, 0x051e0064, 0x04d3006a, + 0x04910070, 0x044c0077, 0x040f007e, 0x03d90085, + 0x03a1008d, 0x036f0095, 0x033d009e, 0x030b00a8, + 0x02e000b2, 0x02b900bc, 0x029200c7, 0x026d00d3, + 0x024900e0, 0x022900ed, 0x020a00fb, 0x01ec010a, + 0x01d20119, 0x01b7012a, 0x019e013c, 0x0188014e, + 0x01720162, 0x015d0177, 0x0149018e, 0x013701a5, + 0x012601be, 0x011501d8, 0x010601f4, 0x00f70212, + 0x00e90231, 0x00dc0253, 0x00d00276, 0x00c4029b, + 0x00b902c3, 0x00af02ed, 0x00a50319, 0x009c0348, + 0x0093037a, 0x008b03af, 0x008303e6, 0x007c0422, + 0x00750460, 0x006e04a3, 0x006804e9, 0x00620533, + 0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c, +}; + +static const u32 b43_httab_0x22[] = { + 0x0b5e002d, 0x0ae2002f, 0x0a3b0032, 0x09a70035, + 0x09220038, 0x08ab003b, 0x081f003f, 0x07a20043, + 0x07340047, 0x06d2004b, 0x067a004f, 0x06170054, + 0x05bf0059, 0x0571005e, 0x051e0064, 0x04d3006a, + 0x04910070, 0x044c0077, 0x040f007e, 0x03d90085, + 0x03a1008d, 0x036f0095, 0x033d009e, 0x030b00a8, + 0x02e000b2, 0x02b900bc, 0x029200c7, 0x026d00d3, + 0x024900e0, 0x022900ed, 0x020a00fb, 0x01ec010a, + 0x01d20119, 0x01b7012a, 0x019e013c, 0x0188014e, + 0x01720162, 0x015d0177, 0x0149018e, 0x013701a5, + 0x012601be, 0x011501d8, 0x010601f4, 0x00f70212, + 0x00e90231, 0x00dc0253, 0x00d00276, 0x00c4029b, + 0x00b902c3, 0x00af02ed, 0x00a50319, 0x009c0348, + 0x0093037a, 0x008b03af, 0x008303e6, 0x007c0422, + 0x00750460, 0x006e04a3, 0x006804e9, 0x00620533, + 0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c, +}; + +static const u32 b43_httab_0x24[] = { + 0x0b5e002d, 0x0ae2002f, 0x0a3b0032, 0x09a70035, + 0x09220038, 0x08ab003b, 0x081f003f, 0x07a20043, + 0x07340047, 0x06d2004b, 0x067a004f, 0x06170054, + 0x05bf0059, 0x0571005e, 0x051e0064, 0x04d3006a, + 0x04910070, 0x044c0077, 0x040f007e, 0x03d90085, + 0x03a1008d, 0x036f0095, 0x033d009e, 0x030b00a8, + 0x02e000b2, 0x02b900bc, 0x029200c7, 0x026d00d3, + 0x024900e0, 0x022900ed, 0x020a00fb, 0x01ec010a, + 0x01d20119, 0x01b7012a, 0x019e013c, 0x0188014e, + 0x01720162, 0x015d0177, 0x0149018e, 0x013701a5, + 0x012601be, 0x011501d8, 0x010601f4, 0x00f70212, + 0x00e90231, 0x00dc0253, 0x00d00276, 0x00c4029b, + 0x00b902c3, 0x00af02ed, 0x00a50319, 0x009c0348, + 0x0093037a, 0x008b03af, 0x008303e6, 0x007c0422, + 0x00750460, 0x006e04a3, 0x006804e9, 0x00620533, + 0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c, +}; + +/************************************************** + * R/W ops. + **************************************************/ + +u32 b43_httab_read(struct b43_wldev *dev, u32 offset) +{ + u32 type, value; + + type = offset & B43_HTTAB_TYPEMASK; + offset &= ~B43_HTTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + switch (type) { + case B43_HTTAB_8BIT: + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + value = b43_phy_read(dev, B43_PHY_HT_TABLE_DATALO) & 0xFF; + break; + case B43_HTTAB_16BIT: + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + value = b43_phy_read(dev, B43_PHY_HT_TABLE_DATALO); + break; + case B43_HTTAB_32BIT: + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + value = b43_phy_read(dev, B43_PHY_HT_TABLE_DATAHI); + value <<= 16; + value |= b43_phy_read(dev, B43_PHY_HT_TABLE_DATALO); + break; + default: + B43_WARN_ON(1); + value = 0; + } + + return value; +} + +void b43_httab_read_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, void *_data) +{ + u32 type; + u8 *data = _data; + unsigned int i; + + type = offset & B43_HTTAB_TYPEMASK; + offset &= ~B43_HTTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + + for (i = 0; i < nr_elements; i++) { + switch (type) { + case B43_HTTAB_8BIT: + *data = b43_phy_read(dev, B43_PHY_HT_TABLE_DATALO) & 0xFF; + data++; + break; + case B43_HTTAB_16BIT: + *((u16 *)data) = b43_phy_read(dev, B43_PHY_HT_TABLE_DATALO); + data += 2; + break; + case B43_HTTAB_32BIT: + *((u32 *)data) = b43_phy_read(dev, B43_PHY_HT_TABLE_DATAHI); + *((u32 *)data) <<= 16; + *((u32 *)data) |= b43_phy_read(dev, B43_PHY_HT_TABLE_DATALO); + data += 4; + break; + default: + B43_WARN_ON(1); + } + } +} + +void b43_httab_write(struct b43_wldev *dev, u32 offset, u32 value) +{ + u32 type; + + type = offset & B43_HTTAB_TYPEMASK; + offset &= 0xFFFF; + + switch (type) { + case B43_HTTAB_8BIT: + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value); + break; + case B43_HTTAB_16BIT: + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value); + break; + case B43_HTTAB_32BIT: + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATAHI, value >> 16); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value & 0xFFFF); + break; + default: + B43_WARN_ON(1); + } + + return; +} + +void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, const void *_data) +{ + u32 type, value; + const u8 *data = _data; + unsigned int i; + + type = offset & B43_HTTAB_TYPEMASK; + offset &= ~B43_HTTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + + for (i = 0; i < nr_elements; i++) { + switch (type) { + case B43_HTTAB_8BIT: + value = *data; + data++; + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value); + break; + case B43_HTTAB_16BIT: + value = *((u16 *)data); + data += 2; + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value); + break; + case B43_HTTAB_32BIT: + value = *((u32 *)data); + data += 4; + b43_phy_write(dev, B43_PHY_HT_TABLE_DATAHI, value >> 16); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, + value & 0xFFFF); + break; + default: + B43_WARN_ON(1); + } + } +} + +/************************************************** + * Tables ops. + **************************************************/ + +#define httab_upload(dev, offset, data) do { \ + b43_httab_write_bulk(dev, offset, ARRAY_SIZE(data), data); \ + } while (0) +void b43_phy_ht_tables_init(struct b43_wldev *dev) +{ + httab_upload(dev, B43_HTTAB16(0x12, 0), b43_httab_0x12); + httab_upload(dev, B43_HTTAB16(0x27, 0), b43_httab_0x27); + httab_upload(dev, B43_HTTAB16(0x26, 0), b43_httab_0x26); + httab_upload(dev, B43_HTTAB32(0x25, 0), b43_httab_0x25); + httab_upload(dev, B43_HTTAB32(0x2f, 0), b43_httab_0x2f); + httab_upload(dev, B43_HTTAB16(0x1a, 0), b43_httab_0x1a); + httab_upload(dev, B43_HTTAB16(0x1b, 0), b43_httab_0x1b); + httab_upload(dev, B43_HTTAB16(0x1c, 0), b43_httab_0x1c); + httab_upload(dev, B43_HTTAB32(0x1a, 0x0c0), b43_httab_0x1a_0xc0); + httab_upload(dev, B43_HTTAB32(0x1a, 0x140), b43_httab_0x1a_0x140); + httab_upload(dev, B43_HTTAB32(0x1b, 0x140), b43_httab_0x1b_0x140); + httab_upload(dev, B43_HTTAB32(0x1c, 0x140), b43_httab_0x1c_0x140); + httab_upload(dev, B43_HTTAB16(0x1a, 0x1c0), b43_httab_0x1a_0x1c0); + httab_upload(dev, B43_HTTAB16(0x1b, 0x1c0), b43_httab_0x1b_0x1c0); + httab_upload(dev, B43_HTTAB16(0x1c, 0x1c0), b43_httab_0x1c_0x1c0); + httab_upload(dev, B43_HTTAB16(0x1a, 0x240), b43_httab_0x1a_0x240); + httab_upload(dev, B43_HTTAB16(0x1b, 0x240), b43_httab_0x1b_0x240); + httab_upload(dev, B43_HTTAB16(0x1c, 0x240), b43_httab_0x1c_0x240); + httab_upload(dev, B43_HTTAB32(0x1f, 0), b43_httab_0x1f); + httab_upload(dev, B43_HTTAB32(0x21, 0), b43_httab_0x21); + httab_upload(dev, B43_HTTAB32(0x23, 0), b43_httab_0x23); + httab_upload(dev, B43_HTTAB32(0x20, 0), b43_httab_0x20); + httab_upload(dev, B43_HTTAB32(0x22, 0), b43_httab_0x22); + httab_upload(dev, B43_HTTAB32(0x24, 0), b43_httab_0x24); +} diff --git a/drivers/net/wireless/b43/tables_phy_ht.h b/drivers/net/wireless/b43/tables_phy_ht.h new file mode 100644 index 000000000000..ea3be382c894 --- /dev/null +++ b/drivers/net/wireless/b43/tables_phy_ht.h @@ -0,0 +1,22 @@ +#ifndef B43_TABLES_PHY_HT_H_ +#define B43_TABLES_PHY_HT_H_ + +/* The HT-PHY tables. */ +#define B43_HTTAB_TYPEMASK 0xF0000000 +#define B43_HTTAB_8BIT 0x10000000 +#define B43_HTTAB_16BIT 0x20000000 +#define B43_HTTAB_32BIT 0x30000000 +#define B43_HTTAB8(table, offset) (((table) << 10) | (offset) | B43_HTTAB_8BIT) +#define B43_HTTAB16(table, offset) (((table) << 10) | (offset) | B43_HTTAB_16BIT) +#define B43_HTTAB32(table, offset) (((table) << 10) | (offset) | B43_HTTAB_32BIT) + +u32 b43_httab_read(struct b43_wldev *dev, u32 offset); +void b43_httab_read_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, void *_data); +void b43_httab_write(struct b43_wldev *dev, u32 offset, u32 value); +void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, const void *_data); + +void b43_phy_ht_tables_init(struct b43_wldev *dev); + +#endif /* B43_TABLES_PHY_HT_H_ */ diff --git a/drivers/net/wireless/b43/tables_phy_lcn.c b/drivers/net/wireless/b43/tables_phy_lcn.c new file mode 100644 index 000000000000..40c1d0915dd3 --- /dev/null +++ b/drivers/net/wireless/b43/tables_phy_lcn.c @@ -0,0 +1,34 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n LCN-PHY data tables + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "tables_phy_lcn.h" +#include "phy_common.h" +#include "phy_lcn.h" + +/************************************************** + * Tables ops. + **************************************************/ + +void b43_phy_lcn_tables_init(struct b43_wldev *dev) +{ +} diff --git a/drivers/net/wireless/b43/tables_phy_lcn.h b/drivers/net/wireless/b43/tables_phy_lcn.h new file mode 100644 index 000000000000..5e31b15b81ec --- /dev/null +++ b/drivers/net/wireless/b43/tables_phy_lcn.h @@ -0,0 +1,6 @@ +#ifndef B43_TABLES_PHY_LCN_H_ +#define B43_TABLES_PHY_LCN_H_ + +void b43_phy_lcn_tables_init(struct b43_wldev *dev); + +#endif /* B43_TABLES_PHY_LCN_H_ */ diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 488b898418a3..82bcf7595139 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -323,8 +323,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, /* we give the phase1key and iv16 here, the key is stored in * shm. With that the hardware can do phase 2 and encryption. */ - ieee80211_get_tkip_key(info->control.hw_key, skb_frag, - IEEE80211_TKIP_P1_KEY, (u8*)phase1key); + ieee80211_get_tkip_p1k(info->control.hw_key, skb_frag, phase1key); /* phase1key is in host endian. Copy to little-endian txhdr->iv. */ for (i = 0; i < 5; i++) { txhdr->iv[i * 2 + 0] = phase1key[i]; diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 44307753587d..3774dd034746 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -287,7 +287,7 @@ static const char *command_types[] = { "unused", /* HOST_INTERRUPT_COALESCING */ "undefined", "CARD_DISABLE_PHY_OFF", - "MSDU_TX_RATES" "undefined", + "MSDU_TX_RATES", "undefined", "SET_STATION_STAT_BITS", "CLEAR_STATIONS_STAT_BITS", diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index 79ac081832fb..ac4f64de1363 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c @@ -240,8 +240,7 @@ static void iwl4965_tx_cmd_build_hwcrypto(struct iwl_priv *priv, case WLAN_CIPHER_SUITE_TKIP: tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; - ieee80211_get_tkip_key(keyconf, skb_frag, - IEEE80211_TKIP_P2_KEY, tx_cmd->key); + ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n"); break; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index a2de7e991706..84da79376ef8 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -484,7 +484,7 @@ static inline u16 iwl_legacy_pcie_link_ctl(struct iwl_priv *priv) { int pos; u16 pci_lnk_ctl; - pos = pci_find_capability(priv->pci_dev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(priv->pci_dev); pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl); return pci_lnk_ctl; } diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 9a56ce546715..19150398a248 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -14,6 +14,7 @@ iwlagn-objs += iwl-6000.o iwlagn-objs += iwl-1000.o iwlagn-objs += iwl-2000.o iwlagn-objs += iwl-pci.o +iwlagn-objs += iwl-trans.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 2daca80f086f..cf1449df4f0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -34,6 +34,7 @@ #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> +#include <linux/stringify.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -53,10 +54,10 @@ #define IWL100_UCODE_API_MIN 5 #define IWL1000_FW_PRE "iwlwifi-1000-" -#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" +#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode" #define IWL100_FW_PRE "iwlwifi-100-" -#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" +#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode" /* @@ -137,7 +138,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); if (priv->cfg->rx_with_siso_diversity) @@ -196,7 +196,6 @@ static struct iwl_lib_ops iwl1000_lib = { static const struct iwl_ops iwl1000_ops = { .lib = &iwl1000_lib, - .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 1c1330035ca9..a401113c065a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -34,6 +34,7 @@ #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> +#include <linux/stringify.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -49,20 +50,25 @@ #define IWL2030_UCODE_API_MAX 5 #define IWL2000_UCODE_API_MAX 5 #define IWL105_UCODE_API_MAX 5 +#define IWL135_UCODE_API_MAX 5 /* Lowest firmware API version supported */ #define IWL2030_UCODE_API_MIN 5 #define IWL2000_UCODE_API_MIN 5 #define IWL105_UCODE_API_MIN 5 +#define IWL135_UCODE_API_MIN 5 #define IWL2030_FW_PRE "iwlwifi-2030-" -#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" +#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode" #define IWL2000_FW_PRE "iwlwifi-2000-" -#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" +#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode" #define IWL105_FW_PRE "iwlwifi-105-" -#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE #api ".ucode" +#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode" + +#define IWL135_FW_PRE "iwlwifi-135-" +#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE #api ".ucode" static void iwl2000_set_ct_threshold(struct iwl_priv *priv) { @@ -130,7 +136,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); if (priv->cfg->rx_with_siso_diversity) @@ -192,25 +197,21 @@ static struct iwl_lib_ops iwl2000_lib = { static const struct iwl_ops iwl2000_ops = { .lib = &iwl2000_lib, - .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, }; static const struct iwl_ops iwl2030_ops = { .lib = &iwl2000_lib, - .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, }; static const struct iwl_ops iwl105_ops = { .lib = &iwl2000_lib, - .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, }; static const struct iwl_ops iwl135_ops = { .lib = &iwl2000_lib, - .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, }; @@ -343,9 +344,9 @@ struct iwl_cfg iwl105_bgn_cfg = { }; #define IWL_DEVICE_135 \ - .fw_name_pre = IWL105_FW_PRE, \ - .ucode_api_max = IWL105_UCODE_API_MAX, \ - .ucode_api_min = IWL105_UCODE_API_MIN, \ + .fw_name_pre = IWL135_FW_PRE, \ + .ucode_api_max = IWL135_UCODE_API_MAX, \ + .ucode_api_min = IWL135_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .ops = &iwl135_ops, \ @@ -358,12 +359,12 @@ struct iwl_cfg iwl105_bgn_cfg = { .rx_with_siso_diversity = true \ struct iwl_cfg iwl135_bg_cfg = { - .name = "105 Series 1x1 BG/BT", + .name = "135 Series 1x1 BG/BT", IWL_DEVICE_135, }; struct iwl_cfg iwl135_bgn_cfg = { - .name = "105 Series 1x1 BGN/BT", + .name = "135 Series 1x1 BGN/BT", IWL_DEVICE_135, .ht_params = &iwl2000_ht_params, }; @@ -371,3 +372,4 @@ struct iwl_cfg iwl135_bgn_cfg = { MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX)); MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 937a8f12afa7..c55cec853f50 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -35,6 +35,7 @@ #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> +#include <linux/stringify.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -55,10 +56,10 @@ #define IWL5150_UCODE_API_MIN 1 #define IWL5000_FW_PRE "iwlwifi-5000-" -#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" +#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode" #define IWL5150_FW_PRE "iwlwifi-5150-" -#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" +#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode" /* NIC configuration for 5000 series */ static void iwl5000_nic_config(struct iwl_priv *priv) @@ -168,7 +169,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); @@ -213,7 +213,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); @@ -378,13 +377,11 @@ static struct iwl_lib_ops iwl5150_lib = { static const struct iwl_ops iwl5000_ops = { .lib = &iwl5000_lib, - .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, }; static const struct iwl_ops iwl5150_ops = { .lib = &iwl5150_lib, - .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 3fcc0925d542..965d010794b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -34,6 +34,7 @@ #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> +#include <linux/stringify.h> #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -56,16 +57,16 @@ #define IWL6000G2_UCODE_API_MIN 4 #define IWL6000_FW_PRE "iwlwifi-6000-" -#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" +#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode" #define IWL6050_FW_PRE "iwlwifi-6050-" -#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" +#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode" #define IWL6005_FW_PRE "iwlwifi-6000g2a-" -#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" +#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode" #define IWL6030_FW_PRE "iwlwifi-6000g2b-" -#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" +#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode" static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { @@ -156,7 +157,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); if (priv->cfg->rx_with_siso_diversity) @@ -327,27 +327,23 @@ static struct iwl_nic_ops iwl6150_nic_ops = { static const struct iwl_ops iwl6000_ops = { .lib = &iwl6000_lib, - .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, }; static const struct iwl_ops iwl6050_ops = { .lib = &iwl6000_lib, - .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, .nic = &iwl6050_nic_ops, }; static const struct iwl_ops iwl6150_ops = { .lib = &iwl6000_lib, - .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, .nic = &iwl6150_nic_ops, }; static const struct iwl_ops iwl6030_ops = { .lib = &iwl6030_lib, - .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index ba7ed9157c92..ce7d4b56d9b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -205,7 +205,7 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv, return max_rssi - agc - IWLAGN_RSSI_OFFSET; } -static int iwlagn_set_pan_params(struct iwl_priv *priv) +int iwlagn_set_pan_params(struct iwl_priv *priv) { struct iwl_wipan_params_cmd cmd; struct iwl_rxon_context *ctx_bss, *ctx_pan; @@ -297,20 +297,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) return ret; } -struct iwl_hcmd_ops iwlagn_hcmd = { - .set_rxon_chain = iwlagn_set_rxon_chain, - .set_tx_ant = iwlagn_send_tx_ant_config, - .send_bt_config = iwl_send_bt_config, - .set_pan_params = iwlagn_set_pan_params, -}; - -struct iwl_hcmd_ops iwlagn_bt_hcmd = { - .set_rxon_chain = iwlagn_set_rxon_chain, - .set_tx_ant = iwlagn_send_tx_ant_config, - .send_bt_config = iwlagn_send_advance_bt_config, - .set_pan_params = iwlagn_set_pan_params, -}; - struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = { .build_addsta_hcmd = iwlagn_build_addsta_hcmd, .gain_computation = iwlagn_gain_computation, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index efdab6506ae7..90d366e15d2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -628,38 +628,6 @@ struct iwl_mod_params iwlagn_mod_params = { /* the rest are 0 by default */ }; -void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) -{ - unsigned long flags; - int i; - spin_lock_irqsave(&rxq->lock, flags); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { - /* In the reset function, these buffers may have been allocated - * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].page != NULL) { - dma_unmap_page(priv->bus.dev, rxq->pool[i].page_dma, - PAGE_SIZE << priv->hw_params.rx_page_order, - DMA_FROM_DEVICE); - __iwl_free_pages(priv, rxq->pool[i].page); - rxq->pool[i].page = NULL; - } - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - } - - for (i = 0; i < RX_QUEUE_SIZE; i++) - rxq->queue[i] = NULL; - - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->write_actual = 0; - rxq->free_count = 0; - spin_unlock_irqrestore(&rxq->lock, flags); -} - int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { u32 rb_size; @@ -731,7 +699,6 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv) { unsigned long flags; struct iwl_rx_queue *rxq = &priv->rxq; - int ret; /* nic_init */ spin_lock_irqsave(&priv->lock, flags); @@ -747,14 +714,7 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv) priv->cfg->ops->lib->apm_ops.config(priv); /* Allocate the RX queue, or reset if it is already allocated */ - if (!rxq->bd) { - ret = iwl_rx_queue_alloc(priv); - if (ret) { - IWL_ERR(priv, "Unable to initialize Rx queue\n"); - return -ENOMEM; - } - } else - iwlagn_rx_queue_reset(priv, rxq); + priv->trans.ops->rx_init(priv); iwlagn_rx_replenish(priv); @@ -768,12 +728,8 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); /* Allocate or reset and init all Tx and Command queues */ - if (!priv->txq) { - ret = iwlagn_txq_ctx_alloc(priv); - if (ret) - return ret; - } else - iwlagn_txq_ctx_reset(priv); + if (priv->trans.ops->tx_init(priv)) + return -ENOMEM; if (priv->cfg->base_params->shadow_reg_enable) { /* enable shadow regs in HW */ @@ -949,33 +905,6 @@ void iwlagn_rx_replenish_now(struct iwl_priv *priv) iwlagn_rx_queue_restock(priv); } -/* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have its SKB set to NULL - * This free routine walks the list of POOL entries and if SKB is set to - * non NULL it is unmapped and freed - */ -void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) -{ - int i; - for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].page != NULL) { - dma_unmap_page(priv->bus.dev, rxq->pool[i].page_dma, - PAGE_SIZE << priv->hw_params.rx_page_order, - DMA_FROM_DEVICE); - __iwl_free_pages(priv, rxq->pool[i].page); - rxq->pool[i].page = NULL; - } - } - - dma_free_coherent(priv->bus.dev, 4 * RX_QUEUE_SIZE, - rxq->bd, rxq->bd_dma); - dma_free_coherent(priv->bus.dev, - sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); - rxq->bd = NULL; - rxq->rb_stts = NULL; -} - int iwlagn_rxq_stop(struct iwl_priv *priv) { @@ -1437,17 +1366,14 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) /* set scan bit here for PAN params */ set_bit(STATUS_SCAN_HW, &priv->status); - if (priv->cfg->ops->hcmd->set_pan_params) { - ret = priv->cfg->ops->hcmd->set_pan_params(priv); - if (ret) - return ret; - } + ret = iwlagn_set_pan_params(priv); + if (ret) + return ret; ret = iwl_send_cmd_sync(priv, &cmd); if (ret) { clear_bit(STATUS_SCAN_HW, &priv->status); - if (priv->cfg->ops->hcmd->set_pan_params) - priv->cfg->ops->hcmd->set_pan_params(priv); + iwlagn_set_pan_params(priv); } return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index a7c66c4e5f2a..c6bb73a66d9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -210,6 +210,8 @@ static int iwlagn_rxon_disconn(struct iwl_priv *priv, * keys, so we have to restore those afterwards. */ iwl_clear_ucode_stations(priv, ctx); + /* update -- might need P2P now */ + iwl_update_bcast_station(priv, ctx); iwl_restore_stations(priv, ctx); ret = iwl_restore_default_wep_keys(priv, ctx); if (ret) { @@ -434,11 +436,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) if (ret) return ret; - if (priv->cfg->ops->hcmd->set_pan_params) { - ret = priv->cfg->ops->hcmd->set_pan_params(priv); - if (ret) - return ret; - } + ret = iwlagn_set_pan_params(priv); + if (ret) + return ret; if (new_assoc) return iwlagn_rxon_connect(priv, ctx); @@ -481,9 +481,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) * set up the SM PS mode to OFF if an HT channel is * configured. */ - if (priv->cfg->ops->hcmd->set_rxon_chain) - for_each_context(priv, ctx) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + for_each_context(priv, ctx) + iwlagn_set_rxon_chain(priv, ctx); } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { @@ -739,8 +738,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, iwl_set_rxon_ht(priv, &priv->current_ht_config); } - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + iwlagn_set_rxon_chain(priv, ctx); if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK; @@ -819,6 +817,5 @@ void iwlagn_post_scan(struct iwl_priv *priv) if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) iwlagn_commit_rxon(priv, ctx); - if (priv->cfg->ops->hcmd->set_pan_params) - priv->cfg->ops->hcmd->set_pan_params(priv); + iwlagn_set_pan_params(priv); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 0bd722cee5ae..9b32f83f0b7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -35,7 +35,7 @@ #include "iwl-agn.h" static struct iwl_link_quality_cmd * -iwl_sta_alloc_lq(struct iwl_priv *priv, u8 sta_id) +iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id) { int i, r; struct iwl_link_quality_cmd *link_cmd; @@ -47,10 +47,15 @@ iwl_sta_alloc_lq(struct iwl_priv *priv, u8 sta_id) IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n"); return NULL; } + + lockdep_assert_held(&priv->mutex); + /* Set up the rate scaling to start at selected rate, fall back * all the way down to 1M in IEEE order, and then spin on 1M */ if (priv->band == IEEE80211_BAND_5GHZ) r = IWL_RATE_6M_INDEX; + else if (ctx && ctx->vif && ctx->vif->p2p) + r = IWL_RATE_6M_INDEX; else r = IWL_RATE_1M_INDEX; @@ -115,7 +120,7 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx spin_unlock_irqrestore(&priv->sta_lock, flags); /* Set up default rate scaling table in device's station table */ - link_cmd = iwl_sta_alloc_lq(priv, sta_id); + link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); if (!link_cmd) { IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n", addr); @@ -554,7 +559,7 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv, priv->stations[sta_id].used |= IWL_STA_BCAST; spin_unlock_irqrestore(&priv->sta_lock, flags); - link_cmd = iwl_sta_alloc_lq(priv, sta_id); + link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); if (!link_cmd) { IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n"); @@ -574,14 +579,14 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv, * Only used by iwlagn. Placed here to have all bcast station management * code together. */ -static int iwl_update_bcast_station(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) +int iwl_update_bcast_station(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) { unsigned long flags; struct iwl_link_quality_cmd *link_cmd; u8 sta_id = ctx->bcast_sta_id; - link_cmd = iwl_sta_alloc_lq(priv, sta_id); + link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); if (!link_cmd) { IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n"); return -ENOMEM; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index d0ac090399e9..a87e95728b1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -497,8 +497,7 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv, case WLAN_CIPHER_SUITE_TKIP: tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; - ieee80211_get_tkip_key(keyconf, skb_frag, - IEEE80211_TKIP_P2_KEY, tx_cmd->key); + ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n"); break; @@ -878,96 +877,6 @@ void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv) } /** - * iwlagn_txq_ctx_alloc - allocate TX queue context - * Allocate all Tx DMA structures and initialize them - * - * @param priv - * @return error code - */ -int iwlagn_txq_ctx_alloc(struct iwl_priv *priv) -{ - int ret; - int txq_id, slots_num; - unsigned long flags; - - /* Free all tx/cmd queues and keep-warm buffer */ - iwlagn_hw_txq_ctx_free(priv); - - ret = iwlagn_alloc_dma_ptr(priv, &priv->scd_bc_tbls, - priv->hw_params.scd_bc_tbls_size); - if (ret) { - IWL_ERR(priv, "Scheduler BC Table allocation failed\n"); - goto error_bc_tbls; - } - /* Alloc keep-warm buffer */ - ret = iwlagn_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE); - if (ret) { - IWL_ERR(priv, "Keep Warm allocation failed\n"); - goto error_kw; - } - - /* allocate tx queue structure */ - ret = iwl_alloc_txq_mem(priv); - if (ret) - goto error; - - spin_lock_irqsave(&priv->lock, flags); - - /* Turn off all Tx DMA fifos */ - iwlagn_txq_set_sched(priv, 0); - - /* Tell NIC where to find the "keep warm" buffer */ - iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Alloc and init all Tx queues, including the command queue (#4/#9) */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - slots_num = (txq_id == priv->cmd_queue) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, - txq_id); - if (ret) { - IWL_ERR(priv, "Tx %d queue init failed\n", txq_id); - goto error; - } - } - - return ret; - - error: - iwlagn_hw_txq_ctx_free(priv); - iwlagn_free_dma_ptr(priv, &priv->kw); - error_kw: - iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls); - error_bc_tbls: - return ret; -} - -void iwlagn_txq_ctx_reset(struct iwl_priv *priv) -{ - int txq_id, slots_num; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* Turn off all Tx DMA fifos */ - iwlagn_txq_set_sched(priv, 0); - - /* Tell NIC where to find the "keep warm" buffer */ - iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Alloc and init all Tx queues, including the command queue (#4) */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - slots_num = txq_id == priv->cmd_queue ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id); - } -} - -/** * iwlagn_txq_ctx_stop - Stop all Tx DMA channels */ void iwlagn_txq_ctx_stop(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index de8277e32253..2043c8b3139b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -386,11 +386,13 @@ static int iwlagn_alive_notify(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); priv->scd_base_addr = iwl_read_prph(priv, IWLAGN_SCD_SRAM_BASE_ADDR); - a = priv->scd_base_addr + IWLAGN_SCD_CONTEXT_DATA_OFFSET; - for (; a < priv->scd_base_addr + IWLAGN_SCD_TX_STTS_BITMAP_OFFSET; + a = priv->scd_base_addr + IWLAGN_SCD_CONTEXT_MEM_LOWER_BOUND; + /* reset conext data memory */ + for (; a < priv->scd_base_addr + IWLAGN_SCD_CONTEXT_MEM_UPPER_BOUND; a += 4) iwl_write_targ_mem(priv, a, 0); - for (; a < priv->scd_base_addr + IWLAGN_SCD_TRANSLATE_TBL_OFFSET; + /* reset tx status memory */ + for (; a < priv->scd_base_addr + IWLAGN_SCD_TX_STTS_MEM_UPPER_BOUND; a += 4) iwl_write_targ_mem(priv, a, 0); for (; a < priv->scd_base_addr + diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 77ceb8deff75..7e6c463abbdf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -56,7 +56,7 @@ #include "iwl-agn-calib.h" #include "iwl-agn.h" #include "iwl-pci.h" - +#include "iwl-trans.h" /****************************************************************************** * @@ -90,12 +90,10 @@ void iwl_update_chain_flags(struct iwl_priv *priv) { struct iwl_rxon_context *ctx; - if (priv->cfg->ops->hcmd->set_rxon_chain) { - for_each_context(priv, ctx) { - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - if (ctx->active.rx_chain != ctx->staging.rx_chain) - iwlagn_commit_rxon(priv, ctx); - } + for_each_context(priv, ctx) { + iwlagn_set_rxon_chain(priv, ctx); + if (ctx->active.rx_chain != ctx->staging.rx_chain) + iwlagn_commit_rxon(priv, ctx); } } @@ -132,6 +130,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) struct iwl_host_cmd cmd = { .id = REPLY_TX_BEACON, }; + struct ieee80211_tx_info *info; u32 frame_size; u32 rate_flags; u32 rate; @@ -172,14 +171,31 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) frame_size); /* Set up packet rate and flags */ - rate = iwl_rate_get_lowest_plcp(priv, priv->beacon_ctx); + info = IEEE80211_SKB_CB(priv->beacon_skb); + + /* + * Let's set up the rate at least somewhat correctly; + * it will currently not actually be used by the uCode, + * it uses the broadcast station's rate instead. + */ + if (info->control.rates[0].idx < 0 || + info->control.rates[0].flags & IEEE80211_TX_RC_MCS) + rate = 0; + else + rate = info->control.rates[0].idx; + priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, priv->hw_params.valid_tx_ant); rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant); - if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE)) + + /* In mac80211, rates for 5 GHz start at 0 */ + if (info->band == IEEE80211_BAND_5GHZ) + rate += IWL_FIRST_OFDM_RATE; + else if (rate >= IWL_FIRST_CCK_RATE && rate <= IWL_LAST_CCK_RATE) rate_flags |= RATE_MCS_CCK_MSK; - tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, - rate_flags); + + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, rate_flags); /* Submit command */ cmd.len[0] = sizeof(*tx_beacon_cmd); @@ -242,7 +258,7 @@ static void iwl_bg_bt_runtime_config(struct work_struct *work) /* dont send host command if rf-kill is on */ if (!iwl_is_ready_rf(priv)) return; - priv->cfg->ops->hcmd->send_bt_config(priv); + iwlagn_send_advance_bt_config(priv); } static void iwl_bg_bt_full_concurrency(struct work_struct *work) @@ -269,12 +285,11 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) * to avoid 3-wire collisions */ for_each_context(priv, ctx) { - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + iwlagn_set_rxon_chain(priv, ctx); iwlagn_commit_rxon(priv, ctx); } - priv->cfg->ops->hcmd->send_bt_config(priv); + iwlagn_send_advance_bt_config(priv); out: mutex_unlock(&priv->mutex); } @@ -1999,7 +2014,7 @@ int iwl_alive_start(struct iwl_priv *priv) priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK; priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT; priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT; - priv->cfg->ops->hcmd->send_bt_config(priv); + iwlagn_send_advance_bt_config(priv); priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS; iwlagn_send_prio_tbl(priv); @@ -2012,7 +2027,13 @@ int iwl_alive_start(struct iwl_priv *priv) BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); if (ret) return ret; + } else { + /* + * default is 2-wire BT coexexistence support + */ + iwl_send_bt_config(priv); } + if (priv->hw_params.calib_rt_cfg) iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); @@ -2021,8 +2042,7 @@ int iwl_alive_start(struct iwl_priv *priv) priv->active_rate = IWL_RATES_MASK; /* Configure Tx antenna selection based on H/W config */ - if (priv->cfg->ops->hcmd->set_tx_ant) - priv->cfg->ops->hcmd->set_tx_ant(priv, priv->cfg->valid_tx_ant); + iwlagn_send_tx_ant_config(priv, priv->cfg->valid_tx_ant); if (iwl_is_associated_ctx(ctx)) { struct iwl_rxon_cmd *active_rxon = @@ -2036,16 +2056,7 @@ int iwl_alive_start(struct iwl_priv *priv) for_each_context(priv, tmp) iwl_connection_init_rx_config(priv, tmp); - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - } - - if (!priv->cfg->bt_params || (priv->cfg->bt_params && - !priv->cfg->bt_params->advanced_bt_coexist)) { - /* - * default is 2-wire BT coexexistence support - */ - priv->cfg->ops->hcmd->send_bt_config(priv); + iwlagn_set_rxon_chain(priv, ctx); } iwl_reset_run_time_calib(priv); @@ -3270,9 +3281,7 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->rx_statistics_jiffies = jiffies; /* Choose which receivers/antennas to use */ - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, - &priv->contexts[IWL_RXON_CTX_BSS]); + iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]); iwl_init_scan_params(priv); @@ -3499,6 +3508,8 @@ int iwl_probe(void *bus_specific, struct iwl_bus_ops *bus_ops, priv->bus.ops->set_drv_data(&priv->bus, priv); priv->bus.dev = priv->bus.ops->get_dev(&priv->bus); + iwl_trans_register(&priv->trans); + /* At this point both hw and priv are allocated. */ SET_IEEE80211_DEV(hw, priv->bus.dev); @@ -3698,8 +3709,7 @@ void __devexit iwl_remove(struct iwl_priv * priv) iwl_dealloc_ucode(priv); - if (priv->rxq.bd) - iwlagn_rx_queue_free(priv, &priv->rxq); + priv->trans.ops->rx_free(priv); iwlagn_hw_txq_ctx_free(priv); iwl_eeprom_free(priv); @@ -3802,6 +3812,10 @@ MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); +module_param_named(wd_disable, iwlagn_mod_params.wd_disable, bool, S_IRUGO); +MODULE_PARM_DESC(wd_disable, + "Disable stuck queue watchdog timer (default: 0 [enabled])"); + /* * set bt_coex_active to true, uCode will do kill/defer * every time the priority line is asserted (BT is sending signals on the diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 6d5584ae5ebf..4351151e2a91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -182,7 +182,6 @@ void iwlagn_temperature(struct iwl_priv *priv); u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv); const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); -void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); int iwlagn_hw_nic_init(struct iwl_priv *priv); int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); @@ -194,7 +193,6 @@ void iwlagn_rx_queue_restock(struct iwl_priv *priv); void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority); void iwlagn_rx_replenish(struct iwl_priv *priv); void iwlagn_rx_replenish_now(struct iwl_priv *priv); -void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); int iwlagn_rxq_stop(struct iwl_priv *priv); int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); void iwl_setup_rx_handlers(struct iwl_priv *priv); @@ -220,8 +218,6 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv); -int iwlagn_txq_ctx_alloc(struct iwl_priv *priv); -void iwlagn_txq_ctx_reset(struct iwl_priv *priv); void iwlagn_txq_ctx_stop(struct iwl_priv *priv); static inline u32 iwl_tx_status_to_mac80211(u32 status) @@ -260,6 +256,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, /* hcmd */ int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); +int iwlagn_set_pan_params(struct iwl_priv *priv); /* bt coex */ void iwlagn_send_advance_bt_config(struct iwl_priv *priv); @@ -304,6 +301,8 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, int tid); void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt); +int iwl_update_bcast_station(struct iwl_priv *priv, + struct iwl_rxon_context *ctx); int iwl_update_bcast_stations(struct iwl_priv *priv); void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index cde725326c32..f91e306c2498 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -526,19 +526,6 @@ int iwl_full_rxon_required(struct iwl_priv *priv, return 0; } -u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - /* - * Assign the lowest rate -- should really get this from - * the beacon skb from mac80211. - */ - if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) - return IWL_RATE_1M_PLCP; - else - return IWL_RATE_6M_PLCP; -} - static void _iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf, struct iwl_rxon_context *ctx) @@ -598,8 +585,7 @@ static void _iwl_set_rxon_ht(struct iwl_priv *priv, rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; } - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + iwlagn_set_rxon_chain(priv, ctx); IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X " "extension channel offset 0x%x\n", @@ -1229,8 +1215,7 @@ static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { iwl_connection_init_rx_config(priv, ctx); - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + iwlagn_set_rxon_chain(priv, ctx); return iwlagn_commit_rxon(priv, ctx); } @@ -1385,20 +1370,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, } -int iwl_alloc_txq_mem(struct iwl_priv *priv) -{ - if (!priv->txq) - priv->txq = kzalloc( - sizeof(struct iwl_tx_queue) * - priv->cfg->base_params->num_of_queues, - GFP_KERNEL); - if (!priv->txq) { - IWL_ERR(priv, "Not enough memory for txq\n"); - return -ENOMEM; - } - return 0; -} - void iwl_free_txq_mem(struct iwl_priv *priv) { kfree(priv->txq); @@ -1717,6 +1688,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_context *tmp; + enum nl80211_iftype newviftype = newtype; u32 interface_modes; int err; @@ -1772,7 +1744,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* success */ iwl_teardown_interface(priv, vif, true); - vif->type = newtype; + vif->type = newviftype; vif->p2p = newp2p; err = iwl_setup_interface(priv, ctx); WARN_ON(err); @@ -1865,7 +1837,7 @@ void iwl_setup_watchdog(struct iwl_priv *priv) { unsigned int timeout = priv->cfg->base_params->wd_timeout; - if (timeout) + if (timeout && !iwlagn_mod_params.wd_disable) mod_timer(&priv->watchdog, jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); else diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index adf9f9b2efb5..6c21de9f5b60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -80,14 +80,6 @@ struct iwl_cmd; #define IWL_CMD(x) case x: return #x -struct iwl_hcmd_ops { - void (*set_rxon_chain)(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); - int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant); - void (*send_bt_config)(struct iwl_priv *priv); - int (*set_pan_params)(struct iwl_priv *priv); -}; - struct iwl_hcmd_utils_ops { u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); void (*gain_computation)(struct iwl_priv *priv, @@ -146,7 +138,6 @@ struct iwl_nic_ops { struct iwl_ops { const struct iwl_lib_ops *lib; - const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; const struct iwl_nic_ops *nic; }; @@ -160,6 +151,7 @@ struct iwl_mod_params { int restart_fw; /* def: 1 = restart firmware */ bool plcp_check; /* def: true = enable plcp health check */ bool ack_check; /* def: false = disable ack health check */ + bool wd_disable; /* def: false = enable stuck queue check */ bool bt_coex_active; /* def: true = enable bt coex */ int led_mode; /* def: 0 = system default */ bool no_sleep_autoadjust; /* def: true = disable autoadjust */ @@ -336,7 +328,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum nl80211_iftype newtype, bool newp2p); -int iwl_alloc_txq_mem(struct iwl_priv *priv); void iwl_free_txq_mem(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -382,7 +373,6 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, ******************************************************/ void iwl_cmd_queue_free(struct iwl_priv *priv); void iwl_cmd_queue_unmap(struct iwl_priv *priv); -int iwl_rx_queue_alloc(struct iwl_priv *priv); void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q); int iwl_rx_queue_space(const struct iwl_rx_queue *q); @@ -396,11 +386,9 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); * TX ******************************************************/ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); -int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, - int slots_num, u32 txq_id); -void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, - int slots_num, u32 txq_id); void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id); +int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, + int count, int slots_num, u32 id); void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id); void iwl_setup_watchdog(struct iwl_priv *priv); /***************************************************** @@ -409,13 +397,6 @@ void iwl_setup_watchdog(struct iwl_priv *priv); int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); /******************************************************************************* - * Rate - ******************************************************************************/ - -u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); - -/******************************************************************************* * Scanning ******************************************************************************/ void iwl_init_scan_params(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8ec04f20c96a..f4501f836155 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -665,7 +665,6 @@ struct iwl_hw_params { u16 max_rxq_size; u16 max_rxq_log; u32 rx_page_order; - u32 rx_wrt_ptr_reg; u8 max_stations; u8 ht40_channel; u8 max_beacon_itrvl; /* in 1024 ms */ @@ -1227,6 +1226,25 @@ struct iwl_bus { unsigned int irq; }; +struct iwl_trans; + +/** + * struct iwl_trans_ops - transport specific operations + + * @rx_init: inits the rx memory, allocate it if needed + * @rx_free: frees the rx memory + * @tx_init:inits the tx memory, allocate if needed + */ +struct iwl_trans_ops { + int (*rx_init)(struct iwl_priv *priv); + void (*rx_free)(struct iwl_priv *priv); + int (*tx_init)(struct iwl_priv *priv); +}; + +struct iwl_trans { + const struct iwl_trans_ops *ops; +}; + struct iwl_priv { /* ieee device used by generic ieee processing code */ @@ -1295,13 +1313,13 @@ struct iwl_priv { struct mutex mutex; struct iwl_bus bus; /* bus specific data */ + struct iwl_trans trans; /* microcode/device supports multiple contexts */ u8 valid_contexts; /* command queue number */ u8 cmd_queue; - u8 last_sync_cmd_id; /* max number of station keys */ u8 sta_key_max_num; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 7cdb1ec73b54..107b38e2ee93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -113,7 +113,7 @@ const char *get_cmd_string(u8 cmd) } } -#define HOST_COMPLETE_TIMEOUT (HZ / 2) +#define HOST_COMPLETE_TIMEOUT (2 * HZ) static void iwl_generic_cmd_callback(struct iwl_priv *priv, struct iwl_device_cmd *cmd, @@ -171,6 +171,8 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; + lockdep_assert_held(&priv->mutex); + if (WARN_ON(cmd->flags & CMD_ASYNC)) return -EINVAL; @@ -181,16 +183,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", get_cmd_string(cmd->id)); - if (test_and_set_bit(STATUS_HCMD_ACTIVE, &priv->status)) { - IWL_ERR(priv, "STATUS_HCMD_ACTIVE already set while sending %s" - ". Previous SYNC cmdn is %s\n", - get_cmd_string(cmd->id), - get_cmd_string(priv->last_sync_cmd_id)); - WARN_ON(1); - } else { - priv->last_sync_cmd_id = cmd->id; - } - + set_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", get_cmd_string(cmd->id)); diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index 7328fbff7f7b..74911348a2ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -67,6 +67,7 @@ #include "iwl-agn.h" #include "iwl-core.h" #include "iwl-io.h" +#include "iwl-trans.h" /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 @@ -93,7 +94,7 @@ static u16 iwl_pciexp_link_ctrl(struct iwl_bus *bus) u16 pci_lnk_ctl; struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus); - pos = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(pci_dev); pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl); return pci_lnk_ctl; } @@ -383,7 +384,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); struct iwl_pci_bus *bus; - u8 rev_id; u16 pci_cmd; int err; @@ -440,8 +440,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) (unsigned long long) pci_resource_len(pdev, 0)); pr_info("pci_resource_base = %p\n", bus->hw_base); - pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); - pr_info("HW Revision ID = 0x%X\n", rev_id); + pr_info("HW Revision ID = 0x%X\n", pdev->revision); /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ @@ -496,14 +495,11 @@ static void iwl_pci_down(void *bus) static void __devexit iwl_pci_remove(struct pci_dev *pdev) { struct iwl_priv *priv = pci_get_drvdata(pdev); - - /* This can happen if probe failed */ - if (unlikely(!priv)) - return; + void *bus_specific = priv->bus.bus_specific; iwl_remove(priv); - iwl_pci_down(IWL_BUS_GET_PCI_BUS(&priv->bus)); + iwl_pci_down(bus_specific); } #ifdef CONFIG_PM @@ -530,14 +526,7 @@ static int iwl_pci_resume(struct device *device) return iwl_resume(priv); } -static const struct dev_pm_ops iwl_dev_pm_ops = { - .suspend = iwl_pci_suspend, - .resume = iwl_pci_resume, - .freeze = iwl_pci_suspend, - .thaw = iwl_pci_resume, - .poweroff = iwl_pci_suspend, - .restore = iwl_pci_resume, -}; +static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); #define IWL_PM_OPS (&iwl_dev_pm_ops) diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index f00d188b2cfc..1cc0ed1f488c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -168,6 +168,7 @@ * the scheduler (especially for queue #4/#9, the command queue, otherwise * the driver can't issue commands!): */ +#define SCD_MEM_LOWER_BOUND (0x0000) /** * Max Tx window size is the max number of contiguous TFDs that the scheduler @@ -197,15 +198,23 @@ #define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) #define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) -#define IWLAGN_SCD_CONTEXT_DATA_OFFSET (0x600) -#define IWLAGN_SCD_TX_STTS_BITMAP_OFFSET (0x7B1) -#define IWLAGN_SCD_TRANSLATE_TBL_OFFSET (0x7E0) +/* Context Data */ +#define IWLAGN_SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600) +#define IWLAGN_SCD_CONTEXT_MEM_UPPER_BOUND (SCD_MEM_LOWER_BOUND + 0x6A0) + +/* Tx status */ +#define IWLAGN_SCD_TX_STTS_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x6A0) +#define IWLAGN_SCD_TX_STTS_MEM_UPPER_BOUND (SCD_MEM_LOWER_BOUND + 0x7E0) + +/* Translation Data */ +#define IWLAGN_SCD_TRANS_TBL_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x7E0) +#define IWLAGN_SCD_TRANS_TBL_MEM_UPPER_BOUND (SCD_MEM_LOWER_BOUND + 0x808) #define IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(x)\ - (IWLAGN_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) + (IWLAGN_SCD_CONTEXT_MEM_LOWER_BOUND + ((x) * 8)) #define IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ - ((IWLAGN_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc) + ((IWLAGN_SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc) #define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv) \ (((1<<(priv)->hw_params.max_txq_num) - 1) &\ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 3efa7066e987..87148bb3f628 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -134,7 +134,6 @@ int iwl_rx_queue_space(const struct iwl_rx_queue *q) void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) { unsigned long flags; - u32 rx_wrt_ptr_reg = priv->hw_params.rx_wrt_ptr_reg; u32 reg; spin_lock_irqsave(&q->lock, flags); @@ -146,7 +145,7 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q /* shadow register enabled */ /* Device expects a multiple of 8 */ q->write_actual = (q->write & ~0x7); - iwl_write32(priv, rx_wrt_ptr_reg, q->write_actual); + iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write_actual); } else { /* If power-saving is in use, make sure device is awake */ if (test_bit(STATUS_POWER_PMI, &priv->status)) { @@ -162,14 +161,14 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q } q->write_actual = (q->write & ~0x7); - iwl_write_direct32(priv, rx_wrt_ptr_reg, + iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, q->write_actual); /* Else device is assumed to be awake */ } else { /* Device expects a multiple of 8 */ q->write_actual = (q->write & ~0x7); - iwl_write_direct32(priv, rx_wrt_ptr_reg, + iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, q->write_actual); } } @@ -179,46 +178,6 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q spin_unlock_irqrestore(&q->lock, flags); } -int iwl_rx_queue_alloc(struct iwl_priv *priv) -{ - struct iwl_rx_queue *rxq = &priv->rxq; - struct device *dev = priv->bus.dev; - int i; - - spin_lock_init(&rxq->lock); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - - /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ - rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->bd_dma, - GFP_KERNEL); - if (!rxq->bd) - goto err_bd; - - rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct iwl_rb_status), - &rxq->rb_stts_dma, GFP_KERNEL); - if (!rxq->rb_stts) - goto err_rb; - - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->write_actual = 0; - rxq->free_count = 0; - rxq->need_update = 0; - return 0; - -err_rb: - dma_free_coherent(dev, 4 * RX_QUEUE_SIZE, rxq->bd, - rxq->bd_dma); -err_bd: - return -ENOMEM; -} - /****************************************************************************** * * Generic RX handler implementations diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h index 160911a3716a..d825188e5215 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.h +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -66,116 +66,144 @@ #include <linux/types.h> -/* Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and +/* + * Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and * from and kernel space to user space(IWL_TM_CMD_ID_DEV2APP_XX). - * The command ID is carried with IWL_TM_ATTR_COMMAND. There are three types of - * of command from user space and two types of command from kernel space. - * See below. + * The command ID is carried with IWL_TM_ATTR_COMMAND. + * + * @IWL_TM_CMD_APP2DEV_UCODE: + * commands from user application to the uCode, + * the actual uCode host command ID is carried with + * IWL_TM_ATTR_UCODE_CMD_ID + * + * @IWL_TM_CMD_APP2DEV_REG_READ32: + * @IWL_TM_CMD_APP2DEV_REG_WRITE32: + * @IWL_TM_CMD_APP2DEV_REG_WRITE8: + * commands from user applicaiton to access register + * + * @IWL_TM_CMD_APP2DEV_GET_DEVICENAME: retrieve device name + * @IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: load initial uCode image + * @IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: perform calibration + * @IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: load runtime uCode image + * @IWL_TM_CMD_APP2DEV_GET_EEPROM: request EEPROM data + * @IWL_TM_CMD_APP2DEV_FIXRATE_REQ: set fix MCS + * commands fom user space for pure driver level operations + * + * @IWL_TM_CMD_APP2DEV_BEGIN_TRACE: + * @IWL_TM_CMD_APP2DEV_END_TRACE: + * @IWL_TM_CMD_APP2DEV_READ_TRACE: + * commands fom user space for uCode trace operations + * + * @IWL_TM_CMD_DEV2APP_SYNC_RSP: + * commands from kernel space to carry the synchronous response + * to user application + * @IWL_TM_CMD_DEV2APP_UCODE_RX_PKT: + * commands from kernel space to multicast the spontaneous messages + * to user application + * @IWL_TM_CMD_DEV2APP_EEPROM_RSP: + * commands from kernel space to carry the eeprom response + * to user application */ enum iwl_tm_cmd_t { - /* commands from user application to the uCode, - * the actual uCode host command ID is carried with - * IWL_TM_ATTR_UCODE_CMD_ID */ - IWL_TM_CMD_APP2DEV_UCODE = 1, - - /* commands from user applicaiton to access register */ - IWL_TM_CMD_APP2DEV_REG_READ32, - IWL_TM_CMD_APP2DEV_REG_WRITE32, - IWL_TM_CMD_APP2DEV_REG_WRITE8, - - /* commands fom user space for pure driver level operations */ - IWL_TM_CMD_APP2DEV_GET_DEVICENAME, - IWL_TM_CMD_APP2DEV_LOAD_INIT_FW, - IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB, - IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW, - IWL_TM_CMD_APP2DEV_GET_EEPROM, - IWL_TM_CMD_APP2DEV_FIXRATE_REQ, - /* if there is other new command for the driver layer operation, - * append them here */ - - /* commands fom user space for uCode trace operations */ - IWL_TM_CMD_APP2DEV_BEGIN_TRACE, - IWL_TM_CMD_APP2DEV_END_TRACE, - IWL_TM_CMD_APP2DEV_READ_TRACE, - - /* commands from kernel space to carry the synchronous response - * to user application */ - IWL_TM_CMD_DEV2APP_SYNC_RSP, - - /* commands from kernel space to multicast the spontaneous messages - * to user application */ - IWL_TM_CMD_DEV2APP_UCODE_RX_PKT, - - /* commands from kernel space to carry the eeprom response - * to user application */ - IWL_TM_CMD_DEV2APP_EEPROM_RSP, - - IWL_TM_CMD_MAX, + IWL_TM_CMD_APP2DEV_UCODE = 1, + IWL_TM_CMD_APP2DEV_REG_READ32 = 2, + IWL_TM_CMD_APP2DEV_REG_WRITE32 = 3, + IWL_TM_CMD_APP2DEV_REG_WRITE8 = 4, + IWL_TM_CMD_APP2DEV_GET_DEVICENAME = 5, + IWL_TM_CMD_APP2DEV_LOAD_INIT_FW = 6, + IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB = 7, + IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW = 8, + IWL_TM_CMD_APP2DEV_GET_EEPROM = 9, + IWL_TM_CMD_APP2DEV_FIXRATE_REQ = 10, + IWL_TM_CMD_APP2DEV_BEGIN_TRACE = 11, + IWL_TM_CMD_APP2DEV_END_TRACE = 12, + IWL_TM_CMD_APP2DEV_READ_TRACE = 13, + IWL_TM_CMD_DEV2APP_SYNC_RSP = 14, + IWL_TM_CMD_DEV2APP_UCODE_RX_PKT = 15, + IWL_TM_CMD_DEV2APP_EEPROM_RSP = 16, + IWL_TM_CMD_MAX = 17, }; +/* + * Atrribute filed in testmode command + * See enum iwl_tm_cmd_t. + * + * @IWL_TM_ATTR_NOT_APPLICABLE: + * The attribute is not applicable or invalid + * @IWL_TM_ATTR_COMMAND: + * From user space to kernel space: + * the command either destines to ucode, driver, or register; + * From kernel space to user space: + * the command either carries synchronous response, + * or the spontaneous message multicast from the device; + * + * @IWL_TM_ATTR_UCODE_CMD_ID: + * @IWL_TM_ATTR_UCODE_CMD_DATA: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE, + * The mandatory fields are : + * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID; + * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands; + * The optional fields are: + * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload + * to the ucode + * + * @IWL_TM_ATTR_REG_OFFSET: + * @IWL_TM_ATTR_REG_VALUE8: + * @IWL_TM_ATTR_REG_VALUE32: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX, + * The mandatory fields are: + * IWL_TM_ATTR_REG_OFFSET for the offset of the target register; + * IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value + * + * @IWL_TM_ATTR_SYNC_RSP: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP, + * The mandatory fields are: + * IWL_TM_ATTR_SYNC_RSP for the data content responding to the user + * application command + * + * @IWL_TM_ATTR_UCODE_RX_PKT: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT, + * The mandatory fields are: + * IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user + * application + * + * @IWL_TM_ATTR_EEPROM: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_EEPROM, + * The mandatory fields are: + * IWL_TM_ATTR_EEPROM for the data content responging to the user + * application + * + * @IWL_TM_ATTR_TRACE_ADDR: + * @IWL_TM_ATTR_TRACE_SIZE: + * @IWL_TM_ATTR_TRACE_DUMP: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_XXX_TRACE, + * The mandatory fields are: + * IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address + * IWL_TM_ATTR_MEM_TRACE_SIZE for the trace buffer size + * IWL_TM_ATTR_MEM_TRACE_DUMP for the trace dump + * + * @IWL_TM_ATTR_FIXRATE: + * When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ, + * The mandatory fields are: + * IWL_TM_ATTR_FIXRATE for the fixed rate + * + */ enum iwl_tm_attr_t { - IWL_TM_ATTR_NOT_APPLICABLE = 0, - - /* From user space to kernel space: - * the command either destines to ucode, driver, or register; - * See enum iwl_tm_cmd_t. - * - * From kernel space to user space: - * the command either carries synchronous response, - * or the spontaneous message multicast from the device; - * See enum iwl_tm_cmd_t. */ - IWL_TM_ATTR_COMMAND, - - /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE, - * The mandatory fields are : - * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID; - * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands; - * The optional fields are: - * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload - * to the ucode */ - IWL_TM_ATTR_UCODE_CMD_ID, - IWL_TM_ATTR_UCODE_CMD_DATA, - - /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX, - * The mandatory fields are: - * IWL_TM_ATTR_REG_OFFSET for the offset of the target register; - * IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value */ - IWL_TM_ATTR_REG_OFFSET, - IWL_TM_ATTR_REG_VALUE8, - IWL_TM_ATTR_REG_VALUE32, - - /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP, - * The mandatory fields are: - * IWL_TM_ATTR_SYNC_RSP for the data content responding to the user - * application command */ - IWL_TM_ATTR_SYNC_RSP, - /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT, - * The mandatory fields are: - * IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user - * application */ - IWL_TM_ATTR_UCODE_RX_PKT, - - /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_EEPROM, - * The mandatory fields are: - * IWL_TM_ATTR_EEPROM for the data content responging to the user - * application */ - IWL_TM_ATTR_EEPROM, - - /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_XXX_TRACE, - * The mandatory fields are: - * IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address - */ - IWL_TM_ATTR_TRACE_ADDR, - IWL_TM_ATTR_TRACE_SIZE, - IWL_TM_ATTR_TRACE_DUMP, - - /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ, - * The mandatory fields are: - * IWL_TM_ATTR_FIXRATE for the fixed rate - */ - IWL_TM_ATTR_FIXRATE, - - IWL_TM_ATTR_MAX, + IWL_TM_ATTR_NOT_APPLICABLE = 0, + IWL_TM_ATTR_COMMAND = 1, + IWL_TM_ATTR_UCODE_CMD_ID = 2, + IWL_TM_ATTR_UCODE_CMD_DATA = 3, + IWL_TM_ATTR_REG_OFFSET = 4, + IWL_TM_ATTR_REG_VALUE8 = 5, + IWL_TM_ATTR_REG_VALUE32 = 6, + IWL_TM_ATTR_SYNC_RSP = 7, + IWL_TM_ATTR_UCODE_RX_PKT = 8, + IWL_TM_ATTR_EEPROM = 9, + IWL_TM_ATTR_TRACE_ADDR = 10, + IWL_TM_ATTR_TRACE_SIZE = 11, + IWL_TM_ATTR_TRACE_DUMP = 12, + IWL_TM_ATTR_FIXRATE = 13, + IWL_TM_ATTR_MAX = 14, }; /* uCode trace buffer */ diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c new file mode 100644 index 000000000000..7b7b97d8c2e1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-trans.c @@ -0,0 +1,423 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2011 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. + * + * 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, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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. + * + *****************************************************************************/ +#include "iwl-dev.h" +#include "iwl-trans.h" +#include "iwl-core.h" +#include "iwl-helpers.h" +/*TODO remove uneeded includes when the transport layer tx_free will be here */ +#include "iwl-agn.h" + +static int iwl_trans_rx_alloc(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct device *dev = priv->bus.dev; + + memset(&priv->rxq, 0, sizeof(priv->rxq)); + + spin_lock_init(&rxq->lock); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + + if (WARN_ON(rxq->bd || rxq->rb_stts)) + return -EINVAL; + + /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */ + rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, + &rxq->bd_dma, GFP_KERNEL); + if (!rxq->bd) + goto err_bd; + memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE); + + /*Allocate the driver's pointer to receive buffer status */ + rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts), + &rxq->rb_stts_dma, GFP_KERNEL); + if (!rxq->rb_stts) + goto err_rb_stts; + memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); + + return 0; + +err_rb_stts: + dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, + rxq->bd, rxq->bd_dma); + memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); + rxq->bd = NULL; +err_bd: + return -ENOMEM; +} + +static void iwl_trans_rxq_free_rx_bufs(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + int i; + + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].page != NULL) { + dma_unmap_page(priv->bus.dev, rxq->pool[i].page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + DMA_FROM_DEVICE); + __iwl_free_pages(priv, rxq->pool[i].page); + rxq->pool[i].page = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } +} + +static int iwl_trans_rx_init(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + int i, err; + unsigned long flags; + + if (!rxq->bd) { + err = iwl_trans_rx_alloc(priv); + if (err) + return err; + } + + spin_lock_irqsave(&rxq->lock, flags); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + + iwl_trans_rxq_free_rx_bufs(priv); + + for (i = 0; i < RX_QUEUE_SIZE; i++) + rxq->queue[i] = NULL; + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->write_actual = 0; + rxq->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); + + return 0; +} + +static void iwl_trans_rx_free(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + unsigned long flags; + + /*if rxq->bd is NULL, it means that nothing has been allocated, + * exit now */ + if (!rxq->bd) { + IWL_DEBUG_INFO(priv, "Free NULL rx context\n"); + return; + } + + spin_lock_irqsave(&rxq->lock, flags); + iwl_trans_rxq_free_rx_bufs(priv); + spin_unlock_irqrestore(&rxq->lock, flags); + + dma_free_coherent(priv->bus.dev, sizeof(__le32) * RX_QUEUE_SIZE, + rxq->bd, rxq->bd_dma); + memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); + rxq->bd = NULL; + + if (rxq->rb_stts) + dma_free_coherent(priv->bus.dev, + sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); + else + IWL_DEBUG_INFO(priv, "Free rxq->rb_stts which is NULL\n"); + memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma)); + rxq->rb_stts = NULL; +} + +/* TODO:remove this code duplication */ +static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv, + struct iwl_dma_ptr *ptr, size_t size) +{ + if (WARN_ON(ptr->addr)) + return -EINVAL; + + ptr->addr = dma_alloc_coherent(priv->bus.dev, size, + &ptr->dma, GFP_KERNEL); + if (!ptr->addr) + return -ENOMEM; + ptr->size = size; + return 0; +} + +static int iwl_trans_txq_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq, + int slots_num, u32 txq_id) +{ + size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX; + int i; + + if (WARN_ON(txq->meta || txq->cmd || txq->txb || txq->tfds)) + return -EINVAL; + + txq->meta = kzalloc(sizeof(txq->meta[0]) * slots_num, + GFP_KERNEL); + txq->cmd = kzalloc(sizeof(txq->cmd[0]) * slots_num, + GFP_KERNEL); + + if (!txq->meta || !txq->cmd) + goto error; + + for (i = 0; i < slots_num; i++) { + txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd), + GFP_KERNEL); + if (!txq->cmd[i]) + goto error; + } + + /* Alloc driver data array and TFD circular buffer */ + /* Driver private data, only for Tx (not command) queues, + * not shared with device. */ + if (txq_id != priv->cmd_queue) { + txq->txb = kzalloc(sizeof(txq->txb[0]) * + TFD_QUEUE_SIZE_MAX, GFP_KERNEL); + if (!txq->txb) { + IWL_ERR(priv, "kmalloc for auxiliary BD " + "structures failed\n"); + goto error; + } + } else { + txq->txb = NULL; + } + + /* Circular buffer of transmit frame descriptors (TFDs), + * shared with device */ + txq->tfds = dma_alloc_coherent(priv->bus.dev, tfd_sz, &txq->q.dma_addr, + GFP_KERNEL); + if (!txq->tfds) { + IWL_ERR(priv, "dma_alloc_coherent(%zd) failed\n", tfd_sz); + goto error; + } + txq->q.id = txq_id; + + return 0; +error: + kfree(txq->txb); + txq->txb = NULL; + /* since txq->cmd has been zeroed, + * all non allocated cmd[i] will be NULL */ + if (txq->cmd) + for (i = 0; i < slots_num; i++) + kfree(txq->cmd[i]); + kfree(txq->meta); + kfree(txq->cmd); + txq->meta = NULL; + txq->cmd = NULL; + + return -ENOMEM; + +} + +static int iwl_trans_txq_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, + int slots_num, u32 txq_id) +{ + int ret; + + txq->need_update = 0; + memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num); + + /* + * For the default queues 0-3, set up the swq_id + * already -- all others need to get one later + * (if they need one at all). + */ + if (txq_id < 4) + iwl_set_swq_id(txq, txq_id, txq_id); + + /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ + BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); + + /* Initialize queue's high/low-water marks, and head/tail indexes */ + ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, + txq_id); + if (ret) + return ret; + + /* + * Tell nic where to find circular buffer of Tx Frame Descriptors for + * given Tx queue, and enable the DMA channel used for that queue. + * Circular buffer (TFD queue in DRAM) physical base address */ + iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), + txq->q.dma_addr >> 8); + + return 0; +} + +/** + * iwl_trans_tx_alloc - allocate TX context + * Allocate all Tx DMA structures and initialize them + * + * @param priv + * @return error code + */ +static int iwl_trans_tx_alloc(struct iwl_priv *priv) +{ + int ret; + int txq_id, slots_num; + + /*It is not allowed to alloc twice, so warn when this happens. + * We cannot rely on the previous allocation, so free and fail */ + if (WARN_ON(priv->txq)) { + ret = -EINVAL; + goto error; + } + + ret = iwlagn_alloc_dma_ptr(priv, &priv->scd_bc_tbls, + priv->hw_params.scd_bc_tbls_size); + if (ret) { + IWL_ERR(priv, "Scheduler BC Table allocation failed\n"); + goto error; + } + + /* Alloc keep-warm buffer */ + ret = iwlagn_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE); + if (ret) { + IWL_ERR(priv, "Keep Warm allocation failed\n"); + goto error; + } + + priv->txq = kzalloc(sizeof(struct iwl_tx_queue) * + priv->cfg->base_params->num_of_queues, GFP_KERNEL); + if (!priv->txq) { + IWL_ERR(priv, "Not enough memory for txq\n"); + ret = ENOMEM; + goto error; + } + + /* Alloc and init all Tx queues, including the command queue (#4/#9) */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { + slots_num = (txq_id == priv->cmd_queue) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + ret = iwl_trans_txq_alloc(priv, &priv->txq[txq_id], slots_num, + txq_id); + if (ret) { + IWL_ERR(priv, "Tx %d queue alloc failed\n", txq_id); + goto error; + } + } + + return 0; + +error: + iwlagn_hw_txq_ctx_free(priv); + + return ret; +} +static int iwl_trans_tx_init(struct iwl_priv *priv) +{ + int ret; + int txq_id, slots_num; + unsigned long flags; + bool alloc = false; + + if (!priv->txq) { + ret = iwl_trans_tx_alloc(priv); + if (ret) + goto error; + alloc = true; + } + + spin_lock_irqsave(&priv->lock, flags); + + /* Turn off all Tx DMA fifos */ + iwl_write_prph(priv, IWLAGN_SCD_TXFACT, 0); + + /* Tell NIC where to find the "keep warm" buffer */ + iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Alloc and init all Tx queues, including the command queue (#4/#9) */ + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { + slots_num = (txq_id == priv->cmd_queue) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + ret = iwl_trans_txq_init(priv, &priv->txq[txq_id], slots_num, + txq_id); + if (ret) { + IWL_ERR(priv, "Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return 0; +error: + /*Upon error, free only if we allocated something */ + if (alloc) + iwlagn_hw_txq_ctx_free(priv); + return ret; +} + +static const struct iwl_trans_ops trans_ops = { + .rx_init = iwl_trans_rx_init, + .rx_free = iwl_trans_rx_free, + + .tx_init = iwl_trans_tx_init, +}; + +void iwl_trans_register(struct iwl_trans *trans) +{ + trans->ops = &trans_ops; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h new file mode 100644 index 000000000000..bec494c5a979 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2011 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. + * + * 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, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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. + * + *****************************************************************************/ + +void iwl_trans_register(struct iwl_trans *trans); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index fd8aee9972c1..db5abaa2ff7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -126,7 +126,7 @@ static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) } static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta, - struct iwl_tfd *tfd) + struct iwl_tfd *tfd, enum dma_data_direction dma_dir) { int i; int num_tbs; @@ -150,7 +150,7 @@ static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta, /* Unmap chunks, if any. */ for (i = 1; i < num_tbs; i++) dma_unmap_single(priv->bus.dev, iwl_tfd_tb_get_addr(tfd, i), - iwl_tfd_tb_get_len(tfd, i), DMA_TO_DEVICE); + iwl_tfd_tb_get_len(tfd, i), dma_dir); } /** @@ -166,7 +166,8 @@ void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) struct iwl_tfd *tfd_tmp = txq->tfds; int index = txq->q.read_ptr; - iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index]); + iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index], + DMA_TO_DEVICE); /* free SKB */ if (txq->txb) { @@ -219,24 +220,6 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv, return 0; } -/* - * Tell nic where to find circular buffer of Tx Frame Descriptors for - * given Tx queue, and enable the DMA channel used for that queue. - * - * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA - * channels supported in hardware. - */ -static int iwlagn_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) -{ - int txq_id = txq->q.id; - - /* Circular buffer (TFD queue in DRAM) physical base address */ - iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), - txq->q.dma_addr >> 8); - - return 0; -} - /** * iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's */ @@ -309,9 +292,7 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv) i = get_cmd_index(q, q->read_ptr); if (txq->meta[i].flags & CMD_MAPPED) { - dma_unmap_single(priv->bus.dev, - dma_unmap_addr(&txq->meta[i], mapping), - dma_unmap_len(&txq->meta[i], len), + iwlagn_unmap_tfd(priv, &txq->meta[i], &txq->tfds[i], DMA_BIDIRECTIONAL); txq->meta[i].flags = 0; } @@ -393,11 +374,10 @@ int iwl_queue_space(const struct iwl_queue *q) return s; } - /** * iwl_queue_init - Initialize queue's high/low-water and read/write indexes */ -static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, +int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, int count, int slots_num, u32 id) { q->n_bd = count; @@ -427,129 +407,6 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, return 0; } -/** - * iwl_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue - */ -static int iwl_tx_queue_alloc(struct iwl_priv *priv, - struct iwl_tx_queue *txq, u32 id) -{ - struct device *dev = priv->bus.dev; - size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX; - - /* Driver private data, only for Tx (not command) queues, - * not shared with device. */ - if (id != priv->cmd_queue) { - txq->txb = kzalloc(sizeof(txq->txb[0]) * - TFD_QUEUE_SIZE_MAX, GFP_KERNEL); - if (!txq->txb) { - IWL_ERR(priv, "kmalloc for auxiliary BD " - "structures failed\n"); - goto error; - } - } else { - txq->txb = NULL; - } - - /* Circular buffer of transmit frame descriptors (TFDs), - * shared with device */ - txq->tfds = dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr, - GFP_KERNEL); - if (!txq->tfds) { - IWL_ERR(priv, "dma_alloc_coherent(%zd) failed\n", tfd_sz); - goto error; - } - txq->q.id = id; - - return 0; - - error: - kfree(txq->txb); - txq->txb = NULL; - - return -ENOMEM; -} - -/** - * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue - */ -int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, - int slots_num, u32 txq_id) -{ - int i, len; - int ret; - - txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * slots_num, - GFP_KERNEL); - txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * slots_num, - GFP_KERNEL); - - if (!txq->meta || !txq->cmd) - goto out_free_arrays; - - len = sizeof(struct iwl_device_cmd); - for (i = 0; i < slots_num; i++) { - txq->cmd[i] = kmalloc(len, GFP_KERNEL); - if (!txq->cmd[i]) - goto err; - } - - /* Alloc driver data array and TFD circular buffer */ - ret = iwl_tx_queue_alloc(priv, txq, txq_id); - if (ret) - goto err; - - txq->need_update = 0; - - /* - * For the default queues 0-3, set up the swq_id - * already -- all others need to get one later - * (if they need one at all). - */ - if (txq_id < 4) - iwl_set_swq_id(txq, txq_id, txq_id); - - /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ - BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); - - /* Initialize queue's high/low-water marks, and head/tail indexes */ - ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); - if (ret) - return ret; - - /* Tell device where to find queue */ - iwlagn_tx_queue_init(priv, txq); - - return 0; -err: - for (i = 0; i < slots_num; i++) - kfree(txq->cmd[i]); -out_free_arrays: - kfree(txq->meta); - kfree(txq->cmd); - - return -ENOMEM; -} - -void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq, - int slots_num, u32 txq_id) -{ - int actual_slots = slots_num; - - if (txq_id == priv->cmd_queue) - actual_slots++; - - memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots); - - txq->need_update = 0; - - /* Initialize queue's high/low-water marks, and head/tail indexes */ - iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); - - /* Tell device where to find queue */ - iwlagn_tx_queue_init(priv, txq); -} - /*************** HOST COMMAND QUEUE FUNCTIONS *****/ /** @@ -699,10 +556,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) continue; phys_addr = dma_map_single(priv->bus.dev, (void *)cmd->data[i], - cmd->len[i], DMA_TO_DEVICE); + cmd->len[i], DMA_BIDIRECTIONAL); if (dma_mapping_error(priv->bus.dev, phys_addr)) { iwlagn_unmap_tfd(priv, out_meta, - &txq->tfds[q->write_ptr]); + &txq->tfds[q->write_ptr], + DMA_BIDIRECTIONAL); idx = -ENOMEM; goto out; } @@ -806,7 +664,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; - iwlagn_unmap_tfd(priv, meta, &txq->tfds[index]); + iwlagn_unmap_tfd(priv, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index d4005081f1df..2aa4de7cad24 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -585,7 +585,7 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) need_padding ^= ieee80211_has_a4(hdr->frame_control); need_padding ^= ieee80211_is_data_qos(hdr->frame_control) && (*ieee80211_get_qos_ctl(hdr) & - IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); + IEEE80211_QOS_CTL_A_MSDU_PRESENT); if (need_padding) { memmove(skb->data + 2, skb->data, skb->len); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 7e1fa9671277..031cd89b1768 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1130,6 +1130,8 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, for (i = 0; i < req->n_channels; i++) printk(KERN_DEBUG "hwsim hw_scan freq %d\n", req->channels[i]->center_freq); + print_hex_dump(KERN_DEBUG, "scan IEs: ", DUMP_PREFIX_OFFSET, + 16, 1, req->ie, req->ie_len, 1); ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 660831ce293c..4487d935654e 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -960,7 +960,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); if (sme->key) { - if (mwifiex_is_alg_wep(0) | mwifiex_is_alg_wep(0)) { + if (mwifiex_is_alg_wep(priv->sec_info.encryption_mode)) { dev_dbg(priv->adapter->dev, "info: setting wep encryption" " with key len %d\n", sme->key_len); @@ -1288,6 +1288,8 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, *(unsigned long *) wdev_priv = (unsigned long) priv; + set_wiphy_dev(wdev->wiphy, (struct device *) priv->adapter->dev); + ret = wiphy_register(wdev->wiphy); if (ret < 0) { dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 46d65e02c7ba..1bcf9eaa107d 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -27,8 +27,8 @@ static struct dentry *mwifiex_dfs_dir; static char *bss_modes[] = { "Unknown", - "Managed", "Ad-hoc", + "Managed", "Auto" }; diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 0e90b0986ed8..94ddc9038cb3 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -30,7 +30,9 @@ #define MWIFIEX_MAX_BSS_NUM (1) -#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */ +#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd) + * + 4 byte alignment + */ #define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 #define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index c925376fcaae..524f78f4ee69 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -54,10 +54,10 @@ #define SDIO_MP_AGGR_DEF_PKT_LIMIT 8 -#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ +#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (8192) /* 8K */ /* Multi port RX aggregation buffer size */ -#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ +#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (16384) /* 16K */ /* Misc. Config Register : Auto Re-enable interrupts */ #define AUTO_RE_ENABLE_INT BIT(4) diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index d85a0a60aa6a..49b9c1309f7a 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -779,6 +779,8 @@ static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd, case HostCmd_ACT_GEN_SET: if (enable) ibss_coal->enable = cpu_to_le16(*enable); + else + ibss_coal->enable = 0; break; /* In other case.. Nothing to do */ diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index ad64c87b91d6..6804239d87bd 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -183,30 +183,32 @@ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, */ static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - u32 *ul_temp) + u32 *data_buf) { struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; u16 oid = le16_to_cpu(smib->oid); u16 query_type = le16_to_cpu(smib->query_type); + u32 ul_temp; dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x," " query_type = %#x, buf size = %#x\n", oid, query_type, le16_to_cpu(smib->buf_size)); if (query_type == HostCmd_ACT_GEN_GET) { - if (ul_temp) - *ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); + ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); + if (data_buf) + *data_buf = ul_temp; switch (oid) { case FRAG_THRESH_I: dev_dbg(priv->adapter->dev, - "info: SNMP_RESP: FragThsd =%u\n", *ul_temp); + "info: SNMP_RESP: FragThsd =%u\n", ul_temp); break; case RTS_THRESH_I: dev_dbg(priv->adapter->dev, - "info: SNMP_RESP: RTSThsd =%u\n", *ul_temp); + "info: SNMP_RESP: RTSThsd =%u\n", ul_temp); break; case SHORT_RETRY_LIM_I: dev_dbg(priv->adapter->dev, - "info: SNMP_RESP: TxRetryCount=%u\n", *ul_temp); + "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp); break; default: break; @@ -622,22 +624,23 @@ static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, */ static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, - u16 *new_channel) + u16 *data_buf) { struct host_cmd_ds_802_11_rf_channel *rf_channel = &resp->params.rf_channel; + u16 new_channel = le16_to_cpu(rf_channel->current_channel); - if (new_channel) - *new_channel = le16_to_cpu(rf_channel->current_channel); - - if (priv->curr_bss_params.bss_descriptor.channel != *new_channel) { + if (priv->curr_bss_params.bss_descriptor.channel != new_channel) { dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n", priv->curr_bss_params.bss_descriptor.channel, - *new_channel); + new_channel); /* Update the channel again */ - priv->curr_bss_params.bss_descriptor.channel = *new_channel; + priv->curr_bss_params.bss_descriptor.channel = new_channel; } + if (data_buf) + *data_buf = new_channel; + return 0; } diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index fa6221bc9104..1822bfad8896 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -47,6 +47,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct txpd *local_tx_pd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + u8 pad; if (!skb->len) { dev_err(adapter->dev, "Tx: bad packet length: %d\n", @@ -55,15 +56,19 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, return skb->data; } - BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN)); - skb_push(skb, sizeof(*local_tx_pd)); + /* If skb->data is not aligned; add padding */ + pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4; + + BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN + + pad)); + skb_push(skb, sizeof(*local_tx_pd) + pad); local_tx_pd = (struct txpd *) skb->data; memset(local_tx_pd, 0, sizeof(struct txpd)); local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len - - sizeof(struct txpd))); + (sizeof(struct txpd) + pad))); local_tx_pd->priority = (u8) skb->priority; local_tx_pd->pkt_delay_2ms = @@ -88,7 +93,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, } /* Offset of actual data */ - local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) + pad); /* make space for INTF_HEADER_LEN */ skb_push(skb, INTF_HEADER_LEN); diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 32261189bcef..aeac3cc4dbe4 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2474,6 +2474,7 @@ struct mwl8k_cmd_set_hw_spec { * faster client. */ #define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 +#define MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR 0x00000200 #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 @@ -2510,7 +2511,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | - MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY); + MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY | + MWL8K_SET_HW_SPEC_FLAG_GENERATE_CCMP_HDR); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 937f9e8bf05f..76bcc3547976 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1723,6 +1723,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index d27d7b8ba3b6..c288d951c034 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -2016,6 +2016,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 15237c275486..53c5f878f61d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1827,6 +1827,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 5513edfa952a..5319ed921a88 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1031,6 +1031,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = { .flush = rt2x00mac_flush, .get_survey = rt2800_get_survey, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2800_ops rt2800pci_rt2800_ops = { @@ -1160,6 +1161,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { #endif #ifdef CONFIG_RT2800PCI_RT53XX { PCI_DEVICE(0x1814, 0x5390) }, + { PCI_DEVICE(0x1814, 0x539f) }, #endif { 0, } }; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 6e9229830a29..59e77797c0fa 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -757,6 +757,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .flush = rt2x00mac_flush, .get_survey = rt2800_get_survey, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2800_ops rt2800usb_rt2800_ops = { @@ -1020,6 +1021,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x0048) }, { USB_DEVICE(0x0df6, 0x0051) }, { USB_DEVICE(0x0df6, 0x005f) }, + { USB_DEVICE(0x0df6, 0x0060) }, /* SMC */ { USB_DEVICE(0x083a, 0x6618) }, { USB_DEVICE(0x083a, 0x7511) }, @@ -1076,6 +1078,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x148f, 0x3572) }, /* Sitecom */ { USB_DEVICE(0x0df6, 0x0041) }, + { USB_DEVICE(0x0df6, 0x0062) }, /* Toshiba */ { USB_DEVICE(0x0930, 0x0a07) }, /* Zinwell */ @@ -1174,8 +1177,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x004a) }, { USB_DEVICE(0x0df6, 0x004d) }, { USB_DEVICE(0x0df6, 0x0053) }, - { USB_DEVICE(0x0df6, 0x0060) }, - { USB_DEVICE(0x0df6, 0x0062) }, /* SMC */ { USB_DEVICE(0x083a, 0xa512) }, { USB_DEVICE(0x083a, 0xc522) }, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index c446db69bd3c..db435abbd57a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1276,6 +1276,7 @@ int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); +bool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw); /* * Driver allocation handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 1bb9d46077ff..1ca4c7ffc189 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -45,11 +45,11 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) } } -void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, +void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc) { - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key) diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 322cc4f3de5d..15cdc7e57fc4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -336,7 +336,8 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, */ #ifdef CONFIG_RT2X00_LIB_CRYPTO enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key); -void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, +void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc); unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 93bec140e598..8efab3983528 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -818,3 +818,17 @@ void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, *rx_max = rt2x00dev->rx->limit; } EXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam); + +bool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + + tx_queue_for_each(rt2x00dev, queue) { + if (!rt2x00queue_empty(queue)) + return true; + } + + return false; +} +EXPORT_SYMBOL_GPL(rt2x00mac_tx_frames_pending); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index c7fc9def6bcf..29edb9fbe6f1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -200,11 +200,12 @@ void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) skb_pull(skb, l2pad); } -static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, +static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc) { - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) @@ -212,7 +213,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); - if (!test_bit(REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->cap_flags)) + if (!test_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags)) return; /* @@ -237,12 +238,12 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, } -static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, +static void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc, const struct rt2x00_rate *hwrate) { - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; unsigned int data_length; unsigned int duration; @@ -259,8 +260,8 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, txdesc->u.plcp.ifs = IFS_SIFS; /* Data length + CRC + Crypto overhead (IV/EIV/ICV/MIC) */ - data_length = entry->skb->len + 4; - data_length += rt2x00crypto_tx_overhead(rt2x00dev, entry->skb); + data_length = skb->len + 4; + data_length += rt2x00crypto_tx_overhead(rt2x00dev, skb); /* * PLCP setup @@ -301,13 +302,14 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, } } -static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry, +static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc, const struct rt2x00_rate *hwrate) { - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (tx_info->control.sta) txdesc->u.ht.mpdu_density = @@ -380,12 +382,12 @@ static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry, txdesc->u.ht.txop = TXOP_HTTXOP; } -static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, +static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc) { - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; struct ieee80211_rate *rate; const struct rt2x00_rate *hwrate = NULL; @@ -395,8 +397,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Header and frame information. */ - txdesc->length = entry->skb->len; - txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); + txdesc->length = skb->len; + txdesc->header_length = ieee80211_get_hdrlen_from_skb(skb); /* * Check whether this frame is to be acked. @@ -471,13 +473,15 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Apply TX descriptor handling by components */ - rt2x00crypto_create_tx_descriptor(entry, txdesc); - rt2x00queue_create_tx_descriptor_seq(entry, txdesc); + rt2x00crypto_create_tx_descriptor(rt2x00dev, skb, txdesc); + rt2x00queue_create_tx_descriptor_seq(rt2x00dev, skb, txdesc); if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) - rt2x00queue_create_tx_descriptor_ht(entry, txdesc, hwrate); + rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc, + hwrate); else - rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); + rt2x00queue_create_tx_descriptor_plcp(rt2x00dev, skb, txdesc, + hwrate); } static int rt2x00queue_write_tx_data(struct queue_entry *entry, @@ -555,33 +559,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, bool local) { struct ieee80211_tx_info *tx_info; - struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); + struct queue_entry *entry; struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; u8 rate_idx, rate_flags; - - if (unlikely(rt2x00queue_full(queue))) { - ERROR(queue->rt2x00dev, - "Dropping frame due to full tx queue %d.\n", queue->qid); - return -ENOBUFS; - } - - if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, - &entry->flags))) { - ERROR(queue->rt2x00dev, - "Arrived at non-free entry in the non-full queue %d.\n" - "Please file bug report to %s.\n", - queue->qid, DRV_PROJECT); - return -EINVAL; - } + int ret = 0; /* * Copy all TX descriptor information into txdesc, * after that we are free to use the skb->cb array * for our information. */ - entry->skb = skb; - rt2x00queue_create_tx_descriptor(entry, &txdesc); + rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc); /* * All information is retrieved from the skb->cb array, @@ -593,7 +582,6 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, rate_flags = tx_info->control.rates[0].flags; skbdesc = get_skb_frame_desc(skb); memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->entry = entry; skbdesc->tx_rate_idx = rate_idx; skbdesc->tx_rate_flags = rate_flags; @@ -622,9 +610,33 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, * for PCI devices. */ if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags)) - rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length); + rt2x00queue_insert_l2pad(skb, txdesc.header_length); else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags)) - rt2x00queue_align_frame(entry->skb); + rt2x00queue_align_frame(skb); + + spin_lock(&queue->tx_lock); + + if (unlikely(rt2x00queue_full(queue))) { + ERROR(queue->rt2x00dev, + "Dropping frame due to full tx queue %d.\n", queue->qid); + ret = -ENOBUFS; + goto out; + } + + entry = rt2x00queue_get_entry(queue, Q_INDEX); + + if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, + &entry->flags))) { + ERROR(queue->rt2x00dev, + "Arrived at non-free entry in the non-full queue %d.\n" + "Please file bug report to %s.\n", + queue->qid, DRV_PROJECT); + ret = -EINVAL; + goto out; + } + + skbdesc->entry = entry; + entry->skb = skb; /* * It could be possible that the queue was corrupted and this @@ -634,7 +646,8 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) { clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); entry->skb = NULL; - return -EIO; + ret = -EIO; + goto out; } set_bit(ENTRY_DATA_PENDING, &entry->flags); @@ -643,7 +656,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, rt2x00queue_write_tx_descriptor(entry, &txdesc); rt2x00queue_kick_tx_queue(queue, &txdesc); - return 0; +out: + spin_unlock(&queue->tx_lock); + return ret; } int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev, @@ -697,7 +712,7 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, * after that we are free to use the skb->cb array * for our information. */ - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); + rt2x00queue_create_tx_descriptor(rt2x00dev, intf->beacon->skb, &txdesc); /* * Fill in skb descriptor @@ -1184,6 +1199,7 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, struct data_queue *queue, enum data_queue_qid qid) { mutex_init(&queue->status_lock); + spin_lock_init(&queue->tx_lock); spin_lock_init(&queue->index_lock); queue->rt2x00dev = rt2x00dev; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 167d45873dca..f2100f4ddcff 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -54,7 +54,7 @@ * @QID_RX: RX queue * @QID_OTHER: None of the above (don't use, only present for completeness) * @QID_BEACON: Beacon queue (value unspecified, don't send it to device) - * @QID_ATIM: Atim queue (value unspeficied, don't send it to device) + * @QID_ATIM: Atim queue (value unspecified, don't send it to device) */ enum data_queue_qid { QID_AC_VO = 0, @@ -432,6 +432,7 @@ enum data_queue_flags { * @flags: Entry flags, see &enum queue_entry_flags. * @status_lock: The mutex for protecting the start/stop/flush * handling on this queue. + * @tx_lock: Spinlock to serialize tx operations on this queue. * @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or * @index_crypt needs to be changed this lock should be grabbed to prevent * index corruption due to concurrency. @@ -458,6 +459,7 @@ struct data_queue { unsigned long flags; struct mutex status_lock; + spinlock_t tx_lock; spinlock_t index_lock; unsigned int count; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 9d35ec16a3a5..53110b83bf6e 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2982,6 +2982,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ad20953cbf05..6a93939f44e8 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2314,6 +2314,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index 5aee8b22d74e..45e14760c16e 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -21,6 +21,17 @@ config RTL8192SE If you choose to build it as a module, it will be called rtl8192se +config RTL8192DE + tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" + depends on MAC80211 && EXPERIMENTAL + select FW_LOADER + select RTLWIFI + ---help--- + This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe + wireless network adapters. + + If you choose to build it as a module, it will be called rtl8192de + config RTL8192CU tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" depends on MAC80211 && USB && EXPERIMENTAL @@ -35,10 +46,10 @@ config RTL8192CU config RTLWIFI tristate - depends on RTL8192CE || RTL8192CU || RTL8192SE + depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE default m config RTL8192C_COMMON tristate - depends on RTL8192CE || RTL8192CU || RTL8192SE + depends on RTL8192CE || RTL8192CU default m diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index 7acce83c3785..97935c565bab 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -23,5 +23,6 @@ obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/ obj-$(CONFIG_RTL8192CE) += rtl8192ce/ obj-$(CONFIG_RTL8192CU) += rtl8192cu/ obj-$(CONFIG_RTL8192SE) += rtl8192se/ +obj-$(CONFIG_RTL8192DE) += rtl8192de/ ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index ad39af462f87..5efd57833489 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -35,10 +35,10 @@ #include "efuse.h" static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { - INTEL_VENDOR_ID, - ATI_VENDOR_ID, - AMD_VENDOR_ID, - SIS_VENDOR_ID + PCI_VENDOR_ID_INTEL, + PCI_VENDOR_ID_ATI, + PCI_VENDOR_ID_AMD, + PCI_VENDOR_ID_SI }; static const u8 ac_to_hwq[] = { @@ -390,7 +390,7 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev, u8 linkctrl_reg; /*Link Control Register */ - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(pdev); pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg); pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg; @@ -788,15 +788,11 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) { struct ieee80211_hw *hw = dev_id; struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); unsigned long flags; u32 inta = 0; u32 intb = 0; - if (rtlpci->irq_enabled == 0) - return IRQ_HANDLED; - spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); /*read ISR: 4/8bytes */ @@ -1615,6 +1611,16 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, pci_read_config_byte(pdev, 0x8, &revisionid); pci_read_config_word(pdev, 0x3C, &irqline); + /* PCI ID 0x10ec:0x8192 occurs for both RTL8192E, which uses + * r8192e_pci, and RTL8192SE, which uses this driver. If the + * revision ID is RTL_PCI_REVISION_ID_8192PCIE (0x01), then + * the correct driver is r8192e_pci, thus this routine should + * return false. + */ + if (deviceid == RTL_PCI_8192SE_DID && + revisionid == RTL_PCI_REVISION_ID_8192PCIE) + return false; + if (deviceid == RTL_PCI_8192_DID || deviceid == RTL_PCI_0044_DID || deviceid == RTL_PCI_0047_DID || @@ -1847,7 +1853,8 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, pci_write_config_byte(pdev, 0x04, 0x07); /* find adapter */ - _rtl_pci_find_adapter(pdev, hw); + if (!_rtl_pci_find_adapter(pdev, hw)) + goto fail3; /* Init IO handler */ _rtl_pci_io_handler_init(&pdev->dev, hw); diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 671b1f5aa0cf..c53c62046747 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -62,12 +62,6 @@ .subdevice = PCI_ANY_ID,\ .driver_data = (kernel_ulong_t)&(cfg) -#define INTEL_VENDOR_ID 0x8086 -#define SIS_VENDOR_ID 0x1039 -#define ATI_VENDOR_ID 0x1002 -#define ATI_DEVICE_ID 0x7914 -#define AMD_VENDOR_ID 0x1022 - #define PCI_MAX_BRIDGE_NUMBER 255 #define PCI_MAX_DEVICES 32 #define PCI_MAX_FUNCTION 8 @@ -75,11 +69,6 @@ #define PCI_CONF_ADDRESS 0x0CF8 /*PCI Configuration Space Address */ #define PCI_CONF_DATA 0x0CFC /*PCI Configuration Space Data */ -#define PCI_CLASS_BRIDGE_DEV 0x06 -#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04 -#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10 -#define PCI_CAP_ID_EXP 0x10 - #define U1DONTCARE 0xFF #define U2DONTCARE 0xFFFF #define U4DONTCARE 0xFFFFFFFF @@ -169,7 +158,6 @@ struct rtl_pci { bool first_init; bool being_init_adapter; bool init_ready; - bool irq_enabled; /*Tx */ struct rtl8192_tx_ring tx_ring[RTL_PCI_MAX_TX_QUEUE_COUNT]; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index bc6ae9dcf940..9e2a9e34a699 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -1183,7 +1183,6 @@ void rtl92ce_enable_interrupt(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); - rtlpci->irq_enabled = true; } void rtl92ce_disable_interrupt(struct ieee80211_hw *hw) @@ -1193,7 +1192,6 @@ void rtl92ce_disable_interrupt(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED); rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); - rtlpci->irq_enabled = false; synchronize_irq(rtlpci->pdev->irq); } diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h index 598cecc63f41..72a3d5497547 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h @@ -1203,7 +1203,9 @@ #define EPROM_CMD_CONFIG 0x3 #define EPROM_CMD_LOAD 1 +#define HWSET_MAX_SIZE 128 #define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE +#define EFUSE_MAX_SECTION 16 #define WL_HWPDN_EN BIT(0) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 4e057df6f488..a90c09b42390 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -380,13 +380,11 @@ void rtl92c_enable_interrupt(struct ieee80211_hw *hw) 0xFFFFFFFF); rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); - rtlpci->irq_enabled = true; } else { rtl_write_dword(rtlpriv, REG_HIMR, rtlusb->irq_mask[0] & 0xFFFFFFFF); rtl_write_dword(rtlpriv, REG_HIMRE, rtlusb->irq_mask[1] & 0xFFFFFFFF); - rtlusb->irq_enabled = true; } } @@ -398,16 +396,9 @@ void rtl92c_init_interrupt(struct ieee80211_hw *hw) void rtl92c_disable_interrupt(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED); rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); - if (IS_HARDWARE_TYPE_8192CE(rtlhal)) - rtlpci->irq_enabled = false; - else if (IS_HARDWARE_TYPE_8192CU(rtlhal)) - rtlusb->irq_enabled = false; } void rtl92c_set_qos(struct ieee80211_hw *hw, int aci) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index bee7c1480f63..942f7a3969a7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -53,6 +53,8 @@ MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin"); static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + const struct firmware *firmware; + int err; rtlpriv->dm.dm_initialgain_enable = 1; rtlpriv->dm.dm_flag = 0; @@ -64,6 +66,24 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) ("Can't alloc buffer for fw.\n")); return 1; } + /* request fw */ + err = request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Failed to request firmware!\n")); + return 1; + } + if (firmware->size > 0x4000) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is too big!\n")); + release_firmware(firmware); + return 1; + } + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + release_firmware(firmware); + return 0; } @@ -278,6 +298,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ + {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ {RTL_USB_DEVICE(0x0Df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/ /* HP - Lite-On ,8188CUS Slim Combo */ diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/Makefile b/drivers/net/wireless/rtlwifi/rtl8192de/Makefile new file mode 100644 index 000000000000..e3213c8264b6 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/Makefile @@ -0,0 +1,14 @@ +rtl8192de-objs := \ + dm.o \ + fw.o \ + hw.o \ + led.o \ + phy.o \ + rf.o \ + sw.o \ + table.o \ + trx.o + +obj-$(CONFIG_RTL8192DE) += rtl8192de.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/def.h b/drivers/net/wireless/rtlwifi/rtl8192de/def.h new file mode 100644 index 000000000000..f0f5f9bfbb7b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/def.h @@ -0,0 +1,269 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92D_DEF_H__ +#define __RTL92D_DEF_H__ + +/* Min Spacing related settings. */ +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +#define RF6052_MAX_TX_PWR 0x3F +#define RF6052_MAX_REG 0x3F +#define RF6052_MAX_PATH 2 + +#define HAL_RETRY_LIMIT_INFRA 48 +#define HAL_RETRY_LIMIT_AP_ADHOC 7 + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 +#define PHY_BEACON_RSSI_SLID_WIN_MAX 10 + +#define RESET_DELAY_8185 20 + +#define RT_IBSS_INT_MASKS (IMR_BCNINT | IMR_TBDOK | IMR_TBDER) +#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK) + +#define NUM_OF_FIRMWARE_QUEUE 10 +#define NUM_OF_PAGES_IN_FW 0x100 +#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x2 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xA1 + +#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00 + +#define MAX_LINES_HWCONFIG_TXT 1000 +#define MAX_BYTES_LINE_HWCONFIG_TXT 256 + +#define SW_THREE_WIRE 0 +#define HW_THREE_WIRE 2 + +#define BT_DEMO_BOARD 0 +#define BT_QA_BOARD 1 +#define BT_FPGA 2 + +#define RX_SMOOTH_FACTOR 20 + +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 + +#define MAX_H2C_QUEUE_NUM 10 + +#define RX_MPDU_QUEUE 0 +#define RX_CMD_QUEUE 1 +#define RX_MAX_QUEUE 2 + +#define C2H_RX_CMD_HDR_LEN 8 +#define GET_C2H_CMD_CMD_LEN(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 0, 16) +#define GET_C2H_CMD_ELEMENT_ID(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 16, 8) +#define GET_C2H_CMD_CMD_SEQ(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 24, 7) +#define GET_C2H_CMD_CONTINUE(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 31, 1) +#define GET_C2H_CMD_CONTENT(__prxhdr) \ + ((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN) + +#define GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16) +#define GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4) +#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12) + +/* + * 92D chip ver: + * BIT8: IS 92D + * BIT9: single phy + * BIT10: C-cut + * BIT11: D-cut + */ + +/* Chip specific */ +#define CHIP_92C BIT(0) +#define CHIP_92C_1T2R BIT(1) +#define CHIP_8723 BIT(2) /* RTL8723 With BT feature */ +#define CHIP_8723_DRV_REV BIT(3) /* RTL8723 Driver Revised */ +#define NORMAL_CHIP BIT(4) +#define CHIP_VENDOR_UMC BIT(5) +#define CHIP_VENDOR_UMC_B_CUT BIT(6) /* Chip version for ECO */ + +/* for 92D */ +#define CHIP_92D BIT(8) +#define CHIP_92D_SINGLEPHY BIT(9) +#define CHIP_92D_C_CUT BIT(10) +#define CHIP_92D_D_CUT BIT(11) + +enum version_8192d { + VERSION_TEST_CHIP_88C = 0x00, + VERSION_TEST_CHIP_92C = 0x01, + VERSION_NORMAL_TSMC_CHIP_88C = 0x10, + VERSION_NORMAL_TSMC_CHIP_92C = 0x11, + VERSION_NORMAL_TSMC_CHIP_92C_1T2R = 0x13, + VERSION_NORMAL_UMC_CHIP_88C_A_CUT = 0x30, + VERSION_NORMAL_UMC_CHIP_92C_A_CUT = 0x31, + VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT = 0x33, + VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT = 0x34, + VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT = 0x3c, + VERSION_NORMAL_UMC_CHIP_88C_B_CUT = 0x70, + VERSION_NORMAL_UMC_CHIP_92C_B_CUT = 0x71, + VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT = 0x73, + VERSION_TEST_CHIP_92D_SINGLEPHY = 0x300, + VERSION_TEST_CHIP_92D_DUALPHY = 0x100, + VERSION_NORMAL_CHIP_92D_SINGLEPHY = 0x310, + VERSION_NORMAL_CHIP_92D_DUALPHY = 0x110, + VERSION_NORMAL_CHIP_92D_C_CUT_SINGLEPHY = 0x710, + VERSION_NORMAL_CHIP_92D_C_CUT_DUALPHY = 0x510, + VERSION_NORMAL_CHIP_92D_D_CUT_SINGLEPHY = 0xB10, + VERSION_NORMAL_CHIP_92D_D_CUT_DUALPHY = 0x910, +}; + +#define IS_92D_SINGLEPHY(version) \ + ((version & CHIP_92D_SINGLEPHY) ? true : false) +#define IS_92D_C_CUT(version) \ + ((version & CHIP_92D_C_CUT) ? true : false) +#define IS_92D_D_CUT(version) \ + ((version & CHIP_92D_D_CUT) ? true : false) + +enum rf_optype { + RF_OP_BY_SW_3WIRE = 0, + RF_OP_BY_FW, + RF_OP_MAX +}; + +enum rtl_desc_qsel { + QSLT_BK = 0x2, + QSLT_BE = 0x0, + QSLT_VI = 0x5, + QSLT_VO = 0x7, + QSLT_BEACON = 0x10, + QSLT_HIGH = 0x11, + QSLT_MGNT = 0x12, + QSLT_CMD = 0x13, +}; + +enum rtl_desc92d_rate { + DESC92D_RATE1M = 0x00, + DESC92D_RATE2M = 0x01, + DESC92D_RATE5_5M = 0x02, + DESC92D_RATE11M = 0x03, + + DESC92D_RATE6M = 0x04, + DESC92D_RATE9M = 0x05, + DESC92D_RATE12M = 0x06, + DESC92D_RATE18M = 0x07, + DESC92D_RATE24M = 0x08, + DESC92D_RATE36M = 0x09, + DESC92D_RATE48M = 0x0a, + DESC92D_RATE54M = 0x0b, + + DESC92D_RATEMCS0 = 0x0c, + DESC92D_RATEMCS1 = 0x0d, + DESC92D_RATEMCS2 = 0x0e, + DESC92D_RATEMCS3 = 0x0f, + DESC92D_RATEMCS4 = 0x10, + DESC92D_RATEMCS5 = 0x11, + DESC92D_RATEMCS6 = 0x12, + DESC92D_RATEMCS7 = 0x13, + DESC92D_RATEMCS8 = 0x14, + DESC92D_RATEMCS9 = 0x15, + DESC92D_RATEMCS10 = 0x16, + DESC92D_RATEMCS11 = 0x17, + DESC92D_RATEMCS12 = 0x18, + DESC92D_RATEMCS13 = 0x19, + DESC92D_RATEMCS14 = 0x1a, + DESC92D_RATEMCS15 = 0x1b, + DESC92D_RATEMCS15_SG = 0x1c, + DESC92D_RATEMCS32 = 0x20, +}; + +enum channel_plan { + CHPL_FCC = 0, + CHPL_IC = 1, + CHPL_ETSI = 2, + CHPL_SPAIN = 3, + CHPL_FRANCE = 4, + CHPL_MKK = 5, + CHPL_MKK1 = 6, + CHPL_ISRAEL = 7, + CHPL_TELEC = 8, + CHPL_GLOBAL = 9, + CHPL_WORLD = 10, +}; + +struct phy_sts_cck_8192d { + u8 adc_pwdb_X[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + +struct h2c_cmd_8192c { + u8 element_id; + u32 cmd_len; + u8 *p_cmdbuffer; +}; + +struct txpower_info { + u8 cck_index[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht40_1sindex[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht40_2sindexdiff[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht20indexdiff[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ofdmindexdiff[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht40maxoffset[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 ht20maxoffset[RF6052_MAX_PATH][CHANNEL_GROUP_MAX]; + u8 tssi_a[3]; /* 5GL/5GM/5GH */ + u8 tssi_b[3]; +}; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c new file mode 100644 index 000000000000..3cd0736fe8e1 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -0,0 +1,1355 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" + +#define UNDEC_SM_PWDB entry_min_undecoratedsmoothed_pwdb + +struct dig_t de_digtable; + +static const u32 ofdmswing_table[OFDM_TABLE_SIZE_92D] = { + 0x7f8001fe, /* 0, +6.0dB */ + 0x788001e2, /* 1, +5.5dB */ + 0x71c001c7, /* 2, +5.0dB */ + 0x6b8001ae, /* 3, +4.5dB */ + 0x65400195, /* 4, +4.0dB */ + 0x5fc0017f, /* 5, +3.5dB */ + 0x5a400169, /* 6, +3.0dB */ + 0x55400155, /* 7, +2.5dB */ + 0x50800142, /* 8, +2.0dB */ + 0x4c000130, /* 9, +1.5dB */ + 0x47c0011f, /* 10, +1.0dB */ + 0x43c0010f, /* 11, +0.5dB */ + 0x40000100, /* 12, +0dB */ + 0x3c8000f2, /* 13, -0.5dB */ + 0x390000e4, /* 14, -1.0dB */ + 0x35c000d7, /* 15, -1.5dB */ + 0x32c000cb, /* 16, -2.0dB */ + 0x300000c0, /* 17, -2.5dB */ + 0x2d4000b5, /* 18, -3.0dB */ + 0x2ac000ab, /* 19, -3.5dB */ + 0x288000a2, /* 20, -4.0dB */ + 0x26000098, /* 21, -4.5dB */ + 0x24000090, /* 22, -5.0dB */ + 0x22000088, /* 23, -5.5dB */ + 0x20000080, /* 24, -6.0dB */ + 0x1e400079, /* 25, -6.5dB */ + 0x1c800072, /* 26, -7.0dB */ + 0x1b00006c, /* 27. -7.5dB */ + 0x19800066, /* 28, -8.0dB */ + 0x18000060, /* 29, -8.5dB */ + 0x16c0005b, /* 30, -9.0dB */ + 0x15800056, /* 31, -9.5dB */ + 0x14400051, /* 32, -10.0dB */ + 0x1300004c, /* 33, -10.5dB */ + 0x12000048, /* 34, -11.0dB */ + 0x11000044, /* 35, -11.5dB */ + 0x10000040, /* 36, -12.0dB */ + 0x0f00003c, /* 37, -12.5dB */ + 0x0e400039, /* 38, -13.0dB */ + 0x0d800036, /* 39, -13.5dB */ + 0x0cc00033, /* 40, -14.0dB */ + 0x0c000030, /* 41, -14.5dB */ + 0x0b40002d, /* 42, -15.0dB */ +}; + +static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */ + {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */ + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */ + {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */ + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */ + {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */ + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */ + {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */ + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */ + {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */ + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */ + {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */ + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB */ + {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */ + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */ + {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */ + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ + {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */ + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */ + {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */ + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB */ + {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB */ + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB */ + {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB */ + {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB */ + {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB */ + {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB */ + {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB */ + {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB */ + {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB */ + {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB */ + {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB */ + {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB */ +}; + +static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */ + {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */ + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */ + {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */ + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */ + {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */ + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */ + {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */ + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */ + {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */ + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */ + {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */ + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB */ + {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */ + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */ + {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */ + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ + {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */ + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */ + {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */ + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB */ + {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB */ + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB */ + {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB */ + {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB */ + {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB */ + {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB */ + {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB */ + {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB */ + {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB */ + {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB */ + {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB */ + {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ +}; + +static void rtl92d_dm_diginit(struct ieee80211_hw *hw) +{ + de_digtable.dig_enable_flag = true; + de_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + de_digtable.cur_igvalue = 0x20; + de_digtable.pre_igvalue = 0x0; + de_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + de_digtable.presta_connectstate = DIG_STA_DISCONNECT; + de_digtable.curmultista_connectstate = DIG_MULTISTA_DISCONNECT; + de_digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; + de_digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; + de_digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + de_digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + de_digtable.rx_gain_range_max = DM_DIG_FA_UPPER; + de_digtable.rx_gain_range_min = DM_DIG_FA_LOWER; + de_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; + de_digtable.backoff_val_range_max = DM_DIG_BACKOFF_MAX; + de_digtable.backoff_val_range_min = DM_DIG_BACKOFF_MIN; + de_digtable.pre_cck_pd_state = CCK_PD_STAGE_LOWRSSI; + de_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX; + de_digtable.large_fa_hit = 0; + de_digtable.recover_cnt = 0; + de_digtable.forbidden_igi = DM_DIG_FA_LOWER; +} + +static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) +{ + u32 ret_value; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + unsigned long flag = 0; + + /* hold ofdm counter */ + rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 1); /* hold page C counter */ + rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 1); /*hold page D counter */ + + ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, BMASKDWORD); + falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff); + falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, BMASKDWORD); + falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, BMASKDWORD); + falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); + falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, BMASKDWORD); + falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); + falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + + falsealm_cnt->cnt_rate_illegal + + falsealm_cnt->cnt_crc8_fail + + falsealm_cnt->cnt_mcs_fail + + falsealm_cnt->cnt_fast_fsync_fail + + falsealm_cnt->cnt_sb_search_fail; + + if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) { + /* hold cck counter */ + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, BMASKBYTE0); + falsealm_cnt->cnt_cck_fail = ret_value; + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, BMASKBYTE3); + falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } else { + falsealm_cnt->cnt_cck_fail = 0; + } + + /* reset false alarm counter registers */ + falsealm_cnt->cnt_all = falsealm_cnt->cnt_fast_fsync_fail + + falsealm_cnt->cnt_sb_search_fail + + falsealm_cnt->cnt_parity_fail + + falsealm_cnt->cnt_rate_illegal + + falsealm_cnt->cnt_crc8_fail + + falsealm_cnt->cnt_mcs_fail + + falsealm_cnt->cnt_cck_fail; + + rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 1); + /* update ofdm counter */ + rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 0); + /* update page C counter */ + rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 0); + /* update page D counter */ + rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 0); + if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) { + /* reset cck counter */ + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 0); + /* enable cck counter */ + rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 2); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("Cnt_Fast_Fsync_fail = %x, " + "Cnt_SB_Search_fail = %x\n", + falsealm_cnt->cnt_fast_fsync_fail, + falsealm_cnt->cnt_sb_search_fail)); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("Cnt_Parity_Fail = %x, " + "Cnt_Rate_Illegal = %x, Cnt_Crc8_fail = %x, " + "Cnt_Mcs_fail = %x\n", + falsealm_cnt->cnt_parity_fail, + falsealm_cnt->cnt_rate_illegal, + falsealm_cnt->cnt_crc8_fail, + falsealm_cnt->cnt_mcs_fail)); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + ("Cnt_Ofdm_fail = %x, " "Cnt_Cck_fail = %x, " + "Cnt_all = %x\n", + falsealm_cnt->cnt_ofdm_fail, + falsealm_cnt->cnt_cck_fail, + falsealm_cnt->cnt_all)); +} + +static void rtl92d_dm_find_minimum_rssi(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtlpriv); + + /* Determine the minimum RSSI */ + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.UNDEC_SM_PWDB == 0)) { + de_digtable.min_undecorated_pwdb_for_dm = 0; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + ("Not connected to any\n")); + } + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + de_digtable.min_undecorated_pwdb_for_dm = + rtlpriv->dm.UNDEC_SM_PWDB; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + ("AP Client PWDB = 0x%lx\n", + rtlpriv->dm.UNDEC_SM_PWDB)); + } else { + de_digtable.min_undecorated_pwdb_for_dm = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + ("STA Default Port PWDB = 0x%x\n", + de_digtable.min_undecorated_pwdb_for_dm)); + } + } else { + de_digtable.min_undecorated_pwdb_for_dm = + rtlpriv->dm.UNDEC_SM_PWDB; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + ("AP Ext Port or disconnet PWDB = 0x%x\n", + de_digtable.min_undecorated_pwdb_for_dm)); + } + + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n", + de_digtable.min_undecorated_pwdb_for_dm)); +} + +static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned long flag = 0; + + if (de_digtable.cursta_connectctate == DIG_STA_CONNECT) { + if (de_digtable.pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { + if (de_digtable.min_undecorated_pwdb_for_dm <= 25) + de_digtable.cur_cck_pd_state = + CCK_PD_STAGE_LOWRSSI; + else + de_digtable.cur_cck_pd_state = + CCK_PD_STAGE_HIGHRSSI; + } else { + if (de_digtable.min_undecorated_pwdb_for_dm <= 20) + de_digtable.cur_cck_pd_state = + CCK_PD_STAGE_LOWRSSI; + else + de_digtable.cur_cck_pd_state = + CCK_PD_STAGE_HIGHRSSI; + } + } else { + de_digtable.cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI; + } + if (de_digtable.pre_cck_pd_state != de_digtable.cur_cck_pd_state) { + if (de_digtable.cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0x83); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } else { + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0xcd); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } + de_digtable.pre_cck_pd_state = de_digtable.cur_cck_pd_state; + } + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("CurSTAConnectState=%s\n", + (de_digtable.cursta_connectctate == DIG_STA_CONNECT ? + "DIG_STA_CONNECT " : "DIG_STA_DISCONNECT"))); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("CCKPDStage=%s\n", + (de_digtable.cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI ? + "Low RSSI " : "High RSSI "))); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("is92d single phy =%x\n", + IS_92D_SINGLEPHY(rtlpriv->rtlhal.version))); + +} + +void rtl92d_dm_write_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("cur_igvalue = 0x%x, " + "pre_igvalue = 0x%x, backoff_val = %d\n", + de_digtable.cur_igvalue, de_digtable.pre_igvalue, + de_digtable.backoff_val)); + if (de_digtable.dig_enable_flag == false) { + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("DIG is disabled\n")); + de_digtable.pre_igvalue = 0x17; + return; + } + if (de_digtable.pre_igvalue != de_digtable.cur_igvalue) { + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, + de_digtable.cur_igvalue); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, + de_digtable.cur_igvalue); + de_digtable.pre_igvalue = de_digtable.cur_igvalue; + } +} + +static void rtl92d_early_mode_enabled(struct rtl_priv *rtlpriv) +{ + if ((rtlpriv->mac80211.link_state >= MAC80211_LINKED) && + (rtlpriv->mac80211.vendor == PEER_CISCO)) { + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + ("IOT_PEER = CISCO\n")); + if (de_digtable.last_min_undecorated_pwdb_for_dm >= 50 + && de_digtable.min_undecorated_pwdb_for_dm < 50) { + rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x00); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + ("Early Mode Off\n")); + } else if (de_digtable.last_min_undecorated_pwdb_for_dm <= 55 && + de_digtable.min_undecorated_pwdb_for_dm > 55) { + rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x0f); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + ("Early Mode On\n")); + } + } else if (!(rtl_read_byte(rtlpriv, REG_EARLY_MODE_CONTROL) & 0xf)) { + rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x0f); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("Early Mode On\n")); + } +} + +static void rtl92d_dm_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value_igi = de_digtable.cur_igvalue; + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("==>\n")); + if (rtlpriv->rtlhal.earlymode_enable) { + rtl92d_early_mode_enabled(rtlpriv); + de_digtable.last_min_undecorated_pwdb_for_dm = + de_digtable.min_undecorated_pwdb_for_dm; + } + if (rtlpriv->dm.dm_initialgain_enable == false) + return; + + /* because we will send data pkt when scanning + * this will cause some ap like gear-3700 wep TP + * lower if we retrun here, this is the diff of + * mac80211 driver vs ieee80211 driver */ + /* if (rtlpriv->mac80211.act_scanning) + * return; */ + + /* Not STA mode return tmp */ + if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) + return; + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("progress\n")); + /* Decide the current status and if modify initial gain or not */ + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) + de_digtable.cursta_connectctate = DIG_STA_CONNECT; + else + de_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + + /* adjust initial gain according to false alarm counter */ + if (falsealm_cnt->cnt_all < DM_DIG_FA_TH0) + value_igi--; + else if (falsealm_cnt->cnt_all < DM_DIG_FA_TH1) + value_igi += 0; + else if (falsealm_cnt->cnt_all < DM_DIG_FA_TH2) + value_igi++; + else if (falsealm_cnt->cnt_all >= DM_DIG_FA_TH2) + value_igi += 2; + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + ("dm_DIG() Before: large_fa_hit=%d, forbidden_igi=%x\n", + de_digtable.large_fa_hit, de_digtable.forbidden_igi)); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + ("dm_DIG() Before: Recover_cnt=%d, rx_gain_range_min=%x\n", + de_digtable.recover_cnt, de_digtable.rx_gain_range_min)); + + /* deal with abnorally large false alarm */ + if (falsealm_cnt->cnt_all > 10000) { + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + ("dm_DIG(): Abnornally false alarm case.\n")); + + de_digtable.large_fa_hit++; + if (de_digtable.forbidden_igi < de_digtable.cur_igvalue) { + de_digtable.forbidden_igi = de_digtable.cur_igvalue; + de_digtable.large_fa_hit = 1; + } + if (de_digtable.large_fa_hit >= 3) { + if ((de_digtable.forbidden_igi + 1) > DM_DIG_MAX) + de_digtable.rx_gain_range_min = DM_DIG_MAX; + else + de_digtable.rx_gain_range_min = + (de_digtable.forbidden_igi + 1); + de_digtable.recover_cnt = 3600; /* 3600=2hr */ + } + } else { + /* Recovery mechanism for IGI lower bound */ + if (de_digtable.recover_cnt != 0) { + de_digtable.recover_cnt--; + } else { + if (de_digtable.large_fa_hit == 0) { + if ((de_digtable.forbidden_igi - 1) < + DM_DIG_FA_LOWER) { + de_digtable.forbidden_igi = + DM_DIG_FA_LOWER; + de_digtable.rx_gain_range_min = + DM_DIG_FA_LOWER; + + } else { + de_digtable.forbidden_igi--; + de_digtable.rx_gain_range_min = + (de_digtable.forbidden_igi + 1); + } + } else if (de_digtable.large_fa_hit == 3) { + de_digtable.large_fa_hit = 0; + } + } + } + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + ("dm_DIG() After: large_fa_hit=%d, forbidden_igi=%x\n", + de_digtable.large_fa_hit, de_digtable.forbidden_igi)); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, + ("dm_DIG() After: recover_cnt=%d, rx_gain_range_min=%x\n", + de_digtable.recover_cnt, de_digtable.rx_gain_range_min)); + + if (value_igi > DM_DIG_MAX) + value_igi = DM_DIG_MAX; + else if (value_igi < de_digtable.rx_gain_range_min) + value_igi = de_digtable.rx_gain_range_min; + de_digtable.cur_igvalue = value_igi; + rtl92d_dm_write_dig(hw); + if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) + rtl92d_dm_cck_packet_detection_thresh(hw); + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, ("<<==\n")); +} + +static void rtl92d_dm_init_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dynamic_txpower_enable = true; + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +} + +static void rtl92d_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if ((!rtlpriv->dm.dynamic_txpower_enable) + || rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.UNDEC_SM_PWDB == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("Not connected to any\n")); + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.UNDEC_SM_PWDB; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("IBSS Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.UNDEC_SM_PWDB; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + if (rtlhal->current_bandtype == BAND_ON_5G) { + if (undecorated_smoothed_pwdb >= 0x33) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_LEVEL2; + RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD, + ("5G:TxHighPwrLevel_Level2 (TxPwr=0x0)\n")); + } else if ((undecorated_smoothed_pwdb < 0x33) + && (undecorated_smoothed_pwdb >= 0x2b)) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD, + ("5G:TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); + } else if (undecorated_smoothed_pwdb < 0x2b) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_HIPWR, DBG_LOUD, + ("5G:TxHighPwrLevel_Normal\n")); + } + } else { + if (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL2) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_LEVEL2; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n")); + } else + if ((undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) + && (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL1)) { + + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n")); + } else if (undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_NORMAL\n")); + } + } + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("PHY_SetTxPowerLevel8192S() Channel = %d\n", + rtlphy->current_channel)); + rtl92d_phy_set_txpower_level(hw, rtlphy->current_channel); + } + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + +static void rtl92d_dm_pwdb_monitor(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* AP & ADHOC & MESH will return tmp */ + if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) + return; + /* Indicate Rx signal strength to FW. */ + if (rtlpriv->dm.useramask) { + u32 temp = rtlpriv->dm.undecorated_smoothed_pwdb; + + temp <<= 16; + temp |= 0x100; + /* fw v12 cmdid 5:use max macid ,for nic , + * default macid is 0 ,max macid is 1 */ + rtl92d_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, (u8 *) (&temp)); + } else { + rtl_write_byte(rtlpriv, 0x4fe, + (u8) rtlpriv->dm.undecorated_smoothed_pwdb); + } +} + +void rtl92d_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.current_turbo_edca = false; + rtlpriv->dm.is_any_nonbepkts = false; + rtlpriv->dm.is_cur_rdlstate = false; +} + +static void rtl92d_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + static u64 last_txok_cnt; + static u64 last_rxok_cnt; + u64 cur_txok_cnt; + u64 cur_rxok_cnt; + u32 edca_be_ul = 0x5ea42b; + u32 edca_be_dl = 0x5ea42b; + + if (mac->link_state != MAC80211_LINKED) { + rtlpriv->dm.current_turbo_edca = false; + goto exit; + } + + /* Enable BEQ TxOP limit configuration in wireless G-mode. */ + /* To check whether we shall force turn on TXOP configuration. */ + if ((!rtlpriv->dm.disable_framebursting) && + (rtlpriv->sec.pairwise_enc_algorithm == WEP40_ENCRYPTION || + rtlpriv->sec.pairwise_enc_algorithm == WEP104_ENCRYPTION || + rtlpriv->sec.pairwise_enc_algorithm == TKIP_ENCRYPTION)) { + /* Force TxOP limit to 0x005e for UL. */ + if (!(edca_be_ul & 0xffff0000)) + edca_be_ul |= 0x005e0000; + /* Force TxOP limit to 0x005e for DL. */ + if (!(edca_be_dl & 0xffff0000)) + edca_be_dl |= 0x005e0000; + } + + if ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting)) { + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; + cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + if (cur_rxok_cnt > 4 * cur_txok_cnt) { + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, + edca_be_dl); + rtlpriv->dm.is_cur_rdlstate = true; + } + } else { + if (rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, + edca_be_ul); + rtlpriv->dm.is_cur_rdlstate = false; + } + } + rtlpriv->dm.current_turbo_edca = true; + } else { + if (rtlpriv->dm.current_turbo_edca) { + u8 tmp = AC0_BE; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, + (u8 *) (&tmp)); + rtlpriv->dm.current_turbo_edca = false; + } + } + +exit: + rtlpriv->dm.is_any_nonbepkts = false; + last_txok_cnt = rtlpriv->stats.txbytesunicast; + last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void rtl92d_dm_rxgain_tracking_thermalmeter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 index_mapping[RX_INDEX_MAPPING_NUM] = { + 0x0f, 0x0f, 0x0d, 0x0c, 0x0b, + 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x04, 0x03, 0x02 + }; + int i; + u32 u4tmp; + + u4tmp = (index_mapping[(rtlpriv->efuse.eeprom_thermalmeter - + rtlpriv->dm.thermalvalue_rxgain)]) << 12; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("===> Rx Gain %x\n", u4tmp)); + for (i = RF90_PATH_A; i < rtlpriv->phy.num_total_rfpath; i++) + rtl_set_rfreg(hw, i, 0x3C, BRFREGOFFSETMASK, + (rtlpriv->phy.reg_rf3c[i] & (~(0xF000))) | u4tmp); +} + +static void rtl92d_bandtype_2_4G(struct ieee80211_hw *hw, long *temp_cckg, + u8 *cck_index_old) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + unsigned long flag = 0; + long temp_cck; + + /* Query CCK default setting From 0xa24 */ + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + temp_cck = rtl_get_bbreg(hw, RCCK0_TXFILTER2, + BMASKDWORD) & BMASKCCK; + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + for (i = 0; i < CCK_TABLE_LENGTH; i++) { + if (rtlpriv->dm.cck_inch14) { + if (!memcmp((void *)&temp_cck, + (void *)&cckswing_table_ch14[i][2], 4)) { + *cck_index_old = (u8) i; + RT_TRACE(rtlpriv, + COMP_POWER_TRACKING, + DBG_LOUD, + ("Initial reg0x%x = 0x%lx, " + "cck_index=0x%x, ch 14 %d\n", + RCCK0_TXFILTER2, + temp_cck, *cck_index_old, + rtlpriv->dm.cck_inch14)); + break; + } + } else { + if (!memcmp((void *) &temp_cck, + &cckswing_table_ch1ch13[i][2], 4)) { + *cck_index_old = (u8) i; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, + DBG_LOUD, + ("Initial reg0x%x = 0x%lx, " + "cck_index = 0x%x, ch14 %d\n", + RCCK0_TXFILTER2, + temp_cck, *cck_index_old, + rtlpriv->dm.cck_inch14)); + break; + } + } + } + *temp_cckg = temp_cck; +} + +static void rtl92d_bandtype_5G(struct rtl_hal *rtlhal, u8 *ofdm_index, + bool *internal_pa, u8 thermalvalue, u8 delta, + u8 rf, struct rtl_efuse *rtlefuse, + struct rtl_priv *rtlpriv, struct rtl_phy *rtlphy, + u8 index_mapping[5][INDEX_MAPPING_NUM], + u8 index_mapping_pa[8][INDEX_MAPPING_NUM]) +{ + int i; + u8 index; + u8 offset = 0; + + for (i = 0; i < rf; i++) { + if (rtlhal->macphymode == DUALMAC_DUALPHY && + rtlhal->interfaceindex == 1) /* MAC 1 5G */ + *internal_pa = rtlefuse->internal_pa_5g[1]; + else + *internal_pa = rtlefuse->internal_pa_5g[i]; + if (*internal_pa) { + if (rtlhal->interfaceindex == 1 || i == rf) + offset = 4; + else + offset = 0; + if (rtlphy->current_channel >= 100 && + rtlphy->current_channel <= 165) + offset += 2; + } else { + if (rtlhal->interfaceindex == 1 || i == rf) + offset = 2; + else + offset = 0; + } + if (thermalvalue > rtlefuse->eeprom_thermalmeter) + offset++; + if (*internal_pa) { + if (delta > INDEX_MAPPING_NUM - 1) + index = index_mapping_pa[offset] + [INDEX_MAPPING_NUM - 1]; + else + index = + index_mapping_pa[offset][delta]; + } else { + if (delta > INDEX_MAPPING_NUM - 1) + index = + index_mapping[offset][INDEX_MAPPING_NUM - 1]; + else + index = index_mapping[offset][delta]; + } + if (thermalvalue > rtlefuse->eeprom_thermalmeter) { + if (*internal_pa && thermalvalue > 0x12) { + ofdm_index[i] = rtlpriv->dm.ofdm_index[i] - + ((delta / 2) * 3 + (delta % 2)); + } else { + ofdm_index[i] -= index; + } + } else { + ofdm_index[i] += index; + } + } +} + +static void rtl92d_dm_txpower_tracking_callback_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 thermalvalue, delta, delta_lck, delta_iqk, delta_rxgain; + u8 offset, thermalvalue_avg_count = 0; + u32 thermalvalue_avg = 0; + bool internal_pa = false; + long ele_a = 0, ele_d, temp_cck, val_x, value32; + long val_y, ele_c = 0; + u8 ofdm_index[2]; + u8 cck_index = 0; + u8 ofdm_index_old[2]; + u8 cck_index_old = 0; + u8 index; + int i; + bool is2t = IS_92D_SINGLEPHY(rtlhal->version); + u8 ofdm_min_index = 6, ofdm_min_index_internal_pa = 3, rf; + u8 indexforchannel = + rtl92d_get_rightchnlplace_for_iqk(rtlphy->current_channel); + u8 index_mapping[5][INDEX_MAPPING_NUM] = { + /* 5G, path A/MAC 0, decrease power */ + {0, 1, 3, 6, 8, 9, 11, 13, 14, 16, 17, 18, 18}, + /* 5G, path A/MAC 0, increase power */ + {0, 2, 4, 5, 7, 10, 12, 14, 16, 18, 18, 18, 18}, + /* 5G, path B/MAC 1, decrease power */ + {0, 2, 3, 6, 8, 9, 11, 13, 14, 16, 17, 18, 18}, + /* 5G, path B/MAC 1, increase power */ + {0, 2, 4, 5, 7, 10, 13, 16, 16, 18, 18, 18, 18}, + /* 2.4G, for decreas power */ + {0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 10}, + }; + u8 index_mapping_internal_pa[8][INDEX_MAPPING_NUM] = { + /* 5G, path A/MAC 0, ch36-64, decrease power */ + {0, 1, 2, 4, 6, 7, 9, 11, 12, 14, 15, 16, 16}, + /* 5G, path A/MAC 0, ch36-64, increase power */ + {0, 2, 4, 5, 7, 10, 12, 14, 16, 18, 18, 18, 18}, + /* 5G, path A/MAC 0, ch100-165, decrease power */ + {0, 1, 2, 3, 5, 6, 8, 10, 11, 13, 14, 15, 15}, + /* 5G, path A/MAC 0, ch100-165, increase power */ + {0, 2, 4, 5, 7, 10, 12, 14, 16, 18, 18, 18, 18}, + /* 5G, path B/MAC 1, ch36-64, decrease power */ + {0, 1, 2, 4, 6, 7, 9, 11, 12, 14, 15, 16, 16}, + /* 5G, path B/MAC 1, ch36-64, increase power */ + {0, 2, 4, 5, 7, 10, 13, 16, 16, 18, 18, 18, 18}, + /* 5G, path B/MAC 1, ch100-165, decrease power */ + {0, 1, 2, 3, 5, 6, 8, 9, 10, 12, 13, 14, 14}, + /* 5G, path B/MAC 1, ch100-165, increase power */ + {0, 2, 4, 5, 7, 10, 13, 16, 16, 18, 18, 18, 18}, + }; + + rtlpriv->dm.txpower_trackinginit = true; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("\n")); + thermalvalue = (u8) rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0xf800); + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x " + "eeprom_thermalmeter 0x%x\n", thermalvalue, + rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter)); + rtl92d_phy_ap_calibrate(hw, (thermalvalue - + rtlefuse->eeprom_thermalmeter)); + if (is2t) + rf = 2; + else + rf = 1; + if (thermalvalue) { + ele_d = rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD) & BMASKOFDM_D; + for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { + if (ele_d == (ofdmswing_table[i] & BMASKOFDM_D)) { + ofdm_index_old[0] = (u8) i; + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("Initial pathA ele_d reg0x%x = 0x%lx," + " ofdm_index=0x%x\n", + ROFDM0_XATxIQIMBALANCE, + ele_d, ofdm_index_old[0])); + break; + } + } + if (is2t) { + ele_d = rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, + BMASKDWORD) & BMASKOFDM_D; + for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { + if (ele_d == + (ofdmswing_table[i] & BMASKOFDM_D)) { + ofdm_index_old[1] = (u8) i; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, + DBG_LOUD, + ("Initial pathB ele_d reg " + "0x%x = 0x%lx, ofdm_index " + "= 0x%x\n", + ROFDM0_XBTxIQIMBALANCE, ele_d, + ofdm_index_old[1])); + break; + } + } + } + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + rtl92d_bandtype_2_4G(hw, &temp_cck, &cck_index_old); + } else { + temp_cck = 0x090e1317; + cck_index_old = 12; + } + + if (!rtlpriv->dm.thermalvalue) { + rtlpriv->dm.thermalvalue = + rtlefuse->eeprom_thermalmeter; + rtlpriv->dm.thermalvalue_lck = thermalvalue; + rtlpriv->dm.thermalvalue_iqk = thermalvalue; + rtlpriv->dm.thermalvalue_rxgain = + rtlefuse->eeprom_thermalmeter; + for (i = 0; i < rf; i++) + rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i]; + rtlpriv->dm.cck_index = cck_index_old; + } + if (rtlhal->reloadtxpowerindex) { + for (i = 0; i < rf; i++) + rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i]; + rtlpriv->dm.cck_index = cck_index_old; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("reload ofdm index for band switch\n")); + } + rtlpriv->dm.thermalvalue_avg + [rtlpriv->dm.thermalvalue_avg_index] = thermalvalue; + rtlpriv->dm.thermalvalue_avg_index++; + if (rtlpriv->dm.thermalvalue_avg_index == AVG_THERMAL_NUM) + rtlpriv->dm.thermalvalue_avg_index = 0; + for (i = 0; i < AVG_THERMAL_NUM; i++) { + if (rtlpriv->dm.thermalvalue_avg[i]) { + thermalvalue_avg += + rtlpriv->dm.thermalvalue_avg[i]; + thermalvalue_avg_count++; + } + } + if (thermalvalue_avg_count) + thermalvalue = (u8) (thermalvalue_avg / + thermalvalue_avg_count); + if (rtlhal->reloadtxpowerindex) { + delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ? + (thermalvalue - rtlefuse->eeprom_thermalmeter) : + (rtlefuse->eeprom_thermalmeter - thermalvalue); + rtlhal->reloadtxpowerindex = false; + rtlpriv->dm.done_txpower = false; + } else if (rtlpriv->dm.done_txpower) { + delta = (thermalvalue > rtlpriv->dm.thermalvalue) ? + (thermalvalue - rtlpriv->dm.thermalvalue) : + (rtlpriv->dm.thermalvalue - thermalvalue); + } else { + delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ? + (thermalvalue - rtlefuse->eeprom_thermalmeter) : + (rtlefuse->eeprom_thermalmeter - thermalvalue); + } + delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ? + (thermalvalue - rtlpriv->dm.thermalvalue_lck) : + (rtlpriv->dm.thermalvalue_lck - thermalvalue); + delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ? + (thermalvalue - rtlpriv->dm.thermalvalue_iqk) : + (rtlpriv->dm.thermalvalue_iqk - thermalvalue); + delta_rxgain = + (thermalvalue > rtlpriv->dm.thermalvalue_rxgain) ? + (thermalvalue - rtlpriv->dm.thermalvalue_rxgain) : + (rtlpriv->dm.thermalvalue_rxgain - thermalvalue); + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x" + " eeprom_thermalmeter 0x%x delta 0x%x " + "delta_lck 0x%x delta_iqk 0x%x\n", + thermalvalue, rtlpriv->dm.thermalvalue, + rtlefuse->eeprom_thermalmeter, delta, delta_lck, + delta_iqk)); + if ((delta_lck > rtlefuse->delta_lck) && + (rtlefuse->delta_lck != 0)) { + rtlpriv->dm.thermalvalue_lck = thermalvalue; + rtl92d_phy_lc_calibrate(hw); + } + if (delta > 0 && rtlpriv->dm.txpower_track_control) { + rtlpriv->dm.done_txpower = true; + delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ? + (thermalvalue - rtlefuse->eeprom_thermalmeter) : + (rtlefuse->eeprom_thermalmeter - thermalvalue); + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + offset = 4; + if (delta > INDEX_MAPPING_NUM - 1) + index = index_mapping[offset] + [INDEX_MAPPING_NUM - 1]; + else + index = index_mapping[offset][delta]; + if (thermalvalue > rtlpriv->dm.thermalvalue) { + for (i = 0; i < rf; i++) + ofdm_index[i] -= delta; + cck_index -= delta; + } else { + for (i = 0; i < rf; i++) + ofdm_index[i] += index; + cck_index += index; + } + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + rtl92d_bandtype_5G(rtlhal, ofdm_index, + &internal_pa, thermalvalue, + delta, rf, rtlefuse, rtlpriv, + rtlphy, index_mapping, + index_mapping_internal_pa); + } + if (is2t) { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("temp OFDM_A_index=0x%x, OFDM_B_index" + " = 0x%x,cck_index=0x%x\n", + rtlpriv->dm.ofdm_index[0], + rtlpriv->dm.ofdm_index[1], + rtlpriv->dm.cck_index)); + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("temp OFDM_A_index=0x%x,cck_index = " + "0x%x\n", + rtlpriv->dm.ofdm_index[0], + rtlpriv->dm.cck_index)); + } + for (i = 0; i < rf; i++) { + if (ofdm_index[i] > OFDM_TABLE_SIZE_92D - 1) + ofdm_index[i] = OFDM_TABLE_SIZE_92D - 1; + else if (ofdm_index[i] < ofdm_min_index) + ofdm_index[i] = ofdm_min_index; + } + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + if (cck_index > CCK_TABLE_SIZE - 1) { + cck_index = CCK_TABLE_SIZE - 1; + } else if (internal_pa || + rtlhal->current_bandtype == + BAND_ON_2_4G) { + if (ofdm_index[i] < + ofdm_min_index_internal_pa) + ofdm_index[i] = + ofdm_min_index_internal_pa; + } else if (cck_index < 0) { + cck_index = 0; + } + } + if (is2t) { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("new OFDM_A_index=0x%x, OFDM_B_index " + "= 0x%x, cck_index=0x%x\n", + ofdm_index[0], ofdm_index[1], + cck_index)); + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("new OFDM_A_index=0x%x,cck_index = " + "0x%x\n", + ofdm_index[0], cck_index)); + } + ele_d = (ofdmswing_table[(u8) ofdm_index[0]] & + 0xFFC00000) >> 22; + val_x = rtlphy->iqk_matrix_regsetting + [indexforchannel].value[0][0]; + val_y = rtlphy->iqk_matrix_regsetting + [indexforchannel].value[0][1]; + if (val_x != 0) { + if ((val_x & 0x00000200) != 0) + val_x = val_x | 0xFFFFFC00; + ele_a = + ((val_x * ele_d) >> 8) & 0x000003FF; + + /* new element C = element D x Y */ + if ((val_y & 0x00000200) != 0) + val_y = val_y | 0xFFFFFC00; + ele_c = ((val_y * ele_d) >> 8) & 0x000003FF; + + /* wirte new elements A, C, D to regC80 and + * regC94, element B is always 0 */ + value32 = (ele_d << 22) | ((ele_c & 0x3F) << + 16) | ele_a; + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD, value32); + + value32 = (ele_c & 0x000003C0) >> 6; + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS, + value32); + + value32 = ((val_x * ele_d) >> 7) & 0x01; + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), + value32); + + } else { + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD, + ofdmswing_table + [(u8)ofdm_index[0]]); + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS, + 0x00); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(24), 0x00); + } + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("TxPwrTracking for interface %d path A: X =" + " 0x%lx, Y = 0x%lx ele_A = 0x%lx ele_C = " + "0x%lx ele_D = 0x%lx 0xe94 = 0x%lx 0xe9c = " + "0x%lx\n", rtlhal->interfaceindex, + val_x, val_y, ele_a, ele_c, ele_d, + val_x, val_y)); + + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* Adjust CCK according to IQK result */ + if (!rtlpriv->dm.cck_inch14) { + rtl_write_byte(rtlpriv, 0xa22, + cckswing_table_ch1ch13 + [(u8)cck_index][0]); + rtl_write_byte(rtlpriv, 0xa23, + cckswing_table_ch1ch13 + [(u8)cck_index][1]); + rtl_write_byte(rtlpriv, 0xa24, + cckswing_table_ch1ch13 + [(u8)cck_index][2]); + rtl_write_byte(rtlpriv, 0xa25, + cckswing_table_ch1ch13 + [(u8)cck_index][3]); + rtl_write_byte(rtlpriv, 0xa26, + cckswing_table_ch1ch13 + [(u8)cck_index][4]); + rtl_write_byte(rtlpriv, 0xa27, + cckswing_table_ch1ch13 + [(u8)cck_index][5]); + rtl_write_byte(rtlpriv, 0xa28, + cckswing_table_ch1ch13 + [(u8)cck_index][6]); + rtl_write_byte(rtlpriv, 0xa29, + cckswing_table_ch1ch13 + [(u8)cck_index][7]); + } else { + rtl_write_byte(rtlpriv, 0xa22, + cckswing_table_ch14 + [(u8)cck_index][0]); + rtl_write_byte(rtlpriv, 0xa23, + cckswing_table_ch14 + [(u8)cck_index][1]); + rtl_write_byte(rtlpriv, 0xa24, + cckswing_table_ch14 + [(u8)cck_index][2]); + rtl_write_byte(rtlpriv, 0xa25, + cckswing_table_ch14 + [(u8)cck_index][3]); + rtl_write_byte(rtlpriv, 0xa26, + cckswing_table_ch14 + [(u8)cck_index][4]); + rtl_write_byte(rtlpriv, 0xa27, + cckswing_table_ch14 + [(u8)cck_index][5]); + rtl_write_byte(rtlpriv, 0xa28, + cckswing_table_ch14 + [(u8)cck_index][6]); + rtl_write_byte(rtlpriv, 0xa29, + cckswing_table_ch14 + [(u8)cck_index][7]); + } + } + if (is2t) { + ele_d = (ofdmswing_table[(u8) ofdm_index[1]] & + 0xFFC00000) >> 22; + val_x = rtlphy->iqk_matrix_regsetting + [indexforchannel].value[0][4]; + val_y = rtlphy->iqk_matrix_regsetting + [indexforchannel].value[0][5]; + if (val_x != 0) { + if ((val_x & 0x00000200) != 0) + /* consider minus */ + val_x = val_x | 0xFFFFFC00; + ele_a = ((val_x * ele_d) >> 8) & + 0x000003FF; + /* new element C = element D x Y */ + if ((val_y & 0x00000200) != 0) + val_y = + val_y | 0xFFFFFC00; + ele_c = + ((val_y * + ele_d) >> 8) & 0x00003FF; + /* write new elements A, C, D to regC88 + * and regC9C, element B is always 0 + */ + value32 = (ele_d << 22) | + ((ele_c & 0x3F) << 16) | + ele_a; + rtl_set_bbreg(hw, + ROFDM0_XBTxIQIMBALANCE, + BMASKDWORD, value32); + value32 = (ele_c & 0x000003C0) >> 6; + rtl_set_bbreg(hw, ROFDM0_XDTxAFE, + BMASKH4BITS, value32); + value32 = ((val_x * ele_d) >> 7) & 0x01; + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(28), value32); + } else { + rtl_set_bbreg(hw, + ROFDM0_XBTxIQIMBALANCE, + BMASKDWORD, + ofdmswing_table + [(u8) ofdm_index[1]]); + rtl_set_bbreg(hw, ROFDM0_XDTxAFE, + BMASKH4BITS, 0x00); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, + BIT(28), 0x00); + } + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("TxPwrTracking path B: X = 0x%lx, " + "Y = 0x%lx ele_A = 0x%lx ele_C = 0x" + "%lx ele_D = 0x%lx 0xeb4 = 0x%lx " + "0xebc = 0x%lx\n", + val_x, val_y, ele_a, ele_c, + ele_d, val_x, val_y)); + } + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("TxPwrTracking 0xc80 = 0x%x, 0xc94 = " + "0x%x RF 0x24 = 0x%x\n", + rtl_get_bbreg(hw, 0xc80, BMASKDWORD), + rtl_get_bbreg(hw, 0xc94, BMASKDWORD), + rtl_get_rfreg(hw, RF90_PATH_A, 0x24, + BRFREGOFFSETMASK))); + } + if ((delta_iqk > rtlefuse->delta_iqk) && + (rtlefuse->delta_iqk != 0)) { + rtl92d_phy_reset_iqk_result(hw); + rtlpriv->dm.thermalvalue_iqk = thermalvalue; + rtl92d_phy_iq_calibrate(hw); + } + if (delta_rxgain > 0 && rtlhal->current_bandtype == BAND_ON_5G + && thermalvalue <= rtlefuse->eeprom_thermalmeter) { + rtlpriv->dm.thermalvalue_rxgain = thermalvalue; + rtl92d_dm_rxgain_tracking_thermalmeter(hw); + } + if (rtlpriv->dm.txpower_track_control) + rtlpriv->dm.thermalvalue = thermalvalue; + } + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("<===\n")); +} + +static void rtl92d_dm_initialize_txpower_tracking(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.txpower_tracking = true; + rtlpriv->dm.txpower_trackinginit = false; + rtlpriv->dm.txpower_track_control = true; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("pMgntInfo->txpower_tracking = %d\n", + rtlpriv->dm.txpower_tracking)); +} + +void rtl92d_dm_check_txpower_tracking_thermal_meter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static u8 tm_trigger; + + if (!rtlpriv->dm.txpower_tracking) + return; + + if (!tm_trigger) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | + BIT(16), 0x03); + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("Trigger 92S Thermal Meter!!\n")); + tm_trigger = 1; + return; + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("Schedule TxPowerTracking direct call!!\n")); + rtl92d_dm_txpower_tracking_callback_thermalmeter(hw); + tm_trigger = 0; + } +} + +void rtl92d_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rate_adaptive *ra = &(rtlpriv->ra); + + ra->ratr_state = DM_RATR_STA_INIT; + ra->pre_ratr_state = DM_RATR_STA_INIT; + if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) + rtlpriv->dm.useramask = true; + else + rtlpriv->dm.useramask = false; +} + +void rtl92d_dm_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtl92d_dm_diginit(hw); + rtl92d_dm_init_dynamic_txpower(hw); + rtl92d_dm_init_edca_turbo(hw); + rtl92d_dm_init_rate_adaptive_mask(hw); + rtl92d_dm_initialize_txpower_tracking(hw); +} + +void rtl92d_dm_watchdog(struct ieee80211_hw *hw) +{ + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool fw_current_inpsmode = false; + bool fwps_awake = true; + + /* 1. RF is OFF. (No need to do DM.) + * 2. Fw is under power saving mode for FwLPS. + * (Prevent from SW/FW I/O racing.) + * 3. IPS workitem is scheduled. (Prevent from IPS sequence + * to be swapped with DM. + * 4. RFChangeInProgress is TRUE. + * (Prevent from broken by IPS/HW/SW Rf off.) */ + + if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) && + fwps_awake) && (!ppsc->rfchange_inprogress)) { + rtl92d_dm_pwdb_monitor(hw); + rtl92d_dm_false_alarm_counter_statistics(hw); + rtl92d_dm_find_minimum_rssi(hw); + rtl92d_dm_dig(hw); + /* rtl92d_dm_dynamic_bb_powersaving(hw); */ + rtl92d_dm_dynamic_txpower(hw); + /* rtl92d_dm_check_txpower_tracking_thermal_meter(hw); */ + /* rtl92d_dm_refresh_rate_adaptive_mask(hw); */ + /* rtl92d_dm_interrupt_migration(hw); */ + rtl92d_dm_check_edca_turbo(hw); + } +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h new file mode 100644 index 000000000000..69354657f0f5 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h @@ -0,0 +1,212 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92C_DM_H__ +#define __RTL92C_DM_H__ + +#define HAL_DM_DIG_DISABLE BIT(0) +#define HAL_DM_HIPWR_DISABLE BIT(1) + +#define OFDM_TABLE_LENGTH 37 +#define OFDM_TABLE_SIZE_92D 43 +#define CCK_TABLE_LENGTH 33 + +#define CCK_TABLE_SIZE 33 + +#define BW_AUTO_SWITCH_HIGH_LOW 25 +#define BW_AUTO_SWITCH_LOW_HIGH 30 + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 + +#define DM_FALSEALARM_THRESH_LOW 400 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_MAX 0x3e +#define DM_DIG_MIN 0x1c + +#define DM_DIG_FA_UPPER 0x32 +#define DM_DIG_FA_LOWER 0x20 +#define DM_DIG_FA_TH0 0x100 +#define DM_DIG_FA_TH1 0x400 +#define DM_DIG_FA_TH2 0x600 + +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 +#define DM_DIG_BACKOFF_DEFAULT 10 + +#define RXPATHSELECTION_SS_TH_lOW 30 +#define RXPATHSELECTION_DIFF_TH 18 + +#define DM_RATR_STA_INIT 0 +#define DM_RATR_STA_HIGH 1 +#define DM_RATR_STA_MIDDLE 2 +#define DM_RATR_STA_LOW 3 + +#define CTS2SELF_THVAL 30 +#define REGC38_TH 20 + +#define WAIOTTHVAL 25 + +#define TXHIGHPWRLEVEL_NORMAL 0 +#define TXHIGHPWRLEVEL_LEVEL1 1 +#define TXHIGHPWRLEVEL_LEVEL2 2 +#define TXHIGHPWRLEVEL_BT1 3 +#define TXHIGHPWRLEVEL_BT2 4 + +#define DM_TYPE_BYFW 0 +#define DM_TYPE_BYDRIVER 1 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 +#define INDEX_MAPPING_NUM 13 + +struct ps_t { + u8 pre_ccastate; + u8 cur_ccasate; + + u8 pre_rfstate; + u8 cur_rfstate; + + long rssi_val_min; +}; + +struct dig_t { + u8 dig_enable_flag; + u8 dig_ext_port_stage; + + u32 rssi_lowthresh; + u32 rssi_highthresh; + + u32 fa_lowthresh; + u32 fa_highthresh; + + u8 cursta_connectctate; + u8 presta_connectstate; + u8 curmultista_connectstate; + + u8 pre_igvalue; + u8 cur_igvalue; + + char backoff_val; + char backoff_val_range_max; + char backoff_val_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + u8 min_undecorated_pwdb_for_dm; + long last_min_undecorated_pwdb_for_dm; + + u8 pre_cck_pd_state; + u8 cur_cck_pd_state; + + u8 pre_cck_fa_state; + u8 cur_cck_fa_state; + + u8 pre_ccastate; + u8 cur_ccasate; + + u8 large_fa_hit; + u8 forbidden_igi; + u32 recover_cnt; +}; + +struct swat { + u8 failure_cnt; + u8 try_flag; + u8 stop_trying; + long pre_rssi; + long trying_threshold; + u8 cur_antenna; + u8 pre_antenna; +}; + +enum tag_dynamic_init_gain_operation_type_definition { + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_BACKOFF = 2, + DIG_TYPE_RX_GAIN_MIN = 3, + DIG_TYPE_RX_GAIN_MAX = 4, + DIG_TYPE_ENABLE = 5, + DIG_TYPE_DISABLE = 6, + DIG_OP_TYPE_MAX +}; + +enum tag_cck_packet_detection_threshold_type_definition { + CCK_PD_STAGE_LOWRSSI = 0, + CCK_PD_STAGE_HIGHRSSI = 1, + CCK_FA_STAGE_LOW = 2, + CCK_FA_STAGE_HIGH = 3, + CCK_PD_STAGE_MAX = 4, +}; + +enum dm_1r_cca { + CCA_1R = 0, + CCA_2R = 1, + CCA_MAX = 2, +}; + +enum dm_rf { + RF_SAVE = 0, + RF_NORMAL = 1, + RF_MAX = 2, +}; + +enum dm_sw_ant_switch { + ANS_ANTENNA_B = 1, + ANS_ANTENNA_A = 2, + ANS_ANTENNA_MAX = 3, +}; + +enum dm_dig_ext_port_alg { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_connect { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_MULTISTA_DISCONNECT = 3, + DIG_MULTISTA_CONNECT = 4, + DIG_CONNECT_MAX +}; + +extern struct dig_t de_digtable; + +void rtl92d_dm_init(struct ieee80211_hw *hw); +void rtl92d_dm_watchdog(struct ieee80211_hw *hw); +void rtl92d_dm_init_edca_turbo(struct ieee80211_hw *hw); +void rtl92d_dm_write_dig(struct ieee80211_hw *hw); +void rtl92d_dm_check_txpower_tracking_thermal_meter(struct ieee80211_hw *hw); +void rtl92d_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c new file mode 100644 index 000000000000..82f060bdbc0b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c @@ -0,0 +1,790 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" +#include "sw.h" + +static bool _rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv) +{ + return (rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY) ? + true : false; +} + +static void _rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp; + + if (enable) { + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04); + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); + rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); + } else { + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); + /* Reserved for fw extension. + * 0x81[7] is used for mac0 status , + * so don't write this reg here + * rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);*/ + } +} + +static void _rtl92d_fw_block_write(struct ieee80211_hw *hw, + const u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 blocksize = sizeof(u32); + u8 *bufferptr = (u8 *) buffer; + u32 *pu4BytePtr = (u32 *) buffer; + u32 i, offset, blockCount, remainSize; + + blockCount = size / blocksize; + remainSize = size % blocksize; + for (i = 0; i < blockCount; i++) { + offset = i * blocksize; + rtl_write_dword(rtlpriv, (FW_8192D_START_ADDRESS + offset), + *(pu4BytePtr + i)); + } + if (remainSize) { + offset = blockCount * blocksize; + bufferptr += offset; + for (i = 0; i < remainSize; i++) { + rtl_write_byte(rtlpriv, (FW_8192D_START_ADDRESS + + offset + i), *(bufferptr + i)); + } + } +} + +static void _rtl92d_fw_page_write(struct ieee80211_hw *hw, + u32 page, const u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value8; + u8 u8page = (u8) (page & 0x07); + + value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; + rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); + _rtl92d_fw_block_write(hw, buffer, size); +} + +static void _rtl92d_fill_dummy(u8 *pfwbuf, u32 *pfwlen) +{ + u32 fwlen = *pfwlen; + u8 remain = (u8) (fwlen % 4); + + remain = (remain == 0) ? 0 : (4 - remain); + while (remain > 0) { + pfwbuf[fwlen] = 0; + fwlen++; + remain--; + } + *pfwlen = fwlen; +} + +static void _rtl92d_write_fw(struct ieee80211_hw *hw, + enum version_8192d version, u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 *bufferPtr = (u8 *) buffer; + u32 pagenums, remainSize; + u32 page, offset; + + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size)); + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) + _rtl92d_fill_dummy(bufferPtr, &size); + pagenums = size / FW_8192D_PAGE_SIZE; + remainSize = size % FW_8192D_PAGE_SIZE; + if (pagenums > 8) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Page numbers should not greater then 8\n")); + } + for (page = 0; page < pagenums; page++) { + offset = page * FW_8192D_PAGE_SIZE; + _rtl92d_fw_page_write(hw, page, (bufferPtr + offset), + FW_8192D_PAGE_SIZE); + } + if (remainSize) { + offset = pagenums * FW_8192D_PAGE_SIZE; + page = pagenums; + _rtl92d_fw_page_write(hw, page, (bufferPtr + offset), + remainSize); + } +} + +static int _rtl92d_fw_free_to_go(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 counter = 0; + u32 value32; + + do { + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + } while ((counter++ < FW_8192D_POLLING_TIMEOUT_COUNT) && + (!(value32 & FWDL_ChkSum_rpt))); + if (counter >= FW_8192D_POLLING_TIMEOUT_COUNT) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", + value32)); + return -EIO; + } + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32)); + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + value32 |= MCUFWDL_RDY; + rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + return 0; +} + +void rtl92d_firmware_selfreset(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1b_tmp; + u8 delay = 100; + + /* Set (REG_HMETFR + 3) to 0x20 is reset 8051 */ + rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + while (u1b_tmp & BIT(2)) { + delay--; + if (delay == 0) + break; + udelay(50); + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + } + RT_ASSERT((delay > 0), ("8051 reset failed!\n")); + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + ("=====> 8051 reset success (%d) .\n", delay)); +} + +static int _rtl92d_fw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 counter; + + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, ("FW already have download\n")); + /* polling for FW ready */ + counter = 0; + do { + if (rtlhal->interfaceindex == 0) { + if (rtl_read_byte(rtlpriv, FW_MAC0_READY) & + MAC0_READY) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + ("Polling FW ready success!! " + "REG_MCUFWDL: 0x%x .\n", + rtl_read_byte(rtlpriv, + FW_MAC0_READY))); + return 0; + } + udelay(5); + } else { + if (rtl_read_byte(rtlpriv, FW_MAC1_READY) & + MAC1_READY) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + ("Polling FW ready success!! " + "REG_MCUFWDL: 0x%x .\n", + rtl_read_byte(rtlpriv, + FW_MAC1_READY))); + return 0; + } + udelay(5); + } + } while (counter++ < POLLING_READY_TIMEOUT_COUNT); + + if (rtlhal->interfaceindex == 0) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + ("Polling FW ready fail!! MAC0 FW init not ready: " + "0x%x .\n", + rtl_read_byte(rtlpriv, FW_MAC0_READY))); + } else { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + ("Polling FW ready fail!! MAC1 FW init not ready: " + "0x%x .\n", + rtl_read_byte(rtlpriv, FW_MAC1_READY))); + } + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + ("Polling FW ready fail!! REG_MCUFWDL:0x%08ul .\n", + rtl_read_dword(rtlpriv, REG_MCUFWDL))); + return -1; +} + +int rtl92d_download_fw(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 *pfwheader; + u8 *pfwdata; + u32 fwsize; + int err; + enum version_8192d version = rtlhal->version; + u8 value; + u32 count; + bool fw_downloaded = false, fwdl_in_process = false; + unsigned long flags; + + if (!rtlhal->pfirmware) + return 1; + fwsize = rtlhal->fwsize; + pfwheader = (u8 *) rtlhal->pfirmware; + pfwdata = (u8 *) rtlhal->pfirmware; + rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader); + rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, (" FirmwareVersion(%d)," + "FirmwareSubVersion(%d), Signature(%#x)\n", + rtlhal->fw_version, rtlhal->fw_subversion, + GET_FIRMWARE_HDR_SIGNATURE(pfwheader))); + if (IS_FW_HEADER_EXIST(pfwheader)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Shift 32 bytes for FW header!!\n")); + pfwdata = pfwdata + 32; + fwsize = fwsize - 32; + } + + spin_lock_irqsave(&globalmutex_for_fwdownload, flags); + fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv); + if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5)) + fwdl_in_process = true; + else + fwdl_in_process = false; + if (fw_downloaded) { + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + goto exit; + } else if (fwdl_in_process) { + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + for (count = 0; count < 5000; count++) { + udelay(500); + spin_lock_irqsave(&globalmutex_for_fwdownload, flags); + fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv); + if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5)) + fwdl_in_process = true; + else + fwdl_in_process = false; + spin_unlock_irqrestore(&globalmutex_for_fwdownload, + flags); + if (fw_downloaded) + goto exit; + else if (!fwdl_in_process) + break; + else + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + ("Wait for another mac " + "download fw\n")); + } + spin_lock_irqsave(&globalmutex_for_fwdownload, flags); + value = rtl_read_byte(rtlpriv, 0x1f); + value |= BIT(5); + rtl_write_byte(rtlpriv, 0x1f, value); + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + } else { + value = rtl_read_byte(rtlpriv, 0x1f); + value |= BIT(5); + rtl_write_byte(rtlpriv, 0x1f, value); + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + } + + /* If 8051 is running in RAM code, driver should + * inform Fw to reset by itself, or it will cause + * download Fw fail.*/ + /* 8051 RAM code */ + if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) { + rtl92d_firmware_selfreset(hw); + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + } + _rtl92d_enable_fw_download(hw, true); + _rtl92d_write_fw(hw, version, pfwdata, fwsize); + _rtl92d_enable_fw_download(hw, false); + spin_lock_irqsave(&globalmutex_for_fwdownload, flags); + err = _rtl92d_fw_free_to_go(hw); + /* download fw over,clear 0x1f[5] */ + value = rtl_read_byte(rtlpriv, 0x1f); + value &= (~BIT(5)); + rtl_write_byte(rtlpriv, 0x1f, value); + spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("fw is not ready to run!\n")); + goto exit; + } else { + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + ("fw is ready to run!\n")); + } +exit: + err = _rtl92d_fw_init(hw); + return err; +} + +static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 val_hmetfr; + bool result = false; + + val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); + if (((val_hmetfr >> boxnum) & BIT(0)) == 0) + result = true; + return result; +} + +static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *cmdbuffer) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u8 boxnum; + u16 box_reg = 0, box_extreg = 0; + u8 u1b_tmp; + bool isfw_read = false; + u8 buf_index = 0; + bool bwrite_sucess = false; + u8 wait_h2c_limmit = 100; + u8 wait_writeh2c_limmit = 100; + u8 boxcontent[4], boxextcontent[2]; + u32 h2c_waitcounter = 0; + unsigned long flag; + u8 idx; + + if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Return as RF is off!!!\n")); + return; + } + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n")); + while (true) { + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + if (rtlhal->h2c_setinprogress) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("H2C set in progress! Wait to set.." + "element_id(%d).\n", element_id)); + + while (rtlhal->h2c_setinprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, + flag); + h2c_waitcounter++; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Wait 100 us (%d times)...\n", + h2c_waitcounter)); + udelay(100); + + if (h2c_waitcounter > 1000) + return; + + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, + flag); + } + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + } else { + rtlhal->h2c_setinprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + break; + } + } + while (!bwrite_sucess) { + wait_writeh2c_limmit--; + if (wait_writeh2c_limmit == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Write H2C fail because no trigger " + "for FW INT!\n")); + break; + } + boxnum = rtlhal->last_hmeboxnum; + switch (boxnum) { + case 0: + box_reg = REG_HMEBOX_0; + box_extreg = REG_HMEBOX_EXT_0; + break; + case 1: + box_reg = REG_HMEBOX_1; + box_extreg = REG_HMEBOX_EXT_1; + break; + case 2: + box_reg = REG_HMEBOX_2; + box_extreg = REG_HMEBOX_EXT_2; + break; + case 3: + box_reg = REG_HMEBOX_3; + box_extreg = REG_HMEBOX_EXT_3; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum); + while (!isfw_read) { + wait_h2c_limmit--; + if (wait_h2c_limmit == 0) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Wating too long for FW read " + "clear HMEBox(%d)!\n", boxnum)); + break; + } + udelay(10); + isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum); + u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Wating for FW read clear HMEBox(%d)!!! " + "0x1BF = %2x\n", boxnum, u1b_tmp)); + } + if (!isfw_read) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Write H2C register BOX[%d] fail!!!!! " + "Fw do not read.\n", boxnum)); + break; + } + memset(boxcontent, 0, sizeof(boxcontent)); + memset(boxextcontent, 0, sizeof(boxextcontent)); + boxcontent[0] = element_id; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Write element_id box_reg(%4x) = %2x\n", + box_reg, element_id)); + switch (cmd_len) { + case 1: + boxcontent[0] &= ~(BIT(7)); + memcpy(boxcontent + 1, cmdbuffer + buf_index, 1); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + case 2: + boxcontent[0] &= ~(BIT(7)); + memcpy(boxcontent + 1, cmdbuffer + buf_index, 2); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + case 3: + boxcontent[0] &= ~(BIT(7)); + memcpy(boxcontent + 1, cmdbuffer + buf_index, 3); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + case 4: + boxcontent[0] |= (BIT(7)); + memcpy(boxextcontent, cmdbuffer + buf_index, 2); + memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2); + for (idx = 0; idx < 2; idx++) + rtl_write_byte(rtlpriv, box_extreg + idx, + boxextcontent[idx]); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + case 5: + boxcontent[0] |= (BIT(7)); + memcpy(boxextcontent, cmdbuffer + buf_index, 2); + memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3); + for (idx = 0; idx < 2; idx++) + rtl_write_byte(rtlpriv, box_extreg + idx, + boxextcontent[idx]); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + bwrite_sucess = true; + rtlhal->last_hmeboxnum = boxnum + 1; + if (rtlhal->last_hmeboxnum == 4) + rtlhal->last_hmeboxnum = 0; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("pHalData->last_hmeboxnum = %d\n", + rtlhal->last_hmeboxnum)); + } + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + rtlhal->h2c_setinprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n")); +} + +void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *cmdbuffer) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 tmp_cmdbuf[2]; + + if (rtlhal->fw_ready == false) { + RT_ASSERT(false, ("return H2C cmd because of Fw " + "download fail!!!\n")); + return; + } + memset(tmp_cmdbuf, 0, 8); + memcpy(tmp_cmdbuf, cmdbuffer, cmd_len); + _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); + return; +} + +void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1_h2c_set_pwrmode[3] = { 0 }; + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode)); + SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); + SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1); + SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, + ppsc->reg_max_lps_awakeintvl); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n", + u1_h2c_set_pwrmode, 3); + rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); +} + +static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + u8 idx = 0; + unsigned long flags; + struct sk_buff *pskb; + + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + pskb = __skb_dequeue(&ring->queue); + if (pskb) + kfree_skb(pskb); + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + pdesc = &ring->desc[idx]; + /* discard output from call below */ + rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); + __skb_queue_tail(&ring->queue, skb); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + return true; +} + +#define BEACON_PG 0 /*->1 */ +#define PSPOLL_PG 2 +#define NULL_PG 3 +#define PROBERSP_PG 4 /*->5 */ +#define TOTAL_RESERVED_PKT_LEN 768 + +static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { + /* page 0 beacon */ + 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, + 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, + 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, + 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, + 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, + 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, + 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 1 beacon */ + 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, + 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, + 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, + 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 2 ps-poll */ + 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 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, + 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 3 null */ + 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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, 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, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 4 probe_resp */ + 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, + 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, + 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, + 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, + 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, + 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, + 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, + 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, + 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 5 probe_resp */ + 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, + 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, + 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, + 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, +}; + +void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct sk_buff *skb = NULL; + u32 totalpacketlen; + bool rtstatus; + u8 u1RsvdPageLoc[3] = { 0 }; + bool dlok = false; + u8 *beacon; + u8 *p_pspoll; + u8 *nullfunc; + u8 *p_probersp; + /*--------------------------------------------------------- + (1) beacon + ---------------------------------------------------------*/ + beacon = &reserved_page_packet[BEACON_PG * 128]; + SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); + SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + /*------------------------------------------------------- + (2) ps-poll + --------------------------------------------------------*/ + p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; + SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); + SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG); + /*-------------------------------------------------------- + (3) null data + ---------------------------------------------------------*/ + nullfunc = &reserved_page_packet[NULL_PG * 128]; + SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); + SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); + SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG); + /*--------------------------------------------------------- + (4) probe response + ----------------------------------------------------------*/ + p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; + SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG); + totalpacketlen = TOTAL_RESERVED_PKT_LEN; + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", + &reserved_page_packet[0], totalpacketlen); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", + u1RsvdPageLoc, 3); + skb = dev_alloc_skb(totalpacketlen); + memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet, + totalpacketlen); + rtstatus = _rtl92d_cmd_send_packet(hw, skb); + + if (rtstatus) + dlok = true; + if (dlok) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Set RSVD page location to Fw.\n")); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 3); + rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE, + sizeof(u1RsvdPageLoc), u1RsvdPageLoc); + } else + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("Set RSVD page location to Fw FAIL!!!!!!.\n")); +} + +void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ + u8 u1_joinbssrpt_parm[1] = {0}; + + SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); + rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h new file mode 100644 index 000000000000..0c4d489eaa48 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92D__FW__H__ +#define __RTL92D__FW__H__ + +#define FW_8192D_START_ADDRESS 0x1000 +#define FW_8192D_PAGE_SIZE 4096 +#define FW_8192D_POLLING_TIMEOUT_COUNT 1000 + +#define IS_FW_HEADER_EXIST(_pfwhdr) \ + ((GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFF0) == 0x92C0 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFF0) == 0x88C0 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFFF) == 0x92D0 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFFF) == 0x92D1 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFFF) == 0x92D2 || \ + (GET_FIRMWARE_HDR_SIGNATURE(_pfwhdr) & 0xFFFF) == 0x92D3) + +/* Define a macro that takes an le32 word, converts it to host ordering, + * right shifts by a specified count, creates a mask of the specified + * bit count, and extracts that number of bits. + */ + +#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ + ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ + BIT_LEN_MASK_32(__mask)) + +/* Firmware Header(8-byte alinment required) */ +/* --- LONG WORD 0 ---- */ +#define GET_FIRMWARE_HDR_SIGNATURE(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr, 0, 16) +#define GET_FIRMWARE_HDR_CATEGORY(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr, 16, 8) +#define GET_FIRMWARE_HDR_FUNCTION(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr, 24, 8) +#define GET_FIRMWARE_HDR_VERSION(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 4, 0, 16) +#define GET_FIRMWARE_HDR_SUB_VER(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 4, 16, 8) +#define GET_FIRMWARE_HDR_RSVD1(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 4, 24, 8) + +/* --- LONG WORD 1 ---- */ +#define GET_FIRMWARE_HDR_MONTH(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 8, 0, 8) +#define GET_FIRMWARE_HDR_DATE(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 8, 8, 8) +#define GET_FIRMWARE_HDR_HOUR(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 8, 16, 8) +#define GET_FIRMWARE_HDR_MINUTE(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 8, 24, 8) +#define GET_FIRMWARE_HDR_ROMCODE_SIZE(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 12, 0, 16) +#define GET_FIRMWARE_HDR_RSVD2(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 12, 16, 16) + +/* --- LONG WORD 2 ---- */ +#define GET_FIRMWARE_HDR_SVN_IDX(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 16, 0, 32) +#define GET_FIRMWARE_HDR_RSVD3(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 20, 0, 32) + +/* --- LONG WORD 3 ---- */ +#define GET_FIRMWARE_HDR_RSVD4(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 24, 0, 32) +#define GET_FIRMWARE_HDR_RSVD5(__fwhdr) \ + SHIFT_AND_MASK_LE(__fwhdr + 28, 0, 32) + +#define pagenum_128(_len) \ + (u32)(((_len) >> 7) + ((_len) & 0x7F ? 1 : 0)) + +#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 1, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 2, 0, 8, __val) +#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 1, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 2, 0, 8, __val) + +struct rtl92d_firmware_header { + u16 signature; + u8 category; + u8 function; + u16 version; + u8 subversion; + u8 rsvd1; + + u8 month; + u8 date; + u8 hour; + u8 minute; + u16 ramcodeSize; + u16 rsvd2; + + u32 svnindex; + u32 rsvd3; + + u32 rsvd4; + u32 rsvd5; +}; + +enum rtl8192d_h2c_cmd { + H2C_AP_OFFLOAD = 0, + H2C_SETPWRMODE = 1, + H2C_JOINBSSRPT = 2, + H2C_RSVDPAGE = 3, + H2C_RSSI_REPORT = 5, + H2C_RA_MASK = 6, + H2C_MAC_MODE_SEL = 9, + H2C_PWRM = 15, + MAX_H2CCMD +}; + +int rtl92d_download_fw(struct ieee80211_hw *hw); +void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); +void rtl92d_firmware_selfreset(struct ieee80211_hw *hw); +void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c new file mode 100644 index 000000000000..5a65bea4cb8f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -0,0 +1,2329 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "led.h" +#include "sw.h" +#include "hw.h" + +u32 rtl92de_read_dword_dbi(struct ieee80211_hw *hw, u16 offset, u8 direct) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 value; + + rtl_write_word(rtlpriv, REG_DBI_CTRL, (offset & 0xFFC)); + rtl_write_byte(rtlpriv, REG_DBI_FLAG, BIT(1) | direct); + udelay(10); + value = rtl_read_dword(rtlpriv, REG_DBI_RDATA); + return value; +} + +void rtl92de_write_dword_dbi(struct ieee80211_hw *hw, + u16 offset, u32 value, u8 direct) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_DBI_CTRL, ((offset & 0xFFC) | 0xF000)); + rtl_write_dword(rtlpriv, REG_DBI_WDATA, value); + rtl_write_byte(rtlpriv, REG_DBI_FLAG, BIT(0) | direct); +} + +static void _rtl92de_set_bcn_ctrl_reg(struct ieee80211_hw *hw, + u8 set_bits, u8 clear_bits) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpci->reg_bcn_ctrl_val |= set_bits; + rtlpci->reg_bcn_ctrl_val &= ~clear_bits; + rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val); +} + +static void _rtl92de_stop_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6))); + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl92de_resume_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6)); + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0x0a); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte |= BIT(0); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl92de_enable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(1)); +} + +static void _rtl92de_disable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl92de_set_bcn_ctrl_reg(hw, BIT(1), 0); +} + +void rtl92de_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + switch (variable) { + case HW_VAR_RCR: + *((u32 *) (val)) = rtlpci->receive_config; + break; + case HW_VAR_RF_STATE: + *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; + break; + case HW_VAR_FWLPS_RF_ON:{ + enum rf_pwrstate rfState; + u32 val_rcr; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, + (u8 *) (&rfState)); + if (rfState == ERFOFF) { + *((bool *) (val)) = true; + } else { + val_rcr = rtl_read_dword(rtlpriv, REG_RCR); + val_rcr &= 0x00070000; + if (val_rcr) + *((bool *) (val)) = false; + else + *((bool *) (val)) = true; + } + break; + } + case HW_VAR_FW_PSMODE_STATUS: + *((bool *) (val)) = ppsc->fw_current_inpsmode; + break; + case HW_VAR_CORRECT_TSF:{ + u64 tsf; + u32 *ptsf_low = (u32 *)&tsf; + u32 *ptsf_high = ((u32 *)&tsf) + 1; + + *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4)); + *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + *((u64 *) (val)) = tsf; + break; + } + case HW_VAR_INT_MIGRATION: + *((bool *)(val)) = rtlpriv->dm.interrupt_migration; + break; + case HW_VAR_INT_AC: + *((bool *)(val)) = rtlpriv->dm.disable_tx_int; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } +} + +void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u8 idx; + + switch (variable) { + case HW_VAR_ETHER_ADDR: + for (idx = 0; idx < ETH_ALEN; idx++) { + rtl_write_byte(rtlpriv, (REG_MACID + idx), + val[idx]); + } + break; + case HW_VAR_BASIC_RATE: { + u16 rate_cfg = ((u16 *) val)[0]; + u8 rate_index = 0; + + rate_cfg = rate_cfg & 0x15f; + if (mac->vendor == PEER_CISCO && + ((rate_cfg & 0x150) == 0)) + rate_cfg |= 0x01; + rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); + rtl_write_byte(rtlpriv, REG_RRSR + 1, + (rate_cfg >> 8) & 0xff); + while (rate_cfg > 0x1) { + rate_cfg = (rate_cfg >> 1); + rate_index++; + } + if (rtlhal->fw_version > 0xe) + rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, + rate_index); + break; + } + case HW_VAR_BSSID: + for (idx = 0; idx < ETH_ALEN; idx++) { + rtl_write_byte(rtlpriv, (REG_BSSID + idx), + val[idx]); + } + break; + case HW_VAR_SIFS: + rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]); + rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]); + rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]); + rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]); + if (!mac->ht_enable) + rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, + 0x0e0e); + else + rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, + *((u16 *) val)); + break; + case HW_VAR_SLOT_TIME: { + u8 e_aci; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("HW_VAR_SLOT_TIME %x\n", val[0])); + rtl_write_byte(rtlpriv, REG_SLOT, val[0]); + for (e_aci = 0; e_aci < AC_MAX; e_aci++) + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_AC_PARAM, + (u8 *) (&e_aci)); + break; + } + case HW_VAR_ACK_PREAMBLE: { + u8 reg_tmp; + u8 short_preamble = (bool) (*(u8 *) val); + + reg_tmp = (mac->cur_40_prime_sc) << 5; + if (short_preamble) + reg_tmp |= 0x80; + rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp); + break; + } + case HW_VAR_AMPDU_MIN_SPACE: { + u8 min_spacing_to_set; + u8 sec_min_space; + + min_spacing_to_set = *((u8 *) val); + if (min_spacing_to_set <= 7) { + sec_min_space = 0; + if (min_spacing_to_set < sec_min_space) + min_spacing_to_set = sec_min_space; + mac->min_space_cfg = ((mac->min_space_cfg & 0xf8) | + min_spacing_to_set); + *val = min_spacing_to_set; + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + mac->min_space_cfg)); + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + } + break; + } + case HW_VAR_SHORTGI_DENSITY: { + u8 density_to_set; + + density_to_set = *((u8 *) val); + mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg; + mac->min_space_cfg |= (density_to_set << 3); + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("Set HW_VAR_SHORTGI_DENSITY: %#x\n", + mac->min_space_cfg)); + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + break; + } + case HW_VAR_AMPDU_FACTOR: { + u8 factor_toset; + u32 regtoSet; + u8 *ptmp_byte = NULL; + u8 index; + + if (rtlhal->macphymode == DUALMAC_DUALPHY) + regtoSet = 0xb9726641; + else if (rtlhal->macphymode == DUALMAC_SINGLEPHY) + regtoSet = 0x66626641; + else + regtoSet = 0xb972a841; + factor_toset = *((u8 *) val); + if (factor_toset <= 3) { + factor_toset = (1 << (factor_toset + 2)); + if (factor_toset > 0xf) + factor_toset = 0xf; + for (index = 0; index < 4; index++) { + ptmp_byte = (u8 *) (®toSet) + index; + if ((*ptmp_byte & 0xf0) > + (factor_toset << 4)) + *ptmp_byte = (*ptmp_byte & 0x0f) + | (factor_toset << 4); + if ((*ptmp_byte & 0x0f) > factor_toset) + *ptmp_byte = (*ptmp_byte & 0xf0) + | (factor_toset); + } + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, regtoSet); + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("Set HW_VAR_AMPDU_FACTOR: %#x\n", + factor_toset)); + } + break; + } + case HW_VAR_AC_PARAM: { + u8 e_aci = *((u8 *) val); + rtl92d_dm_init_edca_turbo(hw); + if (rtlpci->acm_method != eAcmWay2_SW) + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, + (u8 *) (&e_aci)); + break; + } + case HW_VAR_ACM_CTRL: { + u8 e_aci = *((u8 *) val); + union aci_aifsn *p_aci_aifsn = + (union aci_aifsn *)(&(mac->ac[0].aifs)); + u8 acm = p_aci_aifsn->f.acm; + u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); + + acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1); + if (acm) { + switch (e_aci) { + case AC0_BE: + acm_ctrl |= ACMHW_BEQEN; + break; + case AC2_VI: + acm_ctrl |= ACMHW_VIQEN; + break; + case AC3_VO: + acm_ctrl |= ACMHW_VOQEN; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("HW_VAR_ACM_CTRL acm set " + "failed: eACI is %d\n", acm)); + break; + } + } else { + switch (e_aci) { + case AC0_BE: + acm_ctrl &= (~ACMHW_BEQEN); + break; + case AC2_VI: + acm_ctrl &= (~ACMHW_VIQEN); + break; + case AC3_VO: + acm_ctrl &= (~ACMHW_VOQEN); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + } + RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, + ("SetHwReg8190pci(): [HW_VAR_ACM_CTRL] " + "Write 0x%X\n", acm_ctrl)); + rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl); + break; + } + case HW_VAR_RCR: + rtl_write_dword(rtlpriv, REG_RCR, ((u32 *) (val))[0]); + rtlpci->receive_config = ((u32 *) (val))[0]; + break; + case HW_VAR_RETRY_LIMIT: { + u8 retry_limit = ((u8 *) (val))[0]; + + rtl_write_word(rtlpriv, REG_RL, + retry_limit << RETRY_LIMIT_SHORT_SHIFT | + retry_limit << RETRY_LIMIT_LONG_SHIFT); + break; + } + case HW_VAR_DUAL_TSF_RST: + rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1))); + break; + case HW_VAR_EFUSE_BYTES: + rtlefuse->efuse_usedbytes = *((u16 *) val); + break; + case HW_VAR_EFUSE_USAGE: + rtlefuse->efuse_usedpercentage = *((u8 *) val); + break; + case HW_VAR_IO_CMD: + rtl92d_phy_set_io_cmd(hw, (*(enum io_type *)val)); + break; + case HW_VAR_WPA_CONFIG: + rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val)); + break; + case HW_VAR_SET_RPWM: + rtl92d_fill_h2c_cmd(hw, H2C_PWRM, 1, (u8 *) (val)); + break; + case HW_VAR_H2C_FW_PWRMODE: + break; + case HW_VAR_FW_PSMODE_STATUS: + ppsc->fw_current_inpsmode = *((bool *) val); + break; + case HW_VAR_H2C_FW_JOINBSSRPT: { + u8 mstatus = (*(u8 *) val); + u8 tmp_regcr, tmp_reg422; + bool recover = false; + + if (mstatus == RT_MEDIA_CONNECT) { + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_AID, NULL); + tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr | BIT(0))); + _rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(3)); + _rtl92de_set_bcn_ctrl_reg(hw, BIT(4), 0); + tmp_reg422 = rtl_read_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2); + if (tmp_reg422 & BIT(6)) + recover = true; + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, + tmp_reg422 & (~BIT(6))); + rtl92d_set_fw_rsvdpagepkt(hw, 0); + _rtl92de_set_bcn_ctrl_reg(hw, BIT(3), 0); + _rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(4)); + if (recover) + rtl_write_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2, + tmp_reg422); + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr & ~(BIT(0)))); + } + rtl92d_set_fw_joinbss_report_cmd(hw, (*(u8 *) val)); + break; + } + case HW_VAR_AID: { + u16 u2btmp; + u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT); + u2btmp &= 0xC000; + rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp | + mac->assoc_id)); + break; + } + case HW_VAR_CORRECT_TSF: { + u8 btype_ibss = ((u8 *) (val))[0]; + + if (btype_ibss) + _rtl92de_stop_tx_beacon(hw); + _rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(3)); + rtl_write_dword(rtlpriv, REG_TSFTR, + (u32) (mac->tsf & 0xffffffff)); + rtl_write_dword(rtlpriv, REG_TSFTR + 4, + (u32) ((mac->tsf >> 32) & 0xffffffff)); + _rtl92de_set_bcn_ctrl_reg(hw, BIT(3), 0); + if (btype_ibss) + _rtl92de_resume_tx_beacon(hw); + + break; + } + case HW_VAR_INT_MIGRATION: { + bool int_migration = *(bool *) (val); + + if (int_migration) { + /* Set interrrupt migration timer and + * corresponging Tx/Rx counter. + * timer 25ns*0xfa0=100us for 0xf packets. + * 0x306:Rx, 0x307:Tx */ + rtl_write_dword(rtlpriv, REG_INT_MIG, 0xfe000fa0); + rtlpriv->dm.interrupt_migration = int_migration; + } else { + /* Reset all interrupt migration settings. */ + rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + rtlpriv->dm.interrupt_migration = int_migration; + } + break; + } + case HW_VAR_INT_AC: { + bool disable_ac_int = *((bool *) val); + + /* Disable four ACs interrupts. */ + if (disable_ac_int) { + /* Disable VO, VI, BE and BK four AC interrupts + * to gain more efficient CPU utilization. + * When extremely highly Rx OK occurs, + * we will disable Tx interrupts. + */ + rtlpriv->cfg->ops->update_interrupt_mask(hw, 0, + RT_AC_INT_MASKS); + rtlpriv->dm.disable_tx_int = disable_ac_int; + /* Enable four ACs interrupts. */ + } else { + rtlpriv->cfg->ops->update_interrupt_mask(hw, + RT_AC_INT_MASKS, 0); + rtlpriv->dm.disable_tx_int = disable_ac_int; + } + break; + } + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } +} + +static bool _rtl92de_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool status = true; + long count = 0; + u32 value = _LLT_INIT_ADDR(address) | + _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); + + rtl_write_dword(rtlpriv, REG_LLT_INIT, value); + do { + value = rtl_read_dword(rtlpriv, REG_LLT_INIT); + if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) + break; + if (count > POLLING_LLT_THRESHOLD) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Failed to polling write LLT done at " + "address %d!\n", address)); + status = false; + break; + } + } while (++count); + return status; +} + +static bool _rtl92de_llt_table_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned short i; + u8 txpktbuf_bndy; + u8 maxPage; + bool status; + u32 value32; /* High+low page number */ + u8 value8; /* normal page number */ + + if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) { + maxPage = 255; + txpktbuf_bndy = 246; + value8 = 0; + value32 = 0x80bf0d29; + } else if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { + maxPage = 127; + txpktbuf_bndy = 123; + value8 = 0; + value32 = 0x80750005; + } + + /* Set reserved page for each queue */ + /* 11. RQPN 0x200[31:0] = 0x80BD1C1C */ + /* load RQPN */ + rtl_write_byte(rtlpriv, REG_RQPN_NPQ, value8); + rtl_write_dword(rtlpriv, REG_RQPN, value32); + + /* 12. TXRKTBUG_PG_BNDY 0x114[31:0] = 0x27FF00F6 */ + /* TXRKTBUG_PG_BNDY */ + rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, + (rtl_read_word(rtlpriv, REG_TRXFF_BNDY + 2) << 16 | + txpktbuf_bndy)); + + /* 13. TDECTRL[15:8] 0x209[7:0] = 0xF6 */ + /* Beacon Head for TXDMA */ + rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy); + + /* 14. BCNQ_PGBNDY 0x424[7:0] = 0xF6 */ + /* BCNQ_PGBNDY */ + rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); + + /* 15. WMAC_LBK_BF_HD 0x45D[7:0] = 0xF6 */ + /* WMAC_LBK_BF_HD */ + rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy); + + /* Set Tx/Rx page size (Tx must be 128 Bytes, */ + /* Rx can be 64,128,256,512,1024 bytes) */ + /* 16. PBP [7:0] = 0x11 */ + /* TRX page size */ + rtl_write_byte(rtlpriv, REG_PBP, 0x11); + + /* 17. DRV_INFO_SZ = 0x04 */ + rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4); + + /* 18. LLT_table_init(Adapter); */ + for (i = 0; i < (txpktbuf_bndy - 1); i++) { + status = _rtl92de_llt_write(hw, i, i + 1); + if (true != status) + return status; + } + + /* end of list */ + status = _rtl92de_llt_write(hw, (txpktbuf_bndy - 1), 0xFF); + if (true != status) + return status; + + /* Make the other pages as ring buffer */ + /* This ring buffer is used as beacon buffer if we */ + /* config this MAC as two MAC transfer. */ + /* Otherwise used as local loopback buffer. */ + for (i = txpktbuf_bndy; i < maxPage; i++) { + status = _rtl92de_llt_write(hw, i, (i + 1)); + if (true != status) + return status; + } + + /* Let last entry point to the start entry of ring buffer */ + status = _rtl92de_llt_write(hw, maxPage, txpktbuf_bndy); + if (true != status) + return status; + + return true; +} + +static void _rtl92de_gen_refresh_led_state(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + + if (rtlpci->up_first_time) + return; + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) + rtl92de_sw_led_on(hw, pLed0); + else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) + rtl92de_sw_led_on(hw, pLed0); + else + rtl92de_sw_led_off(hw, pLed0); +} + +static bool _rtl92de_init_mac(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + unsigned char bytetmp; + unsigned short wordtmp; + u16 retry; + + rtl92d_phy_set_poweron(hw); + /* Add for resume sequence of power domain according + * to power document V11. Chapter V.11.... */ + /* 0. RSV_CTRL 0x1C[7:0] = 0x00 */ + /* unlock ISO/CLK/Power control register */ + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); + rtl_write_byte(rtlpriv, REG_LDOA15_CTRL, 0x05); + + /* 1. AFE_XTAL_CTRL [7:0] = 0x0F enable XTAL */ + /* 2. SPS0_CTRL 0x11[7:0] = 0x2b enable SPS into PWM mode */ + /* 3. delay (1ms) this is not necessary when initially power on */ + + /* C. Resume Sequence */ + /* a. SPS0_CTRL 0x11[7:0] = 0x2b */ + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); + + /* b. AFE_XTAL_CTRL [7:0] = 0x0F */ + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F); + + /* c. DRV runs power on init flow */ + + /* auto enable WLAN */ + /* 4. APS_FSMCO 0x04[8] = 1; wait till 0x04[8] = 0 */ + /* Power On Reset for MAC Block */ + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0); + udelay(2); + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp); + udelay(2); + + /* 5. Wait while 0x04[8] == 0 goto 2, otherwise goto 1 */ + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); + udelay(50); + retry = 0; + while ((bytetmp & BIT(0)) && retry < 1000) { + retry++; + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); + udelay(50); + } + + /* Enable Radio off, GPIO, and LED function */ + /* 6. APS_FSMCO 0x04[15:0] = 0x0012 when enable HWPDN */ + rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x1012); + + /* release RF digital isolation */ + /* 7. SYS_ISO_CTRL 0x01[1] = 0x0; */ + /*Set REG_SYS_ISO_CTRL 0x1=0x82 to prevent wake# problem. */ + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82); + udelay(2); + + /* make sure that BB reset OK. */ + /* rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); */ + + /* Disable REG_CR before enable it to assure reset */ + rtl_write_word(rtlpriv, REG_CR, 0x0); + + /* Release MAC IO register reset */ + rtl_write_word(rtlpriv, REG_CR, 0x2ff); + + /* clear stopping tx/rx dma */ + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0x0); + + /* rtl_write_word(rtlpriv,REG_CR+2, 0x2); */ + + /* System init */ + /* 18. LLT_table_init(Adapter); */ + if (_rtl92de_llt_table_init(hw) == false) + return false; + + /* Clear interrupt and enable interrupt */ + /* 19. HISR 0x124[31:0] = 0xffffffff; */ + /* HISRE 0x12C[7:0] = 0xFF */ + rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff); + rtl_write_byte(rtlpriv, REG_HISRE, 0xff); + + /* 20. HIMR 0x120[31:0] |= [enable INT mask bit map]; */ + /* 21. HIMRE 0x128[7:0] = [enable INT mask bit map] */ + /* The IMR should be enabled later after all init sequence + * is finished. */ + + /* 22. PCIE configuration space configuration */ + /* 23. Ensure PCIe Device 0x80[15:0] = 0x0143 (ASPM+CLKREQ), */ + /* and PCIe gated clock function is enabled. */ + /* PCIE configuration space will be written after + * all init sequence.(Or by BIOS) */ + + rtl92d_phy_config_maccoexist_rfpage(hw); + + /* THe below section is not related to power document Vxx . */ + /* This is only useful for driver and OS setting. */ + /* -------------------Software Relative Setting---------------------- */ + wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL); + wordtmp &= 0xf; + wordtmp |= 0xF771; + rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp); + + /* Reported Tx status from HW for rate adaptive. */ + /* This should be realtive to power on step 14. But in document V11 */ + /* still not contain the description.!!! */ + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F); + + /* Set Tx/Rx page size (Tx must be 128 Bytes, + * Rx can be 64,128,256,512,1024 bytes) */ + /* rtl_write_byte(rtlpriv,REG_PBP, 0x11); */ + + /* Set RCR register */ + rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + /* rtl_write_byte(rtlpriv,REG_RX_DRVINFO_SZ, 4); */ + + /* Set TCR register */ + rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config); + + /* disable earlymode */ + rtl_write_byte(rtlpriv, 0x4d0, 0x0); + + /* Set TX/RX descriptor physical address(from OS API). */ + rtl_write_dword(rtlpriv, REG_BCNQ_DESA, + rtlpci->tx_ring[BEACON_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_MGQ_DESA, rtlpci->tx_ring[MGNT_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_VOQ_DESA, rtlpci->tx_ring[VO_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_VIQ_DESA, rtlpci->tx_ring[VI_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_BEQ_DESA, rtlpci->tx_ring[BE_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_BKQ_DESA, rtlpci->tx_ring[BK_QUEUE].dma); + rtl_write_dword(rtlpriv, REG_HQ_DESA, rtlpci->tx_ring[HIGH_QUEUE].dma); + /* Set RX Desc Address */ + rtl_write_dword(rtlpriv, REG_RX_DESA, + rtlpci->rx_ring[RX_MPDU_QUEUE].dma); + + /* if we want to support 64 bit DMA, we should set it here, + * but now we do not support 64 bit DMA*/ + + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x33); + + /* Reset interrupt migration setting when initialization */ + rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + + /* Reconsider when to do this operation after asking HWSD. */ + bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6)); + do { + retry++; + bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); + } while ((retry < 200) && !(bytetmp & BIT(7))); + + /* After MACIO reset,we must refresh LED state. */ + _rtl92de_gen_refresh_led_state(hw); + + /* Reset H2C protection register */ + rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0); + + return true; +} + +static void _rtl92de_hw_configure(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 reg_bw_opmode = BW_OPMODE_20MHZ; + u32 reg_rrsr; + + reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); + rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + rtl_write_dword(rtlpriv, REG_RRSR, reg_rrsr); + rtl_write_byte(rtlpriv, REG_SLOT, 0x09); + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, 0x0); + rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F80); + rtl_write_word(rtlpriv, REG_RL, 0x0707); + rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x02012802); + rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF); + rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000); + rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504); + rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); + rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504); + /* Aggregation threshold */ + if (rtlhal->macphymode == DUALMAC_DUALPHY) + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb9726641); + else if (rtlhal->macphymode == DUALMAC_SINGLEPHY) + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x66626641); + else + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); + rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0x0a); + rtlpci->reg_bcn_ctrl_val = 0x1f; + rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); + rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + /* For throughput */ + rtl_write_word(rtlpriv, REG_FAST_EDCA_CTRL, 0x6666); + /* ACKTO for IOT issue. */ + rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); + /* Set Spec SIFS (used in NAV) */ + rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x1010); + rtl_write_word(rtlpriv, REG_MAC_SPEC_SIFS, 0x1010); + /* Set SIFS for CCK */ + rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x1010); + /* Set SIFS for OFDM */ + rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x1010); + /* Set Multicast Address. */ + rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff); + rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff); + switch (rtlpriv->phy.rf_type) { + case RF_1T2R: + case RF_1T1R: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_1T << 3); + break; + case RF_2T2R: + case RF_2T2R_GREEN: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_2T << 3); + break; + } +} + +static void _rtl92de_enable_aspm_back_door(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + rtl_write_byte(rtlpriv, 0x34b, 0x93); + rtl_write_word(rtlpriv, 0x350, 0x870c); + rtl_write_byte(rtlpriv, 0x352, 0x1); + if (ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x349, 0x1b); + else + rtl_write_byte(rtlpriv, 0x349, 0x03); + rtl_write_word(rtlpriv, 0x350, 0x2718); + rtl_write_byte(rtlpriv, 0x352, 0x1); +} + +void rtl92de_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n", + rtlpriv->sec.pairwise_enc_algorithm, + rtlpriv->sec.group_enc_algorithm)); + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("not open hw encryption\n")); + return; + } + sec_reg_value = SCR_TXENCENABLE | SCR_RXENCENABLE; + if (rtlpriv->sec.use_defaultkey) { + sec_reg_value |= SCR_TXUSEDK; + sec_reg_value |= SCR_RXUSEDK; + } + sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK); + rtl_write_byte(rtlpriv, REG_CR + 1, 0x02); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The SECR-value %x\n", sec_reg_value)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); +} + +int rtl92de_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool rtstatus = true; + u8 tmp_u1b; + int i; + int err; + unsigned long flags; + + rtlpci->being_init_adapter = true; + rtlpci->init_ready = false; + spin_lock_irqsave(&globalmutex_for_power_and_efuse, flags); + /* we should do iqk after disable/enable */ + rtl92d_phy_reset_iqk_result(hw); + /* rtlpriv->intf_ops->disable_aspm(hw); */ + rtstatus = _rtl92de_init_mac(hw); + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Init MAC failed\n")); + err = 1; + spin_unlock_irqrestore(&globalmutex_for_power_and_efuse, flags); + return err; + } + err = rtl92d_download_fw(hw); + spin_unlock_irqrestore(&globalmutex_for_power_and_efuse, flags); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("Failed to download FW. Init HW " + "without FW..\n")); + rtlhal->fw_ready = false; + return 1; + } else { + rtlhal->fw_ready = true; + } + rtlhal->last_hmeboxnum = 0; + rtlpriv->psc.fw_current_inpsmode = false; + + tmp_u1b = rtl_read_byte(rtlpriv, 0x605); + tmp_u1b = tmp_u1b | 0x30; + rtl_write_byte(rtlpriv, 0x605, tmp_u1b); + + if (rtlhal->earlymode_enable) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EarlyMode Enabled!!!\n")); + + tmp_u1b = rtl_read_byte(rtlpriv, 0x4d0); + tmp_u1b = tmp_u1b | 0x1f; + rtl_write_byte(rtlpriv, 0x4d0, tmp_u1b); + + rtl_write_byte(rtlpriv, 0x4d3, 0x80); + + tmp_u1b = rtl_read_byte(rtlpriv, 0x605); + tmp_u1b = tmp_u1b | 0x40; + rtl_write_byte(rtlpriv, 0x605, tmp_u1b); + } + + if (mac->rdg_en) { + rtl_write_byte(rtlpriv, REG_RD_CTRL, 0xff); + rtl_write_word(rtlpriv, REG_RD_NAV_NXT, 0x200); + rtl_write_byte(rtlpriv, REG_RD_RESP_PKT_TH, 0x05); + } + + rtl92d_phy_mac_config(hw); + /* because last function modify RCR, so we update + * rcr var here, or TP will unstable for receive_config + * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx + * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252*/ + rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR); + rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV); + + rtl92d_phy_bb_config(hw); + + rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; + /* set before initialize RF */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); + + /* config RF */ + rtl92d_phy_rf_config(hw); + + /* After read predefined TXT, we must set BB/MAC/RF + * register as our requirement */ + /* After load BB,RF params,we need do more for 92D. */ + rtl92d_update_bbrf_configuration(hw); + /* set default value after initialize RF, */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0); + rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, + RF_CHNLBW, BRFREGOFFSETMASK); + rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, + RF_CHNLBW, BRFREGOFFSETMASK); + + /*---- Set CCK and OFDM Block "ON"----*/ + if (rtlhal->current_bandtype == BAND_ON_2_4G) + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + if (rtlhal->interfaceindex == 0) { + /* RFPGA0_ANALOGPARAMETER2: cck clock select, + * set to 20MHz by default */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10) | + BIT(11), 3); + } else { + /* Mac1 */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(11) | + BIT(10), 3); + } + + _rtl92de_hw_configure(hw); + + /* reset hw sec */ + rtl_cam_reset_all_entry(hw); + rtl92de_enable_hw_security_config(hw); + + /* Read EEPROM TX power index and PHY_REG_PG.txt to capture correct */ + /* TX power index for different rate set. */ + rtl92d_phy_get_hw_reg_originalvalue(hw); + rtl92d_phy_set_txpower_level(hw, rtlphy->current_channel); + + ppsc->rfpwr_state = ERFON; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + + _rtl92de_enable_aspm_back_door(hw); + /* rtlpriv->intf_ops->enable_aspm(hw); */ + + rtl92d_dm_init(hw); + rtlpci->being_init_adapter = false; + + if (ppsc->rfpwr_state == ERFON) { + rtl92d_phy_lc_calibrate(hw); + /* 5G and 2.4G must wait sometime to let RF LO ready */ + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + u32 tmp_rega; + for (i = 0; i < 10000; i++) { + udelay(MAX_STALL_TIME); + + tmp_rega = rtl_get_rfreg(hw, + (enum radio_path)RF90_PATH_A, + 0x2a, BMASKDWORD); + + if (((tmp_rega & BIT(11)) == BIT(11))) + break; + } + /* check that loop was successful. If not, exit now */ + if (i == 10000) { + rtlpci->init_ready = false; + return 1; + } + } + } + rtlpci->init_ready = true; + return err; +} + +static enum version_8192d _rtl92de_read_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + enum version_8192d version = VERSION_NORMAL_CHIP_92D_SINGLEPHY; + u32 value32; + + value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG); + if (!(value32 & 0x000f0000)) { + version = VERSION_TEST_CHIP_92D_SINGLEPHY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("TEST CHIP!!!\n")); + } else { + version = VERSION_NORMAL_CHIP_92D_SINGLEPHY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Normal CHIP!!!\n")); + } + return version; +} + +static int _rtl92de_set_media_status(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bt_msr = rtl_read_byte(rtlpriv, MSR); + enum led_ctl_mode ledaction = LED_CTL_NO_LINK; + u8 bcnfunc_enable; + + bt_msr &= 0xfc; + + if (type == NL80211_IFTYPE_UNSPECIFIED || + type == NL80211_IFTYPE_STATION) { + _rtl92de_stop_tx_beacon(hw); + _rtl92de_enable_bcn_sub_func(hw); + } else if (type == NL80211_IFTYPE_ADHOC || + type == NL80211_IFTYPE_AP) { + _rtl92de_resume_tx_beacon(hw); + _rtl92de_disable_bcn_sub_func(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("Set HW_VAR_MEDIA_STATUS: No such media " + "status(%x).\n", type)); + } + bcnfunc_enable = rtl_read_byte(rtlpriv, REG_BCN_CTRL); + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + bt_msr |= MSR_NOLINK; + ledaction = LED_CTL_LINK; + bcnfunc_enable &= 0xF7; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to NO LINK!\n")); + break; + case NL80211_IFTYPE_ADHOC: + bt_msr |= MSR_ADHOC; + bcnfunc_enable |= 0x08; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to Ad Hoc!\n")); + break; + case NL80211_IFTYPE_STATION: + bt_msr |= MSR_INFRA; + ledaction = LED_CTL_LINK; + bcnfunc_enable &= 0xF7; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to STA!\n")); + break; + case NL80211_IFTYPE_AP: + bt_msr |= MSR_AP; + bcnfunc_enable |= 0x08; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to AP!\n")); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Network type %d not support!\n", type)); + return 1; + break; + + } + rtl_write_byte(rtlpriv, REG_CR + 2, bt_msr); + rtlpriv->cfg->ops->led_control(hw, ledaction); + if ((bt_msr & 0xfc) == MSR_AP) + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); + else + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); + return 0; +} + +void rtl92de_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 reg_rcr = rtlpci->receive_config; + + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + if (check_bssid) { + reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + _rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(4)); + } else if (check_bssid == false) { + reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); + _rtl92de_set_bcn_ctrl_reg(hw, BIT(4), 0); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + } +} + +int rtl92de_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (_rtl92de_set_media_status(hw, type)) + return -EOPNOTSUPP; + + /* check bssid */ + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92de_set_check_bssid(hw, true); + } else { + rtl92de_set_check_bssid(hw, false); + } + return 0; +} + +/* do iqk or reload iqk */ +/* windows just rtl92d_phy_reload_iqk_setting in set channel, + * but it's very strict for time sequence so we add + * rtl92d_phy_reload_iqk_setting here */ +void rtl92d_linked_set_reg(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 indexforchannel; + u8 channel = rtlphy->current_channel; + + indexforchannel = rtl92d_get_rightchnlplace_for_iqk(channel); + if (!rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done) { + RT_TRACE(rtlpriv, COMP_SCAN | COMP_INIT, DBG_DMESG, + ("Do IQK for channel:%d.\n", channel)); + rtl92d_phy_iq_calibrate(hw); + } +} + +/* don't set REG_EDCA_BE_PARAM here because + * mac80211 will send pkt when scan */ +void rtl92de_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl92d_dm_init_edca_turbo(hw); + return; + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); + break; + case AC0_BE: + break; + case AC2_VI: + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222); + break; + default: + RT_ASSERT(false, ("invalid aci: %d !\n", aci)); + break; + } +} + +void rtl92de_enable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); +} + +void rtl92de_disable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED); + rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); + synchronize_irq(rtlpci->pdev->irq); +} + +static void _rtl92de_poweroff_adapter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1b_tmp; + unsigned long flags; + + rtlpriv->intf_ops->enable_aspm(hw); + rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); + rtl_set_bbreg(hw, RFPGA0_XCD_RFPARAMETER, BIT(3), 0); + rtl_set_bbreg(hw, RFPGA0_XCD_RFPARAMETER, BIT(15), 0); + + /* 0x20:value 05-->04 */ + rtl_write_byte(rtlpriv, REG_LDOA15_CTRL, 0x04); + + /* ==== Reset digital sequence ====== */ + rtl92d_firmware_selfreset(hw); + + /* f. SYS_FUNC_EN 0x03[7:0]=0x51 reset MCU, MAC register, DCORE */ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x51); + + /* g. MCUFWDL 0x80[1:0]=0 reset MCU ready status */ + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + + /* ==== Pull GPIO PIN to balance level and LED control ====== */ + + /* h. GPIO_PIN_CTRL 0x44[31:0]=0x000 */ + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000); + + /* i. Value = GPIO_PIN_CTRL[7:0] */ + u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL); + + /* j. GPIO_PIN_CTRL 0x44[31:0] = 0x00FF0000 | (value <<8); */ + /* write external PIN level */ + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, + 0x00FF0000 | (u1b_tmp << 8)); + + /* k. GPIO_MUXCFG 0x42 [15:0] = 0x0780 */ + rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790); + + /* l. LEDCFG 0x4C[15:0] = 0x8080 */ + rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080); + + /* ==== Disable analog sequence === */ + + /* m. AFE_PLL_CTRL[7:0] = 0x80 disable PLL */ + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); + + /* n. SPS0_CTRL 0x11[7:0] = 0x22 enter PFM mode */ + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); + + /* o. AFE_XTAL_CTRL 0x24[7:0] = 0x0E disable XTAL, if No BT COEX */ + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); + + /* p. RSV_CTRL 0x1C[7:0] = 0x0E lock ISO/CLK/Power control register */ + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); + + /* ==== interface into suspend === */ + + /* q. APS_FSMCO[15:8] = 0x58 PCIe suspend mode */ + /* According to power document V11, we need to set this */ + /* value as 0x18. Otherwise, we may not L0s sometimes. */ + /* This indluences power consumption. Bases on SD1's test, */ + /* set as 0x00 do not affect power current. And if it */ + /* is set as 0x18, they had ever met auto load fail problem. */ + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("In PowerOff,reg0x%x=%X\n", REG_SPS0_CTRL, + rtl_read_byte(rtlpriv, REG_SPS0_CTRL))); + /* r. Note: for PCIe interface, PON will not turn */ + /* off m-bias and BandGap in PCIe suspend mode. */ + + /* 0x17[7] 1b': power off in process 0b' : power off over */ + if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { + spin_lock_irqsave(&globalmutex_power, flags); + u1b_tmp = rtl_read_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS); + u1b_tmp &= (~BIT(7)); + rtl_write_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS, u1b_tmp); + spin_unlock_irqrestore(&globalmutex_power, flags); + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("<=======\n")); +} + +void rtl92de_card_disable(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum nl80211_iftype opmode; + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + _rtl92de_set_media_status(hw, opmode); + + if (rtlpci->driver_is_goingto_unload || + ppsc->rfoff_reason > RF_CHANGE_BY_PS) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + /* Power sequence for each MAC. */ + /* a. stop tx DMA */ + /* b. close RF */ + /* c. clear rx buf */ + /* d. stop rx DMA */ + /* e. reset MAC */ + + /* a. stop tx DMA */ + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFE); + udelay(50); + + /* b. TXPAUSE 0x522[7:0] = 0xFF Pause MAC TX queue */ + + /* c. ========RF OFF sequence========== */ + /* 0x88c[23:20] = 0xf. */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + + /* APSD_CTRL 0x600[7:0] = 0x40 */ + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + + /* Close antenna 0,0xc04,0xd04 */ + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0); + + /* SYS_FUNC_EN 0x02[7:0] = 0xE2 reset BB state machine */ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + + /* Mac0 can not do Global reset. Mac1 can do. */ + /* SYS_FUNC_EN 0x02[7:0] = 0xE0 reset BB state machine */ + if (rtlpriv->rtlhal.interfaceindex == 1) + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE0); + udelay(50); + + /* d. stop tx/rx dma before disable REG_CR (0x100) to fix */ + /* dma hang issue when disable/enable device. */ + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xff); + udelay(50); + rtl_write_byte(rtlpriv, REG_CR, 0x0); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("==> Do power off.......\n")); + if (rtl92d_phy_check_poweroff(hw)) + _rtl92de_poweroff_adapter(hw); + return; +} + +void rtl92de_interrupt_recognized(struct ieee80211_hw *hw, + u32 *p_inta, u32 *p_intb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0]; + rtl_write_dword(rtlpriv, ISR, *p_inta); + + /* + * *p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1]; + * rtl_write_dword(rtlpriv, ISR + 4, *p_intb); + */ +} + +void rtl92de_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval, atim_window; + + bcn_interval = mac->beacon_interval; + atim_window = 2; + /*rtl92de_disable_interrupt(hw); */ + rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f); + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x20); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x30); + else + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x20); + rtl_write_byte(rtlpriv, 0x606, 0x30); +} + +void rtl92de_set_beacon_interval(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval = mac->beacon_interval; + + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, + ("beacon_interval:%d\n", bcn_interval)); + /* rtl92de_disable_interrupt(hw); */ + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); + /* rtl92de_enable_interrupt(hw); */ +} + +void rtl92de_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); + if (add_msr) + rtlpci->irq_mask[0] |= add_msr; + if (rm_msr) + rtlpci->irq_mask[0] &= (~rm_msr); + rtl92de_disable_interrupt(hw); + rtl92de_enable_interrupt(hw); +} + +static void _rtl92de_readpowervalue_fromprom(struct txpower_info *pwrinfo, + u8 *rom_content, bool autoLoadfail) +{ + u32 rfpath, eeaddr, group, offset1, offset2; + u8 i; + + memset(pwrinfo, 0, sizeof(struct txpower_info)); + if (autoLoadfail) { + for (group = 0; group < CHANNEL_GROUP_MAX; group++) { + for (rfpath = 0; rfpath < RF6052_MAX_PATH; rfpath++) { + if (group < CHANNEL_GROUP_MAX_2G) { + pwrinfo->cck_index[rfpath][group] = + EEPROM_DEFAULT_TXPOWERLEVEL_2G; + pwrinfo->ht40_1sindex[rfpath][group] = + EEPROM_DEFAULT_TXPOWERLEVEL_2G; + } else { + pwrinfo->ht40_1sindex[rfpath][group] = + EEPROM_DEFAULT_TXPOWERLEVEL_5G; + } + pwrinfo->ht40_2sindexdiff[rfpath][group] = + EEPROM_DEFAULT_HT40_2SDIFF; + pwrinfo->ht20indexdiff[rfpath][group] = + EEPROM_DEFAULT_HT20_DIFF; + pwrinfo->ofdmindexdiff[rfpath][group] = + EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF; + pwrinfo->ht40maxoffset[rfpath][group] = + EEPROM_DEFAULT_HT40_PWRMAXOFFSET; + pwrinfo->ht20maxoffset[rfpath][group] = + EEPROM_DEFAULT_HT20_PWRMAXOFFSET; + } + } + for (i = 0; i < 3; i++) { + pwrinfo->tssi_a[i] = EEPROM_DEFAULT_TSSI; + pwrinfo->tssi_b[i] = EEPROM_DEFAULT_TSSI; + } + return; + } + + /* Maybe autoload OK,buf the tx power index value is not filled. + * If we find it, we set it to default value. */ + for (rfpath = 0; rfpath < RF6052_MAX_PATH; rfpath++) { + for (group = 0; group < CHANNEL_GROUP_MAX_2G; group++) { + eeaddr = EEPROM_CCK_TX_PWR_INX_2G + (rfpath * 3) + + group; + pwrinfo->cck_index[rfpath][group] = + (rom_content[eeaddr] == 0xFF) ? + (eeaddr > 0x7B ? + EEPROM_DEFAULT_TXPOWERLEVEL_5G : + EEPROM_DEFAULT_TXPOWERLEVEL_2G) : + rom_content[eeaddr]; + } + } + for (rfpath = 0; rfpath < RF6052_MAX_PATH; rfpath++) { + for (group = 0; group < CHANNEL_GROUP_MAX; group++) { + offset1 = group / 3; + offset2 = group % 3; + eeaddr = EEPROM_HT40_1S_TX_PWR_INX_2G + (rfpath * 3) + + offset2 + offset1 * 21; + pwrinfo->ht40_1sindex[rfpath][group] = + (rom_content[eeaddr] == 0xFF) ? (eeaddr > 0x7B ? + EEPROM_DEFAULT_TXPOWERLEVEL_5G : + EEPROM_DEFAULT_TXPOWERLEVEL_2G) : + rom_content[eeaddr]; + } + } + /* These just for 92D efuse offset. */ + for (group = 0; group < CHANNEL_GROUP_MAX; group++) { + for (rfpath = 0; rfpath < RF6052_MAX_PATH; rfpath++) { + int base1 = EEPROM_HT40_2S_TX_PWR_INX_DIFF_2G; + + offset1 = group / 3; + offset2 = group % 3; + + if (rom_content[base1 + offset2 + offset1 * 21] != 0xFF) + pwrinfo->ht40_2sindexdiff[rfpath][group] = + (rom_content[base1 + + offset2 + offset1 * 21] >> (rfpath * 4)) + & 0xF; + else + pwrinfo->ht40_2sindexdiff[rfpath][group] = + EEPROM_DEFAULT_HT40_2SDIFF; + if (rom_content[EEPROM_HT20_TX_PWR_INX_DIFF_2G + offset2 + + offset1 * 21] != 0xFF) + pwrinfo->ht20indexdiff[rfpath][group] = + (rom_content[EEPROM_HT20_TX_PWR_INX_DIFF_2G + + offset2 + offset1 * 21] >> (rfpath * 4)) + & 0xF; + else + pwrinfo->ht20indexdiff[rfpath][group] = + EEPROM_DEFAULT_HT20_DIFF; + if (rom_content[EEPROM_OFDM_TX_PWR_INX_DIFF_2G + offset2 + + offset1 * 21] != 0xFF) + pwrinfo->ofdmindexdiff[rfpath][group] = + (rom_content[EEPROM_OFDM_TX_PWR_INX_DIFF_2G + + offset2 + offset1 * 21] >> (rfpath * 4)) + & 0xF; + else + pwrinfo->ofdmindexdiff[rfpath][group] = + EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF; + if (rom_content[EEPROM_HT40_MAX_PWR_OFFSET_2G + offset2 + + offset1 * 21] != 0xFF) + pwrinfo->ht40maxoffset[rfpath][group] = + (rom_content[EEPROM_HT40_MAX_PWR_OFFSET_2G + + offset2 + offset1 * 21] >> (rfpath * 4)) + & 0xF; + else + pwrinfo->ht40maxoffset[rfpath][group] = + EEPROM_DEFAULT_HT40_PWRMAXOFFSET; + if (rom_content[EEPROM_HT20_MAX_PWR_OFFSET_2G + offset2 + + offset1 * 21] != 0xFF) + pwrinfo->ht20maxoffset[rfpath][group] = + (rom_content[EEPROM_HT20_MAX_PWR_OFFSET_2G + + offset2 + offset1 * 21] >> (rfpath * 4)) & + 0xF; + else + pwrinfo->ht20maxoffset[rfpath][group] = + EEPROM_DEFAULT_HT20_PWRMAXOFFSET; + } + } + if (rom_content[EEPROM_TSSI_A_5G] != 0xFF) { + /* 5GL */ + pwrinfo->tssi_a[0] = rom_content[EEPROM_TSSI_A_5G] & 0x3F; + pwrinfo->tssi_b[0] = rom_content[EEPROM_TSSI_B_5G] & 0x3F; + /* 5GM */ + pwrinfo->tssi_a[1] = rom_content[EEPROM_TSSI_AB_5G] & 0x3F; + pwrinfo->tssi_b[1] = + (rom_content[EEPROM_TSSI_AB_5G] & 0xC0) >> 6 | + (rom_content[EEPROM_TSSI_AB_5G + 1] & 0x0F) << 2; + /* 5GH */ + pwrinfo->tssi_a[2] = (rom_content[EEPROM_TSSI_AB_5G + 1] & + 0xF0) >> 4 | + (rom_content[EEPROM_TSSI_AB_5G + 2] & 0x03) << 4; + pwrinfo->tssi_b[2] = (rom_content[EEPROM_TSSI_AB_5G + 2] & + 0xFC) >> 2; + } else { + for (i = 0; i < 3; i++) { + pwrinfo->tssi_a[i] = EEPROM_DEFAULT_TSSI; + pwrinfo->tssi_b[i] = EEPROM_DEFAULT_TSSI; + } + } +} + +static void _rtl92de_read_txpower_info(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct txpower_info pwrinfo; + u8 tempval[2], i, pwr, diff; + u32 ch, rfPath, group; + + _rtl92de_readpowervalue_fromprom(&pwrinfo, hwinfo, autoload_fail); + if (!autoload_fail) { + /* bit0~2 */ + rtlefuse->eeprom_regulatory = (hwinfo[EEPROM_RF_OPT1] & 0x7); + rtlefuse->eeprom_thermalmeter = + hwinfo[EEPROM_THERMAL_METER] & 0x1f; + rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_K]; + tempval[0] = hwinfo[EEPROM_IQK_DELTA] & 0x03; + tempval[1] = (hwinfo[EEPROM_LCK_DELTA] & 0x0C) >> 2; + rtlefuse->txpwr_fromeprom = true; + if (IS_92D_D_CUT(rtlpriv->rtlhal.version)) { + rtlefuse->internal_pa_5g[0] = + !((hwinfo[EEPROM_TSSI_A_5G] & + BIT(6)) >> 6); + rtlefuse->internal_pa_5g[1] = + !((hwinfo[EEPROM_TSSI_B_5G] & + BIT(6)) >> 6); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Is D cut,Internal PA0 %d Internal PA1 %d\n", + rtlefuse->internal_pa_5g[0], + rtlefuse->internal_pa_5g[1])) + } + rtlefuse->eeprom_c9 = hwinfo[EEPROM_RF_OPT6]; + rtlefuse->eeprom_cc = hwinfo[EEPROM_RF_OPT7]; + } else { + rtlefuse->eeprom_regulatory = 0; + rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER; + rtlefuse->crystalcap = EEPROM_DEFAULT_CRYSTALCAP; + tempval[0] = tempval[1] = 3; + } + + /* Use default value to fill parameters if + * efuse is not filled on some place. */ + + /* ThermalMeter from EEPROM */ + if (rtlefuse->eeprom_thermalmeter < 0x06 || + rtlefuse->eeprom_thermalmeter > 0x1c) + rtlefuse->eeprom_thermalmeter = 0x12; + rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter; + + /* check XTAL_K */ + if (rtlefuse->crystalcap == 0xFF) + rtlefuse->crystalcap = 0; + if (rtlefuse->eeprom_regulatory > 3) + rtlefuse->eeprom_regulatory = 0; + + for (i = 0; i < 2; i++) { + switch (tempval[i]) { + case 0: + tempval[i] = 5; + break; + case 1: + tempval[i] = 4; + break; + case 2: + tempval[i] = 3; + break; + case 3: + default: + tempval[i] = 0; + break; + } + } + + rtlefuse->delta_iqk = tempval[0]; + if (tempval[1] > 0) + rtlefuse->delta_lck = tempval[1] - 1; + if (rtlefuse->eeprom_c9 == 0xFF) + rtlefuse->eeprom_c9 = 0x00; + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + ("EEPROMRegulatory = 0x%x\n", rtlefuse->eeprom_regulatory)); + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + ("ThermalMeter = 0x%x\n", rtlefuse->eeprom_thermalmeter)); + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + ("CrystalCap = 0x%x\n", rtlefuse->crystalcap)); + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + ("Delta_IQK = 0x%x Delta_LCK = 0x%x\n", rtlefuse->delta_iqk, + rtlefuse->delta_lck)); + + for (rfPath = 0; rfPath < RF6052_MAX_PATH; rfPath++) { + for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) { + group = rtl92d_get_chnlgroup_fromarray((u8) ch); + if (ch < CHANNEL_MAX_NUMBER_2G) + rtlefuse->txpwrlevel_cck[rfPath][ch] = + pwrinfo.cck_index[rfPath][group]; + rtlefuse->txpwrlevel_ht40_1s[rfPath][ch] = + pwrinfo.ht40_1sindex[rfPath][group]; + rtlefuse->txpwr_ht20diff[rfPath][ch] = + pwrinfo.ht20indexdiff[rfPath][group]; + rtlefuse->txpwr_legacyhtdiff[rfPath][ch] = + pwrinfo.ofdmindexdiff[rfPath][group]; + rtlefuse->pwrgroup_ht20[rfPath][ch] = + pwrinfo.ht20maxoffset[rfPath][group]; + rtlefuse->pwrgroup_ht40[rfPath][ch] = + pwrinfo.ht40maxoffset[rfPath][group]; + pwr = pwrinfo.ht40_1sindex[rfPath][group]; + diff = pwrinfo.ht40_2sindexdiff[rfPath][group]; + rtlefuse->txpwrlevel_ht40_2s[rfPath][ch] = + (pwr > diff) ? (pwr - diff) : 0; + } + } +} + +static void _rtl92de_read_macphymode_from_prom(struct ieee80211_hw *hw, + u8 *content) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 macphy_crvalue = content[EEPROM_MAC_FUNCTION]; + + if (macphy_crvalue & BIT(3)) { + rtlhal->macphymode = SINGLEMAC_SINGLEPHY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("MacPhyMode SINGLEMAC_SINGLEPHY\n")); + } else { + rtlhal->macphymode = DUALMAC_DUALPHY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("MacPhyMode DUALMAC_DUALPHY\n")); + } +} + +static void _rtl92de_read_macphymode_and_bandtype(struct ieee80211_hw *hw, + u8 *content) +{ + _rtl92de_read_macphymode_from_prom(hw, content); + rtl92d_phy_config_macphymode(hw); + rtl92d_phy_config_macphymode_info(hw); +} + +static void _rtl92de_efuse_update_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + enum version_8192d chipver = rtlpriv->rtlhal.version; + u8 cutvalue[2]; + u16 chipvalue; + + rtlpriv->intf_ops->read_efuse_byte(hw, EEPROME_CHIP_VERSION_H, + &cutvalue[1]); + rtlpriv->intf_ops->read_efuse_byte(hw, EEPROME_CHIP_VERSION_L, + &cutvalue[0]); + chipvalue = (cutvalue[1] << 8) | cutvalue[0]; + switch (chipvalue) { + case 0xAA55: + chipver |= CHIP_92D_C_CUT; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("C-CUT!!!\n")); + break; + case 0x9966: + chipver |= CHIP_92D_D_CUT; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("D-CUT!!!\n")); + break; + default: + chipver |= CHIP_92D_D_CUT; + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ("Unkown CUT!\n")); + break; + } + rtlpriv->rtlhal.version = chipver; +} + +static void _rtl92de_read_adapter_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 i, usvalue; + u8 hwinfo[HWSET_MAX_SIZE]; + u16 eeprom_id; + unsigned long flags; + + if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + spin_lock_irqsave(&globalmutex_for_power_and_efuse, flags); + rtl_efuse_shadow_map_update(hw); + _rtl92de_efuse_update_chip_version(hw); + spin_unlock_irqrestore(&globalmutex_for_power_and_efuse, flags); + memcpy((void *)hwinfo, (void *)&rtlefuse->efuse_map + [EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE); + } else if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("RTL819X Not boot from eeprom, check it !!")); + } + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), + hwinfo, HWSET_MAX_SIZE); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != RTL8190_EEPROM_ID) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("EEPROM ID(%#x) is invalid!!\n", eeprom_id)); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); + rtlefuse->autoload_failflag = false; + } + if (rtlefuse->autoload_failflag) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("RTL819X Not boot from eeprom, check it !!")); + return; + } + rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID]; + _rtl92de_read_macphymode_and_bandtype(hw, hwinfo); + + /* VID, DID SE 0xA-D */ + rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; + rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; + rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; + rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROMId = 0x%4x\n", eeprom_id)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid)); + + /* Read Permanent MAC address */ + if (rtlhal->interfaceindex == 0) { + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR_MAC0_92D + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + } else { + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR_MAC1_92D + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + } + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, + rtlefuse->dev_addr); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + (MAC_FMT "\n", MAC_ARG(rtlefuse->dev_addr))); + _rtl92de_read_txpower_info(hw, rtlefuse->autoload_failflag, hwinfo); + + /* Read Channel Plan */ + switch (rtlhal->bandset) { + case BAND_ON_2_4G: + rtlefuse->channel_plan = COUNTRY_CODE_TELEC; + break; + case BAND_ON_5G: + rtlefuse->channel_plan = COUNTRY_CODE_FCC; + break; + case BAND_ON_BOTH: + rtlefuse->channel_plan = COUNTRY_CODE_FCC; + break; + default: + rtlefuse->channel_plan = COUNTRY_CODE_FCC; + break; + } + rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; + rtlefuse->txpwr_fromeprom = true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid)); +} + +void rtl92de_read_eeprom_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp_u1b; + + rtlhal->version = _rtl92de_read_chip_version(hw); + tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); + rtlefuse->autoload_status = tmp_u1b; + if (tmp_u1b & BIT(4)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n")); + rtlefuse->epromtype = EEPROM_93C46; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n")); + rtlefuse->epromtype = EEPROM_BOOT_EFUSE; + } + if (tmp_u1b & BIT(5)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); + + rtlefuse->autoload_failflag = false; + _rtl92de_read_adapter_info(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); + } + return; +} + +static void rtl92de_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; + u8 ratr_index = 0; + u8 nmode = mac->ht_enable; + u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate; + u32 tmp_ratr_value; + u8 curtxbw_40mhz = mac->bw_40; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = mac->mode; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_A: + ratr_value &= 0x00000FF0; + break; + case WIRELESS_MODE_B: + if (ratr_value & 0x0000000c) + ratr_value &= 0x0000000d; + else + ratr_value &= 0x0000000f; + break; + case WIRELESS_MODE_G: + ratr_value &= 0x00000FF5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + nmode = 1; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; + + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) { + ratr_mask = 0x000ff005; + } else { + ratr_mask = 0x0f0ff005; + } + + ratr_value &= ratr_mask; + } + break; + default: + if (rtlphy->rf_type == RF_1T2R) + ratr_value &= 0x000ff0ff; + else + ratr_value &= 0x0f0ff0ff; + + break; + } + ratr_value &= 0x0FFFFFFF; + if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz))) { + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & tmp_ratr_value) + break; + } + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + } + rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + ("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0))); +} + +static void rtl92de_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; + u8 ratr_index; + u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; + bool shortgi = false; + u32 value[2]; + u8 macid = 0; + u8 mimo_ps = IEEE80211_SMPS_OFF; + + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + mimo_ps = sta_entry->mimo_ps; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + ratr_index = RATR_INX_WIRELESS_B; + if (ratr_bitmap & 0x0000000c) + ratr_bitmap &= 0x0000000d; + else + ratr_bitmap &= 0x0000000f; + break; + case WIRELESS_MODE_G: + ratr_index = RATR_INX_WIRELESS_GB; + + if (rssi_level == 1) + ratr_bitmap &= 0x00000f00; + else if (rssi_level == 2) + ratr_bitmap &= 0x00000ff0; + else + ratr_bitmap &= 0x00000ff5; + break; + case WIRELESS_MODE_A: + ratr_index = RATR_INX_WIRELESS_G; + ratr_bitmap &= 0x00000ff0; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + if (wirelessmode == WIRELESS_MODE_N_24G) + ratr_index = RATR_INX_WIRELESS_NGB; + else + ratr_index = RATR_INX_WIRELESS_NG; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0007f000; + else + ratr_bitmap &= 0x0007f005; + } else { + if (rtlphy->rf_type == RF_1T2R || + rtlphy->rf_type == RF_1T1R) { + if (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff005; + } + } else { + if (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff005; + } + } + } + if ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz)) { + + if (macid == 0) + shortgi = true; + else if (macid == 1) + shortgi = false; + } + break; + default: + ratr_index = RATR_INX_WIRELESS_NGB; + + if (rtlphy->rf_type == RF_1T2R) + ratr_bitmap &= 0x000ff0ff; + else + ratr_bitmap &= 0x0f0ff0ff; + break; + } + + value[0] = (ratr_bitmap & 0x0fffffff) | (ratr_index << 28); + value[1] = macid | (shortgi ? 0x20 : 0x00) | 0x80; + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + ("ratr_bitmap :%x value0:%x value1:%x\n", + ratr_bitmap, value[0], value[1])); + rtl92d_fill_h2c_cmd(hw, H2C_RA_MASK, 5, (u8 *) value); + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92de_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm.useramask) + rtl92de_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92de_update_hal_rate_table(hw, sta); +} + +void rtl92de_update_channel_access_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 sifs_timer; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, + (u8 *)&mac->slot_time); + if (!mac->ht_enable) + sifs_timer = 0x0a0a; + else + sifs_timer = 0x1010; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); +} + +bool rtl92de_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + enum rf_pwrstate e_rfpowerstate_toset; + u8 u1tmp; + bool actuallyset = false; + unsigned long flag; + + if (rtlpci->being_init_adapter) + return false; + if (ppsc->swrf_processing) + return false; + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (ppsc->rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return false; + } else { + ppsc->rfchange_inprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv, + REG_MAC_PINMUX_CFG) & ~(BIT(3))); + u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL); + e_rfpowerstate_toset = (u1tmp & BIT(3)) ? ERFON : ERFOFF; + if (ppsc->hwradiooff && (e_rfpowerstate_toset == ERFON)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("GPIOChangeRF - HW Radio ON, RF ON\n")); + e_rfpowerstate_toset = ERFON; + ppsc->hwradiooff = false; + actuallyset = true; + } else if ((ppsc->hwradiooff == false) + && (e_rfpowerstate_toset == ERFOFF)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("GPIOChangeRF - HW Radio OFF, RF OFF\n")); + e_rfpowerstate_toset = ERFOFF; + ppsc->hwradiooff = true; + actuallyset = true; + } + if (actuallyset) { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } else { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + *valid = 1; + return !ppsc->hwradiooff; +} + +void rtl92de_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 *macaddr = p_macaddr; + u32 entry_id; + bool is_pairwise = false; + static u8 cam_const_addr[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} + }; + static u8 cam_const_broad[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + if (clear_all) { + u8 idx; + u8 cam_offset = 0; + u8 clear_number = 5; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("clear_all\n")); + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + rtl_cam_empty_entry(hw, cam_offset + idx); + + if (idx < 5) { + memset(rtlpriv->sec.key_buf[idx], 0, + MAX_KEY_LEN); + rtlpriv->sec.key_len[idx] = 0; + } + } + } else { + switch (enc_algo) { + case WEP40_ENCRYPTION: + enc_algo = CAM_WEP40; + break; + case WEP104_ENCRYPTION: + enc_algo = CAM_WEP104; + break; + case TKIP_ENCRYPTION: + enc_algo = CAM_TKIP; + break; + case AESCCMP_ENCRYPTION: + enc_algo = CAM_AES; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case " + "not process\n")); + enc_algo = CAM_TKIP; + break; + } + if (is_wepkey || rtlpriv->sec.use_defaultkey) { + macaddr = cam_const_addr[key_index]; + entry_id = key_index; + } else { + if (is_group) { + macaddr = cam_const_broad; + entry_id = key_index; + } else { + if (mac->opmode == NL80211_IFTYPE_AP) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, COMP_SEC, + DBG_EMERG, ("Can not " + "find free hw security" + " cam entry\n")); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + key_index = PAIRWISE_KEYIDX; + is_pairwise = true; + } + } + if (rtlpriv->sec.key_len[key_index] == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("delete one entry, entry_id is %d\n", + entry_id)); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The insert KEY length is %d\n", + rtlpriv->sec.key_len[PAIRWISE_KEYIDX])); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The insert KEY is %x %x\n", + rtlpriv->sec.key_buf[0][0], + rtlpriv->sec.key_buf[0][1])); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("add one entry\n")); + if (is_pairwise) { + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, + "Pairwiase Key content :", + rtlpriv->sec.pairwise_key, + rtlpriv-> + sec.key_len[PAIRWISE_KEYIDX]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set Pairwiase key\n")); + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv-> + sec.key_buf[key_index]); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set group key\n")); + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + rtl_cam_add_one_entry(hw, + rtlefuse->dev_addr, + PAIRWISE_KEYIDX, + CAM_PAIRWISE_KEY_POSITION, + enc_algo, CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf + [entry_id]); + } + } + } +} + +void rtl92de_suspend(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->rtlhal.macphyctl_reg = rtl_read_byte(rtlpriv, + REG_MAC_PHY_CTRL_NORMAL); +} + +void rtl92de_resume(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL, + rtlpriv->rtlhal.macphyctl_reg); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.h b/drivers/net/wireless/rtlwifi/rtl8192de/hw.h new file mode 100644 index 000000000000..ad44ffa520e6 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.h @@ -0,0 +1,66 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92DE_HW_H__ +#define __RTL92DE_HW_H__ + +void rtl92de_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92de_read_eeprom_info(struct ieee80211_hw *hw); +void rtl92de_interrupt_recognized(struct ieee80211_hw *hw, + u32 *p_inta, u32 *p_intb); +int rtl92de_hw_init(struct ieee80211_hw *hw); +void rtl92de_card_disable(struct ieee80211_hw *hw); +void rtl92de_enable_interrupt(struct ieee80211_hw *hw); +void rtl92de_disable_interrupt(struct ieee80211_hw *hw); +int rtl92de_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92de_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl92de_set_qos(struct ieee80211_hw *hw, int aci); +void rtl92de_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl92de_set_beacon_interval(struct ieee80211_hw *hw); +void rtl92de_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); +void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92de_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); +void rtl92de_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl92de_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); +void rtl92de_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl92de_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); + +extern void rtl92de_write_dword_dbi(struct ieee80211_hw *hw, u16 offset, + u32 value, u8 direct); +extern u32 rtl92de_read_dword_dbi(struct ieee80211_hw *hw, u16 offset, + u8 direct); +void rtl92de_suspend(struct ieee80211_hw *hw); +void rtl92de_resume(struct ieee80211_hw *hw); +void rtl92d_linked_set_reg(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/led.c b/drivers/net/wireless/rtlwifi/rtl8192de/led.c new file mode 100644 index 000000000000..f1552f4df658 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/led.c @@ -0,0 +1,159 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" +#include "led.h" + +static void _rtl92ce_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + +void rtl92de_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin)); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + + if ((rtlpriv->efuse.eeprom_did == 0x8176) || + (rtlpriv->efuse.eeprom_did == 0x8193)) + /* BIT7 of REG_LEDCFG2 should be set to + * make sure we could emit the led2. */ + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0xf0) | + BIT(7) | BIT(5) | BIT(6)); + else + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0xf0) | + BIT(7) | BIT(5)); + break; + case LED_PIN_LED1: + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1); + + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + pled->ledon = true; +} + +void rtl92de_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u8 ledcfg; + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin)); + + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (pcipriv->ledctl.led_opendrain) + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(1) | BIT(5) | BIT(6))); + else + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(3) | BIT(5) | BIT(6))); + break; + case LED_PIN_LED1: + ledcfg &= 0x0f; + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + pled->ledon = false; +} + +void rtl92de_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +static void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + switch (ledaction) { + case LED_CTL_POWER_ON: + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + rtl92de_sw_led_on(hw, pLed0); + break; + case LED_CTL_POWER_OFF: + rtl92de_sw_led_off(hw, pLed0); + break; + default: + break; + } +} + +void rtl92de_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && + (ledaction == LED_CTL_TX || + ledaction == LED_CTL_RX || + ledaction == LED_CTL_SITE_SURVEY || + ledaction == LED_CTL_LINK || + ledaction == LED_CTL_NO_LINK || + ledaction == LED_CTL_START_TO_LINK || + ledaction == LED_CTL_POWER_ON)) { + return; + } + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", ledaction)); + + _rtl92ce_sw_led_control(hw, ledaction); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/led.h b/drivers/net/wireless/rtlwifi/rtl8192de/led.h new file mode 100644 index 000000000000..57f4a3c583d4 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/led.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92CE_LED_H__ +#define __RTL92CE_LED_H__ + +void rtl92de_init_sw_leds(struct ieee80211_hw *hw); +void rtl92de_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92de_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92de_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c new file mode 100644 index 000000000000..3ac7af1c5509 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -0,0 +1,3831 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../ps.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "table.h" +#include "sw.h" +#include "hw.h" + +#define MAX_RF_IMR_INDEX 12 +#define MAX_RF_IMR_INDEX_NORMAL 13 +#define RF_REG_NUM_FOR_C_CUT_5G 6 +#define RF_REG_NUM_FOR_C_CUT_5G_INTERNALPA 7 +#define RF_REG_NUM_FOR_C_CUT_2G 5 +#define RF_CHNL_NUM_5G 19 +#define RF_CHNL_NUM_5G_40M 17 +#define TARGET_CHNL_NUM_5G 221 +#define TARGET_CHNL_NUM_2G 14 +#define CV_CURVE_CNT 64 + +static u32 rf_reg_for_5g_swchnl_normal[MAX_RF_IMR_INDEX_NORMAL] = { + 0, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x0 +}; + +static u8 rf_reg_for_c_cut_5g[RF_REG_NUM_FOR_C_CUT_5G] = { + RF_SYN_G1, RF_SYN_G2, RF_SYN_G3, RF_SYN_G4, RF_SYN_G5, RF_SYN_G6 +}; + +static u8 rf_reg_for_c_cut_2g[RF_REG_NUM_FOR_C_CUT_2G] = { + RF_SYN_G1, RF_SYN_G2, RF_SYN_G3, RF_SYN_G7, RF_SYN_G8 +}; + +static u8 rf_for_c_cut_5g_internal_pa[RF_REG_NUM_FOR_C_CUT_5G_INTERNALPA] = { + 0x0B, 0x48, 0x49, 0x4B, 0x03, 0x04, 0x0E +}; + +static u32 rf_reg_mask_for_c_cut_2g[RF_REG_NUM_FOR_C_CUT_2G] = { + BIT(19) | BIT(18) | BIT(17) | BIT(14) | BIT(1), + BIT(10) | BIT(9), + BIT(18) | BIT(17) | BIT(16) | BIT(1), + BIT(2) | BIT(1), + BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) +}; + +static u8 rf_chnl_5g[RF_CHNL_NUM_5G] = { + 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, + 112, 116, 120, 124, 128, 132, 136, 140 +}; + +static u8 rf_chnl_5g_40m[RF_CHNL_NUM_5G_40M] = { + 38, 42, 46, 50, 54, 58, 62, 102, 106, 110, 114, + 118, 122, 126, 130, 134, 138 +}; +static u32 rf_reg_pram_c_5g[5][RF_REG_NUM_FOR_C_CUT_5G] = { + {0xE43BE, 0xFC638, 0x77C0A, 0xDE471, 0xd7110, 0x8EB04}, + {0xE43BE, 0xFC078, 0xF7C1A, 0xE0C71, 0xD7550, 0xAEB04}, + {0xE43BF, 0xFF038, 0xF7C0A, 0xDE471, 0xE5550, 0xAEB04}, + {0xE43BF, 0xFF079, 0xF7C1A, 0xDE471, 0xE5550, 0xAEB04}, + {0xE43BF, 0xFF038, 0xF7C1A, 0xDE471, 0xd7550, 0xAEB04} +}; + +static u32 rf_reg_param_for_c_cut_2g[3][RF_REG_NUM_FOR_C_CUT_2G] = { + {0x643BC, 0xFC038, 0x77C1A, 0x41289, 0x01840}, + {0x643BC, 0xFC038, 0x07C1A, 0x41289, 0x01840}, + {0x243BC, 0xFC438, 0x07C1A, 0x4128B, 0x0FC41} +}; + +static u32 rf_syn_g4_for_c_cut_2g = 0xD1C31 & 0x7FF; + +static u32 rf_pram_c_5g_int_pa[3][RF_REG_NUM_FOR_C_CUT_5G_INTERNALPA] = { + {0x01a00, 0x40443, 0x00eb5, 0x89bec, 0x94a12, 0x94a12, 0x94a12}, + {0x01800, 0xc0443, 0x00730, 0x896ee, 0x94a52, 0x94a52, 0x94a52}, + {0x01800, 0xc0443, 0x00730, 0x896ee, 0x94a12, 0x94a12, 0x94a12} +}; + +/* [mode][patha+b][reg] */ +static u32 rf_imr_param_normal[1][3][MAX_RF_IMR_INDEX_NORMAL] = { + { + /* channel 1-14. */ + { + 0x70000, 0x00ff0, 0x4400f, 0x00ff0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x64888, 0xe266c, 0x00090, 0x22fff + }, + /* path 36-64 */ + { + 0x70000, 0x22880, 0x4470f, 0x55880, 0x00070, 0x88000, + 0x0, 0x88080, 0x70000, 0x64a82, 0xe466c, 0x00090, + 0x32c9a + }, + /* 100 -165 */ + { + 0x70000, 0x44880, 0x4477f, 0x77880, 0x00070, 0x88000, + 0x0, 0x880b0, 0x0, 0x64b82, 0xe466c, 0x00090, 0x32c9a + } + } +}; + +static u32 curveindex_5g[TARGET_CHNL_NUM_5G] = {0}; + +static u32 curveindex_2g[TARGET_CHNL_NUM_2G] = {0}; + +static u32 targetchnl_5g[TARGET_CHNL_NUM_5G] = { + 25141, 25116, 25091, 25066, 25041, + 25016, 24991, 24966, 24941, 24917, + 24892, 24867, 24843, 24818, 24794, + 24770, 24765, 24721, 24697, 24672, + 24648, 24624, 24600, 24576, 24552, + 24528, 24504, 24480, 24457, 24433, + 24409, 24385, 24362, 24338, 24315, + 24291, 24268, 24245, 24221, 24198, + 24175, 24151, 24128, 24105, 24082, + 24059, 24036, 24013, 23990, 23967, + 23945, 23922, 23899, 23876, 23854, + 23831, 23809, 23786, 23764, 23741, + 23719, 23697, 23674, 23652, 23630, + 23608, 23586, 23564, 23541, 23519, + 23498, 23476, 23454, 23432, 23410, + 23388, 23367, 23345, 23323, 23302, + 23280, 23259, 23237, 23216, 23194, + 23173, 23152, 23130, 23109, 23088, + 23067, 23046, 23025, 23003, 22982, + 22962, 22941, 22920, 22899, 22878, + 22857, 22837, 22816, 22795, 22775, + 22754, 22733, 22713, 22692, 22672, + 22652, 22631, 22611, 22591, 22570, + 22550, 22530, 22510, 22490, 22469, + 22449, 22429, 22409, 22390, 22370, + 22350, 22336, 22310, 22290, 22271, + 22251, 22231, 22212, 22192, 22173, + 22153, 22134, 22114, 22095, 22075, + 22056, 22037, 22017, 21998, 21979, + 21960, 21941, 21921, 21902, 21883, + 21864, 21845, 21826, 21807, 21789, + 21770, 21751, 21732, 21713, 21695, + 21676, 21657, 21639, 21620, 21602, + 21583, 21565, 21546, 21528, 21509, + 21491, 21473, 21454, 21436, 21418, + 21400, 21381, 21363, 21345, 21327, + 21309, 21291, 21273, 21255, 21237, + 21219, 21201, 21183, 21166, 21148, + 21130, 21112, 21095, 21077, 21059, + 21042, 21024, 21007, 20989, 20972, + 25679, 25653, 25627, 25601, 25575, + 25549, 25523, 25497, 25471, 25446, + 25420, 25394, 25369, 25343, 25318, + 25292, 25267, 25242, 25216, 25191, + 25166 +}; + +/* channel 1~14 */ +static u32 targetchnl_2g[TARGET_CHNL_NUM_2G] = { + 26084, 26030, 25976, 25923, 25869, 25816, 25764, + 25711, 25658, 25606, 25554, 25502, 25451, 25328 +}; + +static u32 _rtl92d_phy_calculate_bit_shift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((bitmask >> i) & 0x1) == 1) + break; + } + + return i; +} + +u32 rtl92d_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u32 returnvalue, originalvalue, bitshift; + u8 dbi_direct; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), " + "bitmask(%#x)\n", regaddr, bitmask)); + if (rtlhal->during_mac1init_radioa || rtlhal->during_mac0init_radiob) { + /* mac1 use phy0 read radio_b. */ + /* mac0 use phy1 read radio_b. */ + if (rtlhal->during_mac1init_radioa) + dbi_direct = BIT(3); + else if (rtlhal->during_mac0init_radiob) + dbi_direct = BIT(3) | BIT(2); + originalvalue = rtl92de_read_dword_dbi(hw, (u16)regaddr, + dbi_direct); + } else { + originalvalue = rtl_read_dword(rtlpriv, regaddr); + } + bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); + returnvalue = (originalvalue & bitmask) >> bitshift; + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("BBR MASK=0x%x " + "Addr[0x%x]=0x%x\n", bitmask, regaddr, originalvalue)); + return returnvalue; +} + +void rtl92d_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 dbi_direct = 0; + u32 originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x)\n", regaddr, bitmask, data)); + if (rtlhal->during_mac1init_radioa) + dbi_direct = BIT(3); + else if (rtlhal->during_mac0init_radiob) + /* mac0 use phy1 write radio_b. */ + dbi_direct = BIT(3) | BIT(2); + if (bitmask != BMASKDWORD) { + if (rtlhal->during_mac1init_radioa || + rtlhal->during_mac0init_radiob) + originalvalue = rtl92de_read_dword_dbi(hw, + (u16) regaddr, + dbi_direct); + else + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); + data = ((originalvalue & (~bitmask)) | (data << bitshift)); + } + if (rtlhal->during_mac1init_radioa || rtlhal->during_mac0init_radiob) + rtl92de_write_dword_dbi(hw, (u16) regaddr, data, dbi_direct); + else + rtl_write_dword(rtlpriv, regaddr, data); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x)\n", regaddr, bitmask, data)); +} + +static u32 _rtl92d_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset) +{ + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + u32 newoffset; + u32 tmplong, tmplong2; + u8 rfpi_enable = 0; + u32 retvalue; + + newoffset = offset; + tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD); + if (rfpath == RF90_PATH_A) + tmplong2 = tmplong; + else + tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD); + tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | + (newoffset << 23) | BLSSIREADEDGE; + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD, + tmplong & (~BLSSIREADEDGE)); + udelay(10); + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD, tmplong2); + udelay(50); + udelay(50); + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD, + tmplong | BLSSIREADEDGE); + udelay(10); + if (rfpath == RF90_PATH_A) + rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, + BIT(8)); + else if (rfpath == RF90_PATH_B) + rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, + BIT(8)); + if (rfpi_enable) + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, + BLSSIREADBACKDATA); + else + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, + BLSSIREADBACKDATA); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFR-%d Addr[0x%x] = 0x%x\n", + rfpath, pphyreg->rflssi_readback, retvalue)); + return retvalue; +} + +static void _rtl92d_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 offset, u32 data) +{ + u32 data_and_addr; + u32 newoffset; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + + newoffset = offset; + /* T65 RF */ + data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, BMASKDWORD, data_and_addr); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFW-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rf3wire_offset, data_and_addr)); +} + +u32 rtl92d_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 original_value, readback_value, bitshift; + unsigned long flags; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), " + "rfpath(%#x), bitmask(%#x)\n", + regaddr, rfpath, bitmask)); + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + original_value = _rtl92d_phy_rf_serial_read(hw, rfpath, regaddr); + bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); + readback_value = (original_value & bitmask) >> bitshift; + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " + "bitmask(%#x), original_value(%#x)\n", + regaddr, rfpath, bitmask, original_value)); + return readback_value; +} + +void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 original_value, bitshift; + unsigned long flags; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + ("regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath)); + if (bitmask == 0) + return; + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + if (rtlphy->rf_mode != RF_OP_BY_FW) { + if (bitmask != BRFREGOFFSETMASK) { + original_value = _rtl92d_phy_rf_serial_read(hw, + rfpath, regaddr); + bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); + data = ((original_value & (~bitmask)) | + (data << bitshift)); + } + _rtl92d_phy_rf_serial_write(hw, rfpath, regaddr, data); + } + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), " + "bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, rfpath)); +} + +bool rtl92d_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + u32 arraylength; + u32 *ptrarray; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Read Rtl819XMACPHY_Array\n")); + arraylength = MAC_2T_ARRAYLENGTH; + ptrarray = rtl8192de_mac_2tarray; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Img:Rtl819XMAC_Array\n")); + for (i = 0; i < arraylength; i = i + 2) + rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]); + if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) { + /* improve 2-stream TX EVM */ + /* rtl_write_byte(rtlpriv, 0x14,0x71); */ + /* AMPDU aggregation number 9 */ + /* rtl_write_word(rtlpriv, REG_MAX_AGGR_NUM, MAX_AGGR_NUM); */ + rtl_write_byte(rtlpriv, REG_MAX_AGGR_NUM, 0x0B); + } else { + /* 92D need to test to decide the num. */ + rtl_write_byte(rtlpriv, REG_MAX_AGGR_NUM, 0x07); + } + return true; +} + +static void _rtl92d_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* RF Interface Sowrtware Control */ + /* 16 LSBs if read 32-bit from 0x870 */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; + /* 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */ + rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; + /* 16 LSBs if read 32-bit from 0x874 */ + rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; + /* 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) */ + + rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; + /* RF Interface Readback Value */ + /* 16 LSBs if read 32-bit from 0x8E0 */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; + /* 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */ + rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; + /* 16 LSBs if read 32-bit from 0x8E4 */ + rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; + /* 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) */ + rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; + + /* RF Interface Output (and Enable) */ + /* 16 LSBs if read 32-bit from 0x860 */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; + /* 16 LSBs if read 32-bit from 0x864 */ + rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + + /* RF Interface (Output and) Enable */ + /* 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; + /* 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */ + rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + + /* Addr of LSSI. Wirte RF register by driver */ + /* LSSI Parameter */ + rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = + RFPGA0_XA_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = + RFPGA0_XB_LSSIPARAMETER; + + /* RF parameter */ + /* BB Band Select */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER; + + /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ + /* Tx gain stage */ + rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; + /* Tx gain stage */ + rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; + /* Tx gain stage */ + rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; + /* Tx gain stage */ + rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; + + /* Tranceiver A~D HSSI Parameter-1 */ + /* wire control parameter1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; + /* wire control parameter1 */ + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; + + /* Tranceiver A~D HSSI Parameter-2 */ + /* wire control parameter2 */ + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; + /* wire control parameter2 */ + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; + + /* RF switch Control */ + /* TR/Ant switch control */ + rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + + /* AGC control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; + + /* AGC control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; + + /* RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = + ROFDM0_XARXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = + ROFDM0_XBRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = + ROFDM0_XCRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = + ROFDM0_XDRXIQIMBALANCE; + + /*RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; + + /* Tx AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = + ROFDM0_XATxIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = + ROFDM0_XBTxIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = + ROFDM0_XCTxIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = + ROFDM0_XDTxIQIMBALANCE; + + /* Tx AFE control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATxAFE; + rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTxAFE; + rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTxAFE; + rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTxAFE; + + /* Tranceiver LSSI Readback SI mode */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = + RFPGA0_XA_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = + RFPGA0_XB_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback = + RFPGA0_XC_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = + RFPGA0_XD_LSSIREADBACK; + + /* Tranceiver LSSI Readback PI mode */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = + TRANSCEIVERA_HSPI_READBACK; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = + TRANSCEIVERB_HSPI_READBACK; +} + +static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype) +{ + int i; + u32 *phy_regarray_table; + u32 *agctab_array_table = NULL; + u32 *agctab_5garray_table; + u16 phy_reg_arraylen, agctab_arraylen = 0, agctab_5garraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + /* Normal chip,Mac0 use AGC_TAB.txt for 2G and 5G band. */ + if (rtlhal->interfaceindex == 0) { + agctab_arraylen = AGCTAB_ARRAYLENGTH; + agctab_array_table = rtl8192de_agctab_array; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + (" ===> phy:MAC0, Rtl819XAGCTAB_Array\n")); + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + agctab_arraylen = AGCTAB_2G_ARRAYLENGTH; + agctab_array_table = rtl8192de_agctab_2garray; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + (" ===> phy:MAC1, Rtl819XAGCTAB_2GArray\n")); + } else { + agctab_5garraylen = AGCTAB_5G_ARRAYLENGTH; + agctab_5garray_table = rtl8192de_agctab_5garray; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + (" ===> phy:MAC1, Rtl819XAGCTAB_5GArray\n")); + + } + } + phy_reg_arraylen = PHY_REG_2T_ARRAYLENGTH; + phy_regarray_table = rtl8192de_phy_reg_2tarray; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + (" ===> phy:Rtl819XPHY_REG_Array_PG\n")); + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_reg_arraylen; i = i + 2) { + if (phy_regarray_table[i] == 0xfe) + mdelay(50); + else if (phy_regarray_table[i] == 0xfd) + mdelay(5); + else if (phy_regarray_table[i] == 0xfc) + mdelay(1); + else if (phy_regarray_table[i] == 0xfb) + udelay(50); + else if (phy_regarray_table[i] == 0xfa) + udelay(5); + else if (phy_regarray_table[i] == 0xf9) + udelay(1); + rtl_set_bbreg(hw, phy_regarray_table[i], BMASKDWORD, + phy_regarray_table[i + 1]); + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("The phy_regarray_table[0] is %x" + " Rtl819XPHY_REGArray[1] is %x\n", + phy_regarray_table[i], + phy_regarray_table[i + 1])); + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + if (rtlhal->interfaceindex == 0) { + for (i = 0; i < agctab_arraylen; i = i + 2) { + rtl_set_bbreg(hw, agctab_array_table[i], + BMASKDWORD, + agctab_array_table[i + 1]); + /* Add 1us delay between BB/RF register + * setting. */ + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("The Rtl819XAGCTAB_Array_" + "Table[0] is %ul " + "Rtl819XPHY_REGArray[1] is %ul\n", + agctab_array_table[i], + agctab_array_table[i + 1])); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Normal Chip, MAC0, load " + "Rtl819XAGCTAB_Array\n")); + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + for (i = 0; i < agctab_arraylen; i = i + 2) { + rtl_set_bbreg(hw, agctab_array_table[i], + BMASKDWORD, + agctab_array_table[i + 1]); + /* Add 1us delay between BB/RF register + * setting. */ + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("The Rtl819XAGCTAB_Array_" + "Table[0] is %ul Rtl819XPHY_" + "REGArray[1] is %ul\n", + agctab_array_table[i], + agctab_array_table[i + 1])); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Load Rtl819XAGCTAB_2GArray\n")); + } else { + for (i = 0; i < agctab_5garraylen; i = i + 2) { + rtl_set_bbreg(hw, + agctab_5garray_table[i], + BMASKDWORD, + agctab_5garray_table[i + 1]); + /* Add 1us delay between BB/RF registeri + * setting. */ + udelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("The Rtl819XAGCTAB_5GArray_" + "Table[0] is %ul Rtl819XPHY_" + "REGArray[1] is %ul\n", + agctab_5garray_table[i], + agctab_5garray_table[i + 1])); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Load Rtl819XAGCTAB_5GArray\n")); + } + } + } + return true; +} + +static void _rtl92d_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, + u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (regaddr == RTXAGC_A_RATE18_06) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][0] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][0])); + } + if (regaddr == RTXAGC_A_RATE54_24) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][1] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][1])); + } + if (regaddr == RTXAGC_A_CCK1_MCS32) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][6] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][6])); + } + if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][7] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][7] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][7])); + } + if (regaddr == RTXAGC_A_MCS03_MCS00) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][2] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][2])); + } + if (regaddr == RTXAGC_A_MCS07_MCS04) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][3] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][3])); + } + if (regaddr == RTXAGC_A_MCS11_MCS08) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][4] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][4])); + } + if (regaddr == RTXAGC_A_MCS15_MCS12) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][5] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][5])); + } + if (regaddr == RTXAGC_B_RATE18_06) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][8] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][8] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][8])); + } + if (regaddr == RTXAGC_B_RATE54_24) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][9] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][9])); + } + if (regaddr == RTXAGC_B_CCK1_55_MCS32) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][14] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][14])); + } + if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][15] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][15])); + } + if (regaddr == RTXAGC_B_MCS03_MCS00) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][10] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][10])); + } + if (regaddr == RTXAGC_B_MCS07_MCS04) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][11] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][11])); + } + if (regaddr == RTXAGC_B_MCS11_MCS08) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][12] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][12])); + } + if (regaddr == RTXAGC_B_MCS15_MCS12) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][13] = + data; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%ulx\n", + rtlphy->pwrgroup_cnt, + rtlphy->mcs_txpwrlevel_origoffset + [rtlphy->pwrgroup_cnt][13])); + rtlphy->pwrgroup_cnt++; + } +} + +static bool _rtl92d_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + u32 *phy_regarray_table_pg; + u16 phy_regarray_pg_len; + + phy_regarray_pg_len = PHY_REG_ARRAY_PG_LENGTH; + phy_regarray_table_pg = rtl8192de_phy_reg_array_pg; + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray_pg_len; i = i + 3) { + if (phy_regarray_table_pg[i] == 0xfe) + mdelay(50); + else if (phy_regarray_table_pg[i] == 0xfd) + mdelay(5); + else if (phy_regarray_table_pg[i] == 0xfc) + mdelay(1); + else if (phy_regarray_table_pg[i] == 0xfb) + udelay(50); + else if (phy_regarray_table_pg[i] == 0xfa) + udelay(5); + else if (phy_regarray_table_pg[i] == 0xf9) + udelay(1); + _rtl92d_store_pwrindex_diffrate_offset(hw, + phy_regarray_table_pg[i], + phy_regarray_table_pg[i + 1], + phy_regarray_table_pg[i + 2]); + } + } else { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + ("configtype != BaseBand_Config_PHY_REG\n")); + } + return true; +} + +static bool _rtl92d_phy_bb_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + bool rtstatus = true; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("==>\n")); + rtstatus = _rtl92d_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_PHY_REG); + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Write BB Reg Fail!!")); + return false; + } + + /* if (rtlphy->rf_type == RF_1T2R) { + * _rtl92c_phy_bb_config_1t(hw); + * RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Config to 1T!!\n")); + *} */ + + if (rtlefuse->autoload_failflag == false) { + rtlphy->pwrgroup_cnt = 0; + rtstatus = _rtl92d_phy_config_bb_with_pgheaderfile(hw, + BASEBAND_CONFIG_PHY_REG); + } + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("BB_PG Reg Fail!!")); + return false; + } + rtstatus = _rtl92d_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("AGC Table Fail\n")); + return false; + } + rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, 0x200)); + + return true; +} + +bool rtl92d_phy_bb_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 regval; + u32 regvaldw; + u8 value; + + _rtl92d_phy_init_bb_rf_register_definition(hw); + regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, + regval | BIT(13) | BIT(0) | BIT(1)); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); + /* 0x1f bit7 bit6 represent for mac0/mac1 driver ready */ + value = rtl_read_byte(rtlpriv, REG_RF_CTRL); + rtl_write_byte(rtlpriv, REG_RF_CTRL, value | RF_EN | RF_RSTB | + RF_SDMRSTB); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, FEN_PPLL | FEN_PCIEA | + FEN_DIO_PCIE | FEN_BB_GLB_RSTn | FEN_BBRSTB); + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); + if (!(IS_92D_SINGLEPHY(rtlpriv->rtlhal.version))) { + regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); + rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); + } + + return _rtl92d_phy_bb_config(hw); +} + +bool rtl92d_phy_rf_config(struct ieee80211_hw *hw) +{ + return rtl92d_phy_rf6052_config(hw); +} + +bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum rf_content content, + enum radio_path rfpath) +{ + int i; + u32 *radioa_array_table; + u32 *radiob_array_table; + u16 radioa_arraylen, radiob_arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + radioa_arraylen = RADIOA_2T_ARRAYLENGTH; + radioa_array_table = rtl8192de_radioa_2tarray; + radiob_arraylen = RADIOB_2T_ARRAYLENGTH; + radiob_array_table = rtl8192de_radiob_2tarray; + if (rtlpriv->efuse.internal_pa_5g[0]) { + radioa_arraylen = RADIOA_2T_INT_PA_ARRAYLENGTH; + radioa_array_table = rtl8192de_radioa_2t_int_paarray; + } + if (rtlpriv->efuse.internal_pa_5g[1]) { + radiob_arraylen = RADIOB_2T_INT_PA_ARRAYLENGTH; + radiob_array_table = rtl8192de_radiob_2t_int_paarray; + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("PHY_ConfigRFWithHeaderFile() " + "Radio_A:Rtl819XRadioA_1TArray\n")); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("PHY_ConfigRFWithHeaderFile() " + "Radio_B:Rtl819XRadioB_1TArray\n")); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Radio No %x\n", rfpath)); + + /* this only happens when DMDP, mac0 start on 2.4G, + * mac1 start on 5G, mac 0 has to set phy0&phy1 + * pathA or mac1 has to set phy0&phy1 pathA */ + if ((content == radiob_txt) && (rfpath == RF90_PATH_A)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + (" ===> althougth Path A, we load radiob.txt\n")); + radioa_arraylen = radiob_arraylen; + radioa_array_table = radiob_array_table; + } + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radioa_arraylen; i = i + 2) { + if (radioa_array_table[i] == 0xfe) { + mdelay(50); + } else if (radioa_array_table[i] == 0xfd) { + /* delay_ms(5); */ + mdelay(5); + } else if (radioa_array_table[i] == 0xfc) { + /* delay_ms(1); */ + mdelay(1); + } else if (radioa_array_table[i] == 0xfb) { + udelay(50); + } else if (radioa_array_table[i] == 0xfa) { + udelay(5); + } else if (radioa_array_table[i] == 0xf9) { + udelay(1); + } else { + rtl_set_rfreg(hw, rfpath, radioa_array_table[i], + BRFREGOFFSETMASK, + radioa_array_table[i + 1]); + /* Add 1us delay between BB/RF register set. */ + udelay(1); + } + } + break; + case RF90_PATH_B: + for (i = 0; i < radiob_arraylen; i = i + 2) { + if (radiob_array_table[i] == 0xfe) { + /* Delay specific ms. Only RF configuration + * requires delay. */ + mdelay(50); + } else if (radiob_array_table[i] == 0xfd) { + /* delay_ms(5); */ + mdelay(5); + } else if (radiob_array_table[i] == 0xfc) { + /* delay_ms(1); */ + mdelay(1); + } else if (radiob_array_table[i] == 0xfb) { + udelay(50); + } else if (radiob_array_table[i] == 0xfa) { + udelay(5); + } else if (radiob_array_table[i] == 0xf9) { + udelay(1); + } else { + rtl_set_rfreg(hw, rfpath, radiob_array_table[i], + BRFREGOFFSETMASK, + radiob_array_table[i + 1]); + /* Add 1us delay between BB/RF register set. */ + udelay(1); + } + } + break; + case RF90_PATH_C: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + case RF90_PATH_D: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + return true; +} + +void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->default_initialgain[0] = + (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, BMASKBYTE0); + rtlphy->default_initialgain[1] = + (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, BMASKBYTE0); + rtlphy->default_initialgain[2] = + (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, BMASKBYTE0); + rtlphy->default_initialgain[3] = + (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, BMASKBYTE0); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Default initial gain (c50=0x%x, " + "c58=0x%x, c60=0x%x, c68=0x%x\n", + rtlphy->default_initialgain[0], + rtlphy->default_initialgain[1], + rtlphy->default_initialgain[2], + rtlphy->default_initialgain[3])); + rtlphy->framesync = (u8)rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, + BMASKBYTE0); + rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2, + BMASKDWORD); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Default framesync (0x%x) = 0x%x\n", + ROFDM0_RXDETECTOR3, rtlphy->framesync)); +} + +static void _rtl92d_get_txpower_index(struct ieee80211_hw *hw, u8 channel, + u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 index = (channel - 1); + + /* 1. CCK */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* RF-A */ + cckpowerlevel[RF90_PATH_A] = + rtlefuse->txpwrlevel_cck[RF90_PATH_A][index]; + /* RF-B */ + cckpowerlevel[RF90_PATH_B] = + rtlefuse->txpwrlevel_cck[RF90_PATH_B][index]; + } else { + cckpowerlevel[RF90_PATH_A] = 0; + cckpowerlevel[RF90_PATH_B] = 0; + } + /* 2. OFDM for 1S or 2S */ + if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_1T1R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerlevel[RF90_PATH_A] = + rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index]; + ofdmpowerlevel[RF90_PATH_B] = + rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index]; + } else if (rtlphy->rf_type == RF_2T2R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerlevel[RF90_PATH_A] = + rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_A][index]; + ofdmpowerlevel[RF90_PATH_B] = + rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_B][index]; + } +} + +static void _rtl92d_ccxpower_index_check(struct ieee80211_hw *hw, + u8 channel, u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; + rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; +} + +static u8 _rtl92c_phy_get_rightchnlplace(u8 chnl) +{ + u8 channel_5g[59] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, + 114, 116, 118, 120, 122, 124, 126, 128, + 130, 132, 134, 136, 138, 140, 149, 151, + 153, 155, 157, 159, 161, 163, 165 + }; + u8 place = chnl; + + if (chnl > 14) { + for (place = 14; place < sizeof(channel_5g); place++) { + if (channel_5g[place] == chnl) { + place++; + break; + } + } + } + return place; +} + +void rtl92d_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 cckpowerlevel[2], ofdmpowerlevel[2]; + + if (rtlefuse->txpwr_fromeprom == false) + return; + channel = _rtl92c_phy_get_rightchnlplace(channel); + _rtl92d_get_txpower_index(hw, channel, &cckpowerlevel[0], + &ofdmpowerlevel[0]); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + _rtl92d_ccxpower_index_check(hw, channel, &cckpowerlevel[0], + &ofdmpowerlevel[0]); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + rtl92d_phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]); + rtl92d_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], channel); +} + +void rtl92d_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + enum io_type iotype; + + if (!is_hal_stop(rtlhal)) { + switch (operation) { + case SCAN_OPT_BACKUP: + rtlhal->current_bandtypebackup = + rtlhal->current_bandtype; + iotype = IO_CMD_PAUSE_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD, + (u8 *)&iotype); + break; + case SCAN_OPT_RESTORE: + iotype = IO_CMD_RESUME_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD, + (u8 *)&iotype); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Unknown Scan Backup operation.\n")); + break; + } + } +} + +void rtl92d_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + unsigned long flag = 0; + u8 reg_prsr_rsc; + u8 reg_bw_opmode; + + if (rtlphy->set_bwmode_inprogress) + return; + if ((is_hal_stop(rtlhal)) || (RT_CANNOT_IO(hw))) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("FALSE driver sleep or unload\n")); + return; + } + rtlphy->set_bwmode_inprogress = true; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, + ("Switch to %s bandwidth\n", + rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? + "20MHz" : "40MHz")); + reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); + reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + reg_bw_opmode |= BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + break; + case HT_CHANNEL_WIDTH_20_40: + reg_bw_opmode &= ~BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + + reg_prsr_rsc = (reg_prsr_rsc & 0x90) | + (mac->cur_40_prime_sc << 5); + rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); + break; + } + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); + rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); + /* SET BIT10 BIT11 for receive cck */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10) | + BIT(11), 3); + break; + case HT_CHANNEL_WIDTH_20_40: + rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); + rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); + /* Set Control channel to upper or lower. + * These settings are required only for 40MHz */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCKSIDEBAND, + (mac->cur_40_prime_sc >> 1)); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } + rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); + /* SET BIT10 BIT11 for receive cck */ + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10) | + BIT(11), 0); + rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), + (mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); + break; + + } + rtl92d_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); + rtlphy->set_bwmode_inprogress = false; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); +} + +static void _rtl92d_phy_stop_trx_before_changeband(struct ieee80211_hw *hw) +{ + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x00); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x0); +} + +static void rtl92d_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 value8; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("==>\n")); + rtlhal->bandset = band; + rtlhal->current_bandtype = band; + if (IS_92D_SINGLEPHY(rtlhal->version)) + rtlhal->bandset = BAND_ON_BOTH; + /* stop RX/Tx */ + _rtl92d_phy_stop_trx_before_changeband(hw); + /* reconfig BB/RF according to wireless mode */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* BB & RF Config */ + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ("====>2.4G\n")); + if (rtlhal->interfaceindex == 1) + _rtl92d_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + } else { + /* 5G band */ + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ("====>5G\n")); + if (rtlhal->interfaceindex == 1) + _rtl92d_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + } + rtl92d_update_bbrf_configuration(hw); + if (rtlhal->current_bandtype == BAND_ON_2_4G) + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + + /* 20M BW. */ + /* rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); */ + rtlhal->reloadtxpowerindex = true; + /* notice fw know band status 0x81[1]/0x53[1] = 0: 5G, 1: 2G */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + value8 = rtl_read_byte(rtlpriv, (rtlhal->interfaceindex == + 0 ? REG_MAC0 : REG_MAC1)); + value8 |= BIT(1); + rtl_write_byte(rtlpriv, (rtlhal->interfaceindex == + 0 ? REG_MAC0 : REG_MAC1), value8); + } else { + value8 = rtl_read_byte(rtlpriv, (rtlhal->interfaceindex == + 0 ? REG_MAC0 : REG_MAC1)); + value8 &= (~BIT(1)); + rtl_write_byte(rtlpriv, (rtlhal->interfaceindex == + 0 ? REG_MAC0 : REG_MAC1), value8); + } + mdelay(1); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("<==Switch Band OK.\n")); +} + +static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw, + u8 channel, u8 rfpath) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 imr_num = MAX_RF_IMR_INDEX; + u32 rfmask = BRFREGOFFSETMASK; + u8 group, i; + unsigned long flag = 0; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("====>path %d\n", rfpath)); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("====>5G\n")); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(25) | BIT(24), 0); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); + /* fc area 0xd2c */ + if (channel > 99) + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(13) | + BIT(14), 2); + else + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(13) | + BIT(14), 1); + /* leave 0 for channel1-14. */ + group = channel <= 64 ? 1 : 2; + imr_num = MAX_RF_IMR_INDEX_NORMAL; + for (i = 0; i < imr_num; i++) + rtl_set_rfreg(hw, (enum radio_path)rfpath, + rf_reg_for_5g_swchnl_normal[i], rfmask, + rf_imr_param_normal[0][group][i]); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 1); + } else { + /* G band. */ + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + ("Load RF IMR parameters for G band. IMR already " + "setting %d\n", + rtlpriv->rtlhal.load_imrandiqk_setting_for2g)); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("====>2.4G\n")); + if (!rtlpriv->rtlhal.load_imrandiqk_setting_for2g) { + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + ("Load RF IMR parameters " + "for G band. %d\n", rfpath)); + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(25) | BIT(24), 0); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, + 0x00f00000, 0xf); + imr_num = MAX_RF_IMR_INDEX_NORMAL; + for (i = 0; i < imr_num; i++) { + rtl_set_rfreg(hw, (enum radio_path)rfpath, + rf_reg_for_5g_swchnl_normal[i], + BRFREGOFFSETMASK, + rf_imr_param_normal[0][0][i]); + } + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, + 0x00f00000, 0); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN | BCCKEN, 3); + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + } + } + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("<====\n")); +} + +static void _rtl92d_phy_enable_rf_env(struct ieee80211_hw *hw, + u8 rfpath, u32 *pu4_regval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, ("====>\n")); + /*----Store original RFENV control type----*/ + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + *pu4_regval = rtl_get_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV); + break; + case RF90_PATH_B: + case RF90_PATH_D: + *pu4_regval = + rtl_get_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV << 16); + break; + } + /*----Set RF_ENV enable----*/ + rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1); + udelay(1); + /*----Set RF_ENV output high----*/ + rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); + udelay(1); + /* Set bit number of Address and Data for RF register */ + /* Set 1 to 4 bits for 8255 */ + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREADDRESSLENGTH, 0x0); + udelay(1); + /*Set 0 to 12 bits for 8255 */ + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0); + udelay(1); + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, ("<====\n")); +} + +static void _rtl92d_phy_restore_rf_env(struct ieee80211_hw *hw, u8 rfpath, + u32 *pu4_regval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, ("=====>\n")); + /*----Restore RFENV control type----*/ ; + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV, *pu4_regval); + break; + case RF90_PATH_B: + case RF90_PATH_D: + rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV << 16, + *pu4_regval); + break; + } + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, ("<=====\n")); +} + +static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 path = rtlhal->current_bandtype == + BAND_ON_5G ? RF90_PATH_A : RF90_PATH_B; + u8 index = 0, i = 0, rfpath = RF90_PATH_A; + bool need_pwr_down = false, internal_pa = false; + u32 u4regvalue, mask = 0x1C000, value = 0, u4tmp, u4tmp2; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("====>\n")); + /* config path A for 5G */ + if (rtlhal->current_bandtype == BAND_ON_5G) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("====>5G\n")); + u4tmp = curveindex_5g[channel - 1]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("ver 1 set RF-A, 5G, " + "0x28 = 0x%x !!\n", u4tmp)); + for (i = 0; i < RF_CHNL_NUM_5G; i++) { + if (channel == rf_chnl_5g[i] && channel <= 140) + index = 0; + } + for (i = 0; i < RF_CHNL_NUM_5G_40M; i++) { + if (channel == rf_chnl_5g_40m[i] && channel <= 140) + index = 1; + } + if (channel == 149 || channel == 155 || channel == 161) + index = 2; + else if (channel == 151 || channel == 153 || channel == 163 + || channel == 165) + index = 3; + else if (channel == 157 || channel == 159) + index = 4; + + if (rtlhal->macphymode == DUALMAC_DUALPHY + && rtlhal->interfaceindex == 1) { + need_pwr_down = rtl92d_phy_enable_anotherphy(hw, false); + rtlhal->during_mac1init_radioa = true; + /* asume no this case */ + if (need_pwr_down) + _rtl92d_phy_enable_rf_env(hw, path, + &u4regvalue); + } + for (i = 0; i < RF_REG_NUM_FOR_C_CUT_5G; i++) { + if (i == 0 && (rtlhal->macphymode == DUALMAC_DUALPHY)) { + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_5g[i], + BRFREGOFFSETMASK, 0xE439D); + } else if (rf_reg_for_c_cut_5g[i] == RF_SYN_G4) { + u4tmp2 = (rf_reg_pram_c_5g[index][i] & + 0x7FF) | (u4tmp << 11); + if (channel == 36) + u4tmp2 &= ~(BIT(7) | BIT(6)); + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_5g[i], + BRFREGOFFSETMASK, u4tmp2); + } else { + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_5g[i], + BRFREGOFFSETMASK, + rf_reg_pram_c_5g[index][i]); + } + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + ("offset 0x%x value 0x%x " + "path %d index %d readback 0x%x\n", + rf_reg_for_c_cut_5g[i], + rf_reg_pram_c_5g[index][i], path, + index, rtl_get_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_5g[i], BRFREGOFFSETMASK))); + } + if (need_pwr_down) + _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue); + if (rtlhal->during_mac1init_radioa) + rtl92d_phy_powerdown_anotherphy(hw, false); + if (channel < 149) + value = 0x07; + else if (channel >= 149) + value = 0x02; + if (channel >= 36 && channel <= 64) + index = 0; + else if (channel >= 100 && channel <= 140) + index = 1; + else + index = 2; + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (rtlhal->macphymode == DUALMAC_DUALPHY && + rtlhal->interfaceindex == 1) /* MAC 1 5G */ + internal_pa = rtlpriv->efuse.internal_pa_5g[1]; + else + internal_pa = + rtlpriv->efuse.internal_pa_5g[rfpath]; + if (internal_pa) { + for (i = 0; + i < RF_REG_NUM_FOR_C_CUT_5G_INTERNALPA; + i++) { + rtl_set_rfreg(hw, rfpath, + rf_for_c_cut_5g_internal_pa[i], + BRFREGOFFSETMASK, + rf_pram_c_5g_int_pa[index][i]); + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, + ("offset 0x%x value 0x%x " + "path %d index %d\n", + rf_for_c_cut_5g_internal_pa[i], + rf_pram_c_5g_int_pa[index][i], + rfpath, index)); + } + } else { + rtl_set_rfreg(hw, (enum radio_path)rfpath, 0x0B, + mask, value); + } + } + } else if (rtlhal->current_bandtype == BAND_ON_2_4G) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("====>2.4G\n")); + u4tmp = curveindex_2g[channel - 1]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("ver 3 set RF-B, 2G, " + "0x28 = 0x%x !!\n", u4tmp)); + if (channel == 1 || channel == 2 || channel == 4 || channel == 9 + || channel == 10 || channel == 11 || channel == 12) + index = 0; + else if (channel == 3 || channel == 13 || channel == 14) + index = 1; + else if (channel >= 5 && channel <= 8) + index = 2; + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + path = RF90_PATH_A; + if (rtlhal->interfaceindex == 0) { + need_pwr_down = + rtl92d_phy_enable_anotherphy(hw, true); + rtlhal->during_mac0init_radiob = true; + + if (need_pwr_down) + _rtl92d_phy_enable_rf_env(hw, path, + &u4regvalue); + } + } + for (i = 0; i < RF_REG_NUM_FOR_C_CUT_2G; i++) { + if (rf_reg_for_c_cut_2g[i] == RF_SYN_G7) + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_2g[i], + BRFREGOFFSETMASK, + (rf_reg_param_for_c_cut_2g[index][i] | + BIT(17))); + else + rtl_set_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_2g[i], + BRFREGOFFSETMASK, + rf_reg_param_for_c_cut_2g + [index][i]); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + ("offset 0x%x value 0x%x mak 0x%x path %d " + "index %d readback 0x%x\n", + rf_reg_for_c_cut_2g[i], + rf_reg_param_for_c_cut_2g[index][i], + rf_reg_mask_for_c_cut_2g[i], path, index, + rtl_get_rfreg(hw, (enum radio_path)path, + rf_reg_for_c_cut_2g[i], + BRFREGOFFSETMASK))); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("cosa ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", + rf_syn_g4_for_c_cut_2g | (u4tmp << 11))); + + rtl_set_rfreg(hw, (enum radio_path)path, RF_SYN_G4, + BRFREGOFFSETMASK, + rf_syn_g4_for_c_cut_2g | (u4tmp << 11)); + if (need_pwr_down) + _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue); + if (rtlhal->during_mac0init_radiob) + rtl92d_phy_powerdown_anotherphy(hw, true); + } + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("<====\n")); +} + +u8 rtl92d_get_rightchnlplace_for_iqk(u8 chnl) +{ + u8 channel_all[59] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, + 114, 116, 118, 120, 122, 124, 126, 128, 130, + 132, 134, 136, 138, 140, 149, 151, 153, 155, + 157, 159, 161, 163, 165 + }; + u8 place = chnl; + + if (chnl > 14) { + for (place = 14; place < sizeof(channel_all); place++) { + if (channel_all[place] == chnl) + return place - 13; + } + } + + return 0; +} + +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 /* ms */ +#define MAX_TOLERANCE_92D 3 + +/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +static u8 _rtl92d_phy_patha_iqk(struct ieee80211_hw *hw, bool configpathb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 regeac, rege94, rege9c, regea4; + u8 result = 0; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path A IQK!\n")); + /* path-A IQK setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path-A IQK setting!\n")); + if (rtlhal->interfaceindex == 0) { + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c1f); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c1f); + } else { + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c22); + } + rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x28160206); + /* path-B IQK setting */ + if (configpathb) { + rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x28160206); + } + /* LO calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("LO calibration setting!\n")); + rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + /* One shot, path A LOK & IQK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("One shot, path A LOK & IQK!\n")); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + /* delay x ms */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Delay %d ms for One shot, path A LOK & IQK.\n", + IQK_DELAY_TIME)); + mdelay(IQK_DELAY_TIME); + /* Check failed */ + regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac)); + rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xe94 = 0x%x\n", rege94)); + rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xe9c = 0x%x\n", rege9c)); + regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xea4 = 0x%x\n", regea4)); + if (!(regeac & BIT(28)) && (((rege94 & 0x03FF0000) >> 16) != 0x142) && + (((rege9c & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else /* if Tx not OK, ignore Rx */ + return result; + /* if Tx is OK, check whether Rx is OK */ + if (!(regeac & BIT(27)) && (((regea4 & 0x03FF0000) >> 16) != 0x132) && + (((regeac & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + else + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path A Rx IQK fail!!\n")); + return result; +} + +/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw, + bool configpathb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 regeac, rege94, rege9c, regea4; + u8 result = 0; + u8 i; + u8 retrycount = 2; + u32 TxOKBit = BIT(28), RxOKBit = BIT(27); + + if (rtlhal->interfaceindex == 1) { /* PHY1 */ + TxOKBit = BIT(31); + RxOKBit = BIT(30); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path A IQK!\n")); + /* path-A IQK setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path-A IQK setting!\n")); + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140307); + rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68160960); + /* path-B IQK setting */ + if (configpathb) { + rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82110000); + rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68110000); + } + /* LO calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("LO calibration setting!\n")); + rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + /* path-A PA on */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x07000f60); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, 0x66e60e30); + for (i = 0; i < retrycount; i++) { + /* One shot, path A LOK & IQK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("One shot, path A LOK & IQK!\n")); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + /* delay x ms */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Delay %d ms for One shot, path A LOK & IQK.\n", + IQK_DELAY_TIME)); + mdelay(IQK_DELAY_TIME * 10); + /* Check failed */ + regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac)); + rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xe94 = 0x%x\n", rege94)); + rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xe9c = 0x%x\n", rege9c)); + regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xea4 = 0x%x\n", regea4)); + if (!(regeac & TxOKBit) && + (((rege94 & 0x03FF0000) >> 16) != 0x142)) { + result |= 0x01; + } else { /* if Tx not OK, ignore Rx */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path A Tx IQK fail!!\n")); + continue; + } + + /* if Tx is OK, check whether Rx is OK */ + if (!(regeac & RxOKBit) && + (((regea4 & 0x03FF0000) >> 16) != 0x132)) { + result |= 0x02; + break; + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path A Rx IQK fail!!\n")); + } + } + /* path A PA off */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, + rtlphy->iqk_bb_backup[0]); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, + rtlphy->iqk_bb_backup[1]); + return result; +} + +/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +static u8 _rtl92d_phy_pathb_iqk(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 regeac, regeb4, regebc, regec4, regecc; + u8 result = 0; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path B IQK!\n")); + /* One shot, path B LOK & IQK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("One shot, path A LOK & IQK!\n")); + rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000002); + rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000000); + /* delay x ms */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Delay %d ms for One shot, path B LOK & IQK.\n", + IQK_DELAY_TIME)); + mdelay(IQK_DELAY_TIME); + /* Check failed */ + regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac)); + regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeb4 = 0x%x\n", regeb4)); + regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xebc = 0x%x\n", regebc)); + regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xec4 = 0x%x\n", regec4)); + regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xecc = 0x%x\n", regecc)); + if (!(regeac & BIT(31)) && (((regeb4 & 0x03FF0000) >> 16) != 0x142) && + (((regebc & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else + return result; + if (!(regeac & BIT(30)) && (((regec4 & 0x03FF0000) >> 16) != 0x132) && + (((regecc & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + else + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path B Rx IQK fail!!\n")); + return result; +} + +/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 regeac, regeb4, regebc, regec4, regecc; + u8 result = 0; + u8 i; + u8 retrycount = 2; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path B IQK!\n")); + /* path-A IQK setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path-A IQK setting!\n")); + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82110000); + rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68110000); + + /* path-B IQK setting */ + rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140307); + rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68160960); + + /* LO calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("LO calibration setting!\n")); + rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + + /* path-B PA on */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x0f600700); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, 0x061f0d30); + + for (i = 0; i < retrycount; i++) { + /* One shot, path B LOK & IQK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("One shot, path A LOK & IQK!\n")); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xfa000000); + rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + + /* delay x ms */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Delay %d ms for One shot, path B LOK & IQK.\n", 10)); + mdelay(IQK_DELAY_TIME * 10); + + /* Check failed */ + regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac)); + regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeb4 = 0x%x\n", regeb4)); + regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xebc = 0x%x\n", regebc)); + regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xec4 = 0x%x\n", regec4)); + regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xecc = 0x%x\n", regecc)); + if (!(regeac & BIT(31)) && + (((regeb4 & 0x03FF0000) >> 16) != 0x142)) + result |= 0x01; + else + continue; + if (!(regeac & BIT(30)) && + (((regec4 & 0x03FF0000) >> 16) != 0x132)) { + result |= 0x02; + break; + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path B Rx IQK fail!!\n")); + } + } + + /* path B PA off */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, + rtlphy->iqk_bb_backup[0]); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, + rtlphy->iqk_bb_backup[2]); + return result; +} + +static void _rtl92d_phy_save_adda_registers(struct ieee80211_hw *hw, + u32 *adda_reg, u32 *adda_backup, + u32 regnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Save ADDA parameters.\n")); + for (i = 0; i < regnum; i++) + adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], BMASKDWORD); +} + +static void _rtl92d_phy_save_mac_registers(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Save MAC parameters.\n")); + for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) + macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]); + macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]); +} + +static void _rtl92d_phy_reload_adda_registers(struct ieee80211_hw *hw, + u32 *adda_reg, u32 *adda_backup, + u32 regnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Reload ADDA power saving parameters !\n")); + for (i = 0; i < regnum; i++) + rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, adda_backup[i]); +} + +static void _rtl92d_phy_reload_mac_registers(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Reload MAC parameters !\n")); + for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) + rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]); + rtl_write_byte(rtlpriv, macreg[i], macbackup[i]); +} + +static void _rtl92d_phy_path_adda_on(struct ieee80211_hw *hw, + u32 *adda_reg, bool patha_on, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 pathon; + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("ADDA ON.\n")); + pathon = patha_on ? 0x04db25a4 : 0x0b1b25a4; + if (patha_on) + pathon = rtlpriv->rtlhal.interfaceindex == 0 ? + 0x04db25a4 : 0x0b1b25a4; + for (i = 0; i < IQK_ADDA_REG_NUM; i++) + rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, pathon); +} + +static void _rtl92d_phy_mac_setting_calibration(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("MAC settings for Calibration.\n")); + rtl_write_byte(rtlpriv, macreg[0], 0x3F); + + for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) + rtl_write_byte(rtlpriv, macreg[i], (u8)(macbackup[i] & + (~BIT(3)))); + rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5)))); +} + +static void _rtl92d_phy_patha_standby(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path-A standby mode!\n")); + + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x0); + rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, 0x00010000); + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); +} + +static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 mode; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("BB Switch to %s mode!\n", (pi_mode ? "PI" : "SI"))); + mode = pi_mode ? 0x01000100 : 0x01000000; + rtl_set_bbreg(hw, 0x820, BMASKDWORD, mode); + rtl_set_bbreg(hw, 0x828, BMASKDWORD, mode); +} + +static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], + u8 t, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 i; + u8 patha_ok, pathb_ok; + static u32 adda_reg[IQK_ADDA_REG_NUM] = { + RFPGA0_XCD_SWITCHCONTROL, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec + }; + static u32 iqk_mac_reg[IQK_MAC_REG_NUM] = { + 0x522, 0x550, 0x551, 0x040 + }; + static u32 iqk_bb_reg[IQK_BB_REG_NUM] = { + RFPGA0_XAB_RFINTERFACESW, RFPGA0_XA_RFINTERFACEOE, + RFPGA0_XB_RFINTERFACEOE, ROFDM0_TRMUXPAR, + RFPGA0_XCD_RFINTERFACESW, ROFDM0_TRXPATHENABLE, + RFPGA0_RFMOD, RFPGA0_ANALOGPARAMETER4, + ROFDM0_XAAGCCORE1, ROFDM0_XBAGCCORE1 + }; + const u32 retrycount = 2; + u32 bbvalue; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("IQK for 2.4G :Start!!!\n")); + if (t == 0) { + bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("==>0x%08x\n", bbvalue)); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("IQ Calibration for %s\n", + (is2t ? "2T2R" : "1T1R"))); + + /* Save ADDA parameters, turn Path A ADDA on */ + _rtl92d_phy_save_adda_registers(hw, adda_reg, + rtlphy->adda_backup, IQK_ADDA_REG_NUM); + _rtl92d_phy_save_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + _rtl92d_phy_save_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, IQK_BB_REG_NUM); + } + _rtl92d_phy_path_adda_on(hw, adda_reg, true, is2t); + if (t == 0) + rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER1, BIT(8)); + + /* Switch BB to PI mode to do IQ Calibration. */ + if (!rtlphy->rfpi_enable) + _rtl92d_phy_pimode_switch(hw, true); + + rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22204000); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f); + if (is2t) { + rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, + 0x00010000); + rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, BMASKDWORD, + 0x00010000); + } + /* MAC settings */ + _rtl92d_phy_mac_setting_calibration(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + /* Page B init */ + rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000); + if (is2t) + rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000); + /* IQ calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("IQK setting!\n")); + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x01007c00); + rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800); + for (i = 0; i < retrycount; i++) { + patha_ok = _rtl92d_phy_patha_iqk(hw, is2t); + if (patha_ok == 0x03) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path A IQK Success!!\n")); + result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) & + 0x3FF0000) >> 16; + break; + } else if (i == (retrycount - 1) && patha_ok == 0x01) { + /* Tx IQK OK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path A IQK Only Tx Success!!\n")); + + result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + 0x3FF0000) >> 16; + } + } + if (0x00 == patha_ok) + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path A IQK failed!!\n")); + if (is2t) { + _rtl92d_phy_patha_standby(hw); + /* Turn Path B ADDA on */ + _rtl92d_phy_path_adda_on(hw, adda_reg, false, is2t); + for (i = 0; i < retrycount; i++) { + pathb_ok = _rtl92d_phy_pathb_iqk(hw); + if (pathb_ok == 0x03) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path B IQK Success!!\n")); + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, + BMASKDWORD) & 0x3FF0000) >> 16; + result[t][5] = (rtl_get_bbreg(hw, 0xebc, + BMASKDWORD) & 0x3FF0000) >> 16; + result[t][6] = (rtl_get_bbreg(hw, 0xec4, + BMASKDWORD) & 0x3FF0000) >> 16; + result[t][7] = (rtl_get_bbreg(hw, 0xecc, + BMASKDWORD) & 0x3FF0000) >> 16; + break; + } else if (i == (retrycount - 1) && pathb_ok == 0x01) { + /* Tx IQK OK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path B Only Tx IQK Success!!\n")); + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, + BMASKDWORD) & 0x3FF0000) >> 16; + result[t][5] = (rtl_get_bbreg(hw, 0xebc, + BMASKDWORD) & 0x3FF0000) >> 16; + } + } + if (0x00 == pathb_ok) + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path B IQK failed!!\n")); + } + + /* Back to BB mode, load original value */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("IQK:Back to BB mode, load original value!\n")); + + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0); + if (t != 0) { + /* Switch back BB to SI mode after finish IQ Calibration. */ + if (!rtlphy->rfpi_enable) + _rtl92d_phy_pimode_switch(hw, false); + /* Reload ADDA power saving parameters */ + _rtl92d_phy_reload_adda_registers(hw, adda_reg, + rtlphy->adda_backup, IQK_ADDA_REG_NUM); + /* Reload MAC parameters */ + _rtl92d_phy_reload_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + if (is2t) + _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM); + else + _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM - 1); + /* load 0xe30 IQC default value */ + rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x01008c00); + rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x01008c00); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("<==\n")); +} + +static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, + long result[][8], u8 t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 patha_ok, pathb_ok; + static u32 adda_reg[IQK_ADDA_REG_NUM] = { + RFPGA0_XCD_SWITCHCONTROL, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec + }; + static u32 iqk_mac_reg[IQK_MAC_REG_NUM] = { + 0x522, 0x550, 0x551, 0x040 + }; + static u32 iqk_bb_reg[IQK_BB_REG_NUM] = { + RFPGA0_XAB_RFINTERFACESW, RFPGA0_XA_RFINTERFACEOE, + RFPGA0_XB_RFINTERFACEOE, ROFDM0_TRMUXPAR, + RFPGA0_XCD_RFINTERFACESW, ROFDM0_TRXPATHENABLE, + RFPGA0_RFMOD, RFPGA0_ANALOGPARAMETER4, + ROFDM0_XAAGCCORE1, ROFDM0_XBAGCCORE1 + }; + u32 bbvalue; + bool is2t = IS_92D_SINGLEPHY(rtlhal->version); + + /* Note: IQ calibration must be performed after loading + * PHY_REG.txt , and radio_a, radio_b.txt */ + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("IQK for 5G NORMAL:Start!!!\n")); + mdelay(IQK_DELAY_TIME * 20); + if (t == 0) { + bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("==>0x%08x\n", bbvalue)); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("IQ Calibration for %s\n", + (is2t ? "2T2R" : "1T1R"))); + /* Save ADDA parameters, turn Path A ADDA on */ + _rtl92d_phy_save_adda_registers(hw, adda_reg, + rtlphy->adda_backup, + IQK_ADDA_REG_NUM); + _rtl92d_phy_save_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + if (is2t) + _rtl92d_phy_save_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM); + else + _rtl92d_phy_save_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM - 1); + } + _rtl92d_phy_path_adda_on(hw, adda_reg, true, is2t); + /* MAC settings */ + _rtl92d_phy_mac_setting_calibration(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + if (t == 0) + rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER1, BIT(8)); + /* Switch BB to PI mode to do IQ Calibration. */ + if (!rtlphy->rfpi_enable) + _rtl92d_phy_pimode_switch(hw, true); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22208000); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f); + + /* Page B init */ + rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000); + if (is2t) + rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000); + /* IQ calibration setting */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("IQK setting!\n")); + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x10007c00); + rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800); + patha_ok = _rtl92d_phy_patha_iqk_5g_normal(hw, is2t); + if (patha_ok == 0x03) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path A IQK Success!!\n")); + result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) & + 0x3FF0000) >> 16; + } else if (patha_ok == 0x01) { /* Tx IQK OK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path A IQK Only Tx Success!!\n")); + + result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + 0x3FF0000) >> 16; + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path A IQK Fail!!\n")); + } + if (is2t) { + /* _rtl92d_phy_patha_standby(hw); */ + /* Turn Path B ADDA on */ + _rtl92d_phy_path_adda_on(hw, adda_reg, false, is2t); + pathb_ok = _rtl92d_phy_pathb_iqk_5g_normal(hw); + if (pathb_ok == 0x03) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path B IQK Success!!\n")); + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][6] = (rtl_get_bbreg(hw, 0xec4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][7] = (rtl_get_bbreg(hw, 0xecc, BMASKDWORD) & + 0x3FF0000) >> 16; + } else if (pathb_ok == 0x01) { /* Tx IQK OK */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path B Only Tx IQK Success!!\n")); + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) & + 0x3FF0000) >> 16; + result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) & + 0x3FF0000) >> 16; + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path B IQK failed!!\n")); + } + } + + /* Back to BB mode, load original value */ + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("IQK:Back to BB mode, load original value!\n")); + rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0); + if (t != 0) { + if (is2t) + _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM); + else + _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM - 1); + /* Reload MAC parameters */ + _rtl92d_phy_reload_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + /* Switch back BB to SI mode after finish IQ Calibration. */ + if (!rtlphy->rfpi_enable) + _rtl92d_phy_pimode_switch(hw, false); + /* Reload ADDA power saving parameters */ + _rtl92d_phy_reload_adda_registers(hw, adda_reg, + rtlphy->adda_backup, + IQK_ADDA_REG_NUM); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("<==\n")); +} + +static bool _rtl92d_phy_simularity_compare(struct ieee80211_hw *hw, + long result[][8], u8 c1, u8 c2) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 i, j, diff, sim_bitmap, bound; + u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */ + bool bresult = true; + bool is2t = IS_92D_SINGLEPHY(rtlhal->version); + + if (is2t) + bound = 8; + else + bound = 4; + sim_bitmap = 0; + for (i = 0; i < bound; i++) { + diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - + result[c2][i]) : (result[c2][i] - result[c1][i]); + if (diff > MAX_TOLERANCE_92D) { + if ((i == 2 || i == 6) && !sim_bitmap) { + if (result[c1][i] + result[c1][i + 1] == 0) + final_candidate[(i / 4)] = c2; + else if (result[c2][i] + result[c2][i + 1] == 0) + final_candidate[(i / 4)] = c1; + else + sim_bitmap = sim_bitmap | (1 << i); + } else { + sim_bitmap = sim_bitmap | (1 << i); + } + } + } + if (sim_bitmap == 0) { + for (i = 0; i < (bound / 4); i++) { + if (final_candidate[i] != 0xFF) { + for (j = i * 4; j < (i + 1) * 4 - 2; j++) + result[3][j] = + result[final_candidate[i]][j]; + bresult = false; + } + } + return bresult; + } + if (!(sim_bitmap & 0x0F)) { /* path A OK */ + for (i = 0; i < 4; i++) + result[3][i] = result[c1][i]; + } else if (!(sim_bitmap & 0x03)) { /* path A, Tx OK */ + for (i = 0; i < 2; i++) + result[3][i] = result[c1][i]; + } + if (!(sim_bitmap & 0xF0) && is2t) { /* path B OK */ + for (i = 4; i < 8; i++) + result[3][i] = result[c1][i]; + } else if (!(sim_bitmap & 0x30)) { /* path B, Tx OK */ + for (i = 4; i < 6; i++) + result[3][i] = result[c1][i]; + } + return false; +} + +static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw, + bool iqk_ok, long result[][8], + u8 final_candidate, bool txonly) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 oldval_0, val_x, tx0_a, reg; + long val_y, tx0_c; + bool is2t = IS_92D_SINGLEPHY(rtlhal->version) || + rtlhal->macphymode == DUALMAC_DUALPHY; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("Path A IQ Calibration %s !\n", + (iqk_ok) ? "Success" : "Failed")); + if (final_candidate == 0xFF) { + return; + } else if (iqk_ok) { + oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD) >> 22) & 0x3FF; /* OFDM0_D */ + val_x = result[final_candidate][0]; + if ((val_x & 0x00000200) != 0) + val_x = val_x | 0xFFFFFC00; + tx0_a = (val_x * oldval_0) >> 8; + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("X = 0x%x, tx0_a = 0x%x," + " oldval_0 0x%x\n", val_x, tx0_a, oldval_0)); + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, 0x3FF, tx0_a); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), + ((val_x * oldval_0 >> 7) & 0x1)); + val_y = result[final_candidate][1]; + if ((val_y & 0x00000200) != 0) + val_y = val_y | 0xFFFFFC00; + /* path B IQK result + 3 */ + if (rtlhal->interfaceindex == 1 && + rtlhal->current_bandtype == BAND_ON_5G) + val_y += 3; + tx0_c = (val_y * oldval_0) >> 8; + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Y = 0x%lx, tx0_c = 0x%lx\n", + val_y, tx0_c)); + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, 0xF0000000, + ((tx0_c & 0x3C0) >> 6)); + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, 0x003F0000, + (tx0_c & 0x3F)); + if (is2t) + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(26), + ((val_y * oldval_0 >> 7) & 0x1)); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xC80 = 0x%x\n", + rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, + BMASKDWORD))); + if (txonly) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("only Tx OK\n")); + return; + } + reg = result[final_candidate][2]; + rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg); + reg = result[final_candidate][3] & 0x3F; + rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg); + reg = (result[final_candidate][3] >> 6) & 0xF; + rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg); + } +} + +static void _rtl92d_phy_pathb_fill_iqk_matrix(struct ieee80211_hw *hw, + bool iqk_ok, long result[][8], u8 final_candidate, bool txonly) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 oldval_1, val_x, tx1_a, reg; + long val_y, tx1_c; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Path B IQ Calibration %s !\n", + (iqk_ok) ? "Success" : "Failed")); + if (final_candidate == 0xFF) { + return; + } else if (iqk_ok) { + oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, + BMASKDWORD) >> 22) & 0x3FF; + val_x = result[final_candidate][4]; + if ((val_x & 0x00000200) != 0) + val_x = val_x | 0xFFFFFC00; + tx1_a = (val_x * oldval_1) >> 8; + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("X = 0x%x, tx1_a = 0x%x\n", + val_x, tx1_a)); + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, 0x3FF, tx1_a); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(28), + ((val_x * oldval_1 >> 7) & 0x1)); + val_y = result[final_candidate][5]; + if ((val_y & 0x00000200) != 0) + val_y = val_y | 0xFFFFFC00; + if (rtlhal->current_bandtype == BAND_ON_5G) + val_y += 3; + tx1_c = (val_y * oldval_1) >> 8; + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("Y = 0x%lx, tx1_c = 0x%lx\n", + val_y, tx1_c)); + rtl_set_bbreg(hw, ROFDM0_XDTxAFE, 0xF0000000, + ((tx1_c & 0x3C0) >> 6)); + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, 0x003F0000, + (tx1_c & 0x3F)); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(30), + ((val_y * oldval_1 >> 7) & 0x1)); + if (txonly) + return; + reg = result[final_candidate][6]; + rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0x3FF, reg); + reg = result[final_candidate][7] & 0x3F; + rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0xFC00, reg); + reg = (result[final_candidate][7] >> 6) & 0xF; + rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, 0x0000F000, reg); + } +} + +void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + long result[4][8]; + u8 i, final_candidate, indexforchannel; + bool patha_ok, pathb_ok; + long rege94, rege9c, regea4, regeac, regeb4; + long regebc, regec4, regecc, regtmp = 0; + bool is12simular, is13simular, is23simular; + unsigned long flag = 0; + + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("IQK:Start!!!channel %d\n", rtlphy->current_channel)); + for (i = 0; i < 8; i++) { + result[0][i] = 0; + result[1][i] = 0; + result[2][i] = 0; + result[3][i] = 0; + } + final_candidate = 0xff; + patha_ok = false; + pathb_ok = false; + is12simular = false; + is23simular = false; + is13simular = false; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("IQK !!!currentband %d\n", rtlhal->current_bandtype)); + rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); + for (i = 0; i < 3; i++) { + if (rtlhal->current_bandtype == BAND_ON_5G) { + _rtl92d_phy_iq_calibrate_5g_normal(hw, result, i); + } else if (rtlhal->current_bandtype == BAND_ON_2_4G) { + if (IS_92D_SINGLEPHY(rtlhal->version)) + _rtl92d_phy_iq_calibrate(hw, result, i, true); + else + _rtl92d_phy_iq_calibrate(hw, result, i, false); + } + if (i == 1) { + is12simular = _rtl92d_phy_simularity_compare(hw, result, + 0, 1); + if (is12simular) { + final_candidate = 0; + break; + } + } + if (i == 2) { + is13simular = _rtl92d_phy_simularity_compare(hw, result, + 0, 2); + if (is13simular) { + final_candidate = 0; + break; + } + is23simular = _rtl92d_phy_simularity_compare(hw, result, + 1, 2); + if (is23simular) { + final_candidate = 1; + } else { + for (i = 0; i < 8; i++) + regtmp += result[3][i]; + + if (regtmp != 0) + final_candidate = 3; + else + final_candidate = 0xFF; + } + } + } + rtl92d_release_cckandrw_pagea_ctl(hw, &flag); + for (i = 0; i < 4; i++) { + rege94 = result[i][0]; + rege9c = result[i][1]; + regea4 = result[i][2]; + regeac = result[i][3]; + regeb4 = result[i][4]; + regebc = result[i][5]; + regec4 = result[i][6]; + regecc = result[i][7]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("IQK: rege94=%lx rege9c=%lx regea4=%lx regeac=%lx " + "regeb4=%lx regebc=%lx regec4=%lx regecc=%lx\n ", + rege94, rege9c, regea4, regeac, regeb4, regebc, regec4, + regecc)); + } + if (final_candidate != 0xff) { + rtlphy->reg_e94 = rege94 = result[final_candidate][0]; + rtlphy->reg_e9c = rege9c = result[final_candidate][1]; + regea4 = result[final_candidate][2]; + regeac = result[final_candidate][3]; + rtlphy->reg_eb4 = regeb4 = result[final_candidate][4]; + rtlphy->reg_ebc = regebc = result[final_candidate][5]; + regec4 = result[final_candidate][6]; + regecc = result[final_candidate][7]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("IQK: final_candidate is %x\n", final_candidate)); + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("IQK: rege94=%lx rege9c=%lx regea4=%lx regeac=%lx " + "regeb4=%lx regebc=%lx regec4=%lx regecc=%lx\n ", + rege94, rege9c, regea4, regeac, regeb4, regebc, regec4, + regecc)); + patha_ok = pathb_ok = true; + } else { + rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; /* X default value */ + rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0; /* Y default value */ + } + if ((rege94 != 0) /*&&(regea4 != 0) */) + _rtl92d_phy_patha_fill_iqk_matrix(hw, patha_ok, result, + final_candidate, (regea4 == 0)); + if (IS_92D_SINGLEPHY(rtlhal->version)) { + if ((regeb4 != 0) /*&&(regec4 != 0) */) + _rtl92d_phy_pathb_fill_iqk_matrix(hw, pathb_ok, result, + final_candidate, (regec4 == 0)); + } + if (final_candidate != 0xFF) { + indexforchannel = rtl92d_get_rightchnlplace_for_iqk( + rtlphy->current_channel); + + for (i = 0; i < IQK_MATRIX_REG_NUM; i++) + rtlphy->iqk_matrix_regsetting[indexforchannel]. + value[0][i] = result[final_candidate][i]; + rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done = + true; + + RT_TRACE(rtlpriv, COMP_SCAN | COMP_MLME, DBG_LOUD, + ("\nIQK OK indexforchannel %d.\n", indexforchannel)); + } +} + +void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 indexforchannel; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("channel %d\n", channel)); + /*------Do IQK for normal chip and test chip 5G band------- */ + indexforchannel = rtl92d_get_rightchnlplace_for_iqk(channel); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("indexforchannel %d done %d\n", indexforchannel, + rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done)); + if (0 && !rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done && + rtlphy->need_iqk) { + /* Re Do IQK. */ + RT_TRACE(rtlpriv, COMP_SCAN | COMP_INIT, DBG_LOUD, + ("Do IQK Matrix reg for channel:%d....\n", channel)); + rtl92d_phy_iq_calibrate(hw); + } else { + /* Just load the value. */ + /* 2G band just load once. */ + if (((!rtlhal->load_imrandiqk_setting_for2g) && + indexforchannel == 0) || indexforchannel > 0) { + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + ("Just Read IQK Matrix reg for channel:%d" + "....\n", channel)); + if ((rtlphy->iqk_matrix_regsetting[indexforchannel]. + value[0] != NULL) + /*&&(regea4 != 0) */) + _rtl92d_phy_patha_fill_iqk_matrix(hw, true, + rtlphy->iqk_matrix_regsetting[ + indexforchannel].value, 0, + (rtlphy->iqk_matrix_regsetting[ + indexforchannel].value[0][2] == 0)); + if (IS_92D_SINGLEPHY(rtlhal->version)) { + if ((rtlphy->iqk_matrix_regsetting[ + indexforchannel].value[0][4] != 0) + /*&&(regec4 != 0) */) + _rtl92d_phy_pathb_fill_iqk_matrix(hw, + true, + rtlphy->iqk_matrix_regsetting[ + indexforchannel].value, 0, + (rtlphy->iqk_matrix_regsetting[ + indexforchannel].value[0][6] + == 0)); + } + } + } + rtlphy->need_iqk = false; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("<====\n")); +} + +static u32 _rtl92d_phy_get_abs(u32 val1, u32 val2) +{ + u32 ret; + + if (val1 >= val2) + ret = val1 - val2; + else + ret = val2 - val1; + return ret; +} + +static bool _rtl92d_is_legal_5g_channel(struct ieee80211_hw *hw, u8 channel) +{ + + int i; + u8 channel_5g[45] = { + 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, + 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 136, 138, 140, 149, 151, 153, 155, 157, 159, + 161, 163, 165 + }; + + for (i = 0; i < sizeof(channel_5g); i++) + if (channel == channel_5g[i]) + return true; + return false; +} + +static void _rtl92d_phy_calc_curvindex(struct ieee80211_hw *hw, + u32 *targetchnl, u32 * curvecount_val, + bool is5g, u32 *curveindex) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 smallest_abs_val = 0xffffffff, u4tmp; + u8 i, j; + u8 chnl_num = is5g ? TARGET_CHNL_NUM_5G : TARGET_CHNL_NUM_2G; + + for (i = 0; i < chnl_num; i++) { + if (is5g && !_rtl92d_is_legal_5g_channel(hw, i + 1)) + continue; + curveindex[i] = 0; + for (j = 0; j < (CV_CURVE_CNT * 2); j++) { + u4tmp = _rtl92d_phy_get_abs(targetchnl[i], + curvecount_val[j]); + + if (u4tmp < smallest_abs_val) { + curveindex[i] = j; + smallest_abs_val = u4tmp; + } + } + smallest_abs_val = 0xffffffff; + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("curveindex[%d] = %x\n", i, + curveindex[i])); + } +} + +static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw, + u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 erfpath = rtlpriv->rtlhal.current_bandtype == + BAND_ON_5G ? RF90_PATH_A : + IS_92D_SINGLEPHY(rtlpriv->rtlhal.version) ? + RF90_PATH_B : RF90_PATH_A; + u32 u4tmp = 0, u4regvalue = 0; + bool bneed_powerdown_radio = false; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("path %d\n", erfpath)); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("band type = %d\n", + rtlpriv->rtlhal.current_bandtype)); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("channel = %d\n", channel)); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) {/* Path-A for 5G */ + u4tmp = curveindex_5g[channel-1]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("ver 1 set RF-A, 5G, 0x28 = 0x%ulx !!\n", u4tmp)); + if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY && + rtlpriv->rtlhal.interfaceindex == 1) { + bneed_powerdown_radio = + rtl92d_phy_enable_anotherphy(hw, false); + rtlpriv->rtlhal.during_mac1init_radioa = true; + /* asume no this case */ + if (bneed_powerdown_radio) + _rtl92d_phy_enable_rf_env(hw, erfpath, + &u4regvalue); + } + rtl_set_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800, u4tmp); + if (bneed_powerdown_radio) + _rtl92d_phy_restore_rf_env(hw, erfpath, &u4regvalue); + if (rtlpriv->rtlhal.during_mac1init_radioa) + rtl92d_phy_powerdown_anotherphy(hw, false); + } else if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) { + u4tmp = curveindex_2g[channel-1]; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n", u4tmp)); + if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY && + rtlpriv->rtlhal.interfaceindex == 0) { + bneed_powerdown_radio = + rtl92d_phy_enable_anotherphy(hw, true); + rtlpriv->rtlhal.during_mac0init_radiob = true; + if (bneed_powerdown_radio) + _rtl92d_phy_enable_rf_env(hw, erfpath, + &u4regvalue); + } + rtl_set_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800, u4tmp); + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n", + rtl_get_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800))); + if (bneed_powerdown_radio) + _rtl92d_phy_restore_rf_env(hw, erfpath, &u4regvalue); + if (rtlpriv->rtlhal.during_mac0init_radiob) + rtl92d_phy_powerdown_anotherphy(hw, true); + } + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("<====\n")); +} + +static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 tmpreg, index, rf_mode[2]; + u8 path = is2t ? 2 : 1; + u8 i; + u32 u4tmp, offset; + u32 curvecount_val[CV_CURVE_CNT * 2] = {0}; + u16 timeout = 800, timecount = 0; + + /* Check continuous TX and Packet TX */ + tmpreg = rtl_read_byte(rtlpriv, 0xd03); + /* if Deal with contisuous TX case, disable all continuous TX */ + /* if Deal with Packet TX case, block all queues */ + if ((tmpreg & 0x70) != 0) + rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F); + else + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xF00000, 0x0F); + for (index = 0; index < path; index++) { + /* 1. Read original RF mode */ + offset = index == 0 ? ROFDM0_XAAGCCORE1 : ROFDM0_XBAGCCORE1; + rf_mode[index] = rtl_read_byte(rtlpriv, offset); + /* 2. Set RF mode = standby mode */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_AC, + BRFREGOFFSETMASK, 0x010000); + if (rtlpci->init_ready) { + /* switch CV-curve control by LC-calibration */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_SYN_G7, + BIT(17), 0x0); + /* 4. Set LC calibration begin */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_CHNLBW, + 0x08000, 0x01); + } + u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, RF_SYN_G6, + BRFREGOFFSETMASK); + while ((!(u4tmp & BIT(11))) && timecount <= timeout) { + mdelay(50); + timecount += 50; + u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, + RF_SYN_G6, BRFREGOFFSETMASK); + } + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("PHY_LCK finish delay for %d ms=2\n", timecount)); + u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, BRFREGOFFSETMASK); + if (index == 0 && rtlhal->interfaceindex == 0) { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("path-A / 5G LCK\n")); + } else { + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("path-B / 2.4G LCK\n")); + } + memset(&curvecount_val[0], 0, CV_CURVE_CNT * 2); + /* Set LC calibration off */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_CHNLBW, + 0x08000, 0x0); + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("set RF 0x18[15] = 0\n")); + /* save Curve-counting number */ + for (i = 0; i < CV_CURVE_CNT; i++) { + u32 readval = 0, readval2 = 0; + rtl_set_rfreg(hw, (enum radio_path)index, 0x3F, + 0x7f, i); + + rtl_set_rfreg(hw, (enum radio_path)index, 0x4D, + BRFREGOFFSETMASK, 0x0); + readval = rtl_get_rfreg(hw, (enum radio_path)index, + 0x4F, BRFREGOFFSETMASK); + curvecount_val[2 * i + 1] = (readval & 0xfffe0) >> 5; + /* reg 0x4f [4:0] */ + /* reg 0x50 [19:10] */ + readval2 = rtl_get_rfreg(hw, (enum radio_path)index, + 0x50, 0xffc00); + curvecount_val[2 * i] = (((readval & 0x1F) << 10) | + readval2); + } + if (index == 0 && rtlhal->interfaceindex == 0) + _rtl92d_phy_calc_curvindex(hw, targetchnl_5g, + curvecount_val, + true, curveindex_5g); + else + _rtl92d_phy_calc_curvindex(hw, targetchnl_2g, + curvecount_val, + false, curveindex_2g); + /* switch CV-curve control mode */ + rtl_set_rfreg(hw, (enum radio_path)index, RF_SYN_G7, + BIT(17), 0x1); + } + + /* Restore original situation */ + for (index = 0; index < path; index++) { + offset = index == 0 ? ROFDM0_XAAGCCORE1 : ROFDM0_XBAGCCORE1; + rtl_write_byte(rtlpriv, offset, 0x50); + rtl_write_byte(rtlpriv, offset, rf_mode[index]); + } + if ((tmpreg & 0x70) != 0) + rtl_write_byte(rtlpriv, 0xd03, tmpreg); + else /*Deal with Packet TX case */ + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xF00000, 0x00); + _rtl92d_phy_reload_lck_setting(hw, rtlpriv->phy.current_channel); +} + +static void _rtl92d_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("cosa PHY_LCK ver=2\n")); + _rtl92d_phy_lc_calibrate_sw(hw, is2t); +} + +void rtl92d_phy_lc_calibrate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 timeout = 2000, timecount = 0; + + while (rtlpriv->mac80211.act_scanning && timecount < timeout) { + udelay(50); + timecount += 50; + } + + rtlphy->lck_inprogress = true; + RTPRINT(rtlpriv, FINIT, INIT_IQK, + ("LCK:Start!!! currentband %x delay %d ms\n", + rtlhal->current_bandtype, timecount)); + if (IS_92D_SINGLEPHY(rtlhal->version)) { + _rtl92d_phy_lc_calibrate(hw, true); + } else { + /* For 1T1R */ + _rtl92d_phy_lc_calibrate(hw, false); + } + rtlphy->lck_inprogress = false; + RTPRINT(rtlpriv, FINIT, INIT_IQK, ("LCK:Finish!!!\n")); +} + +void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +{ + return; +} + +static bool _rtl92d_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, + u32 cmdtableidx, u32 cmdtablesz, enum swchnlcmd_id cmdid, + u32 para1, u32 para2, u32 msdelay) +{ + struct swchnlcmd *pcmd; + + if (cmdtable == NULL) { + RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); + return false; + } + if (cmdtableidx >= cmdtablesz) + return false; + + pcmd = cmdtable + cmdtableidx; + pcmd->cmdid = cmdid; + pcmd->para1 = para1; + pcmd->para2 = para2; + pcmd->msdelay = msdelay; + return true; +} + +void rtl92d_phy_reset_iqk_result(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 i; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("settings regs %d default regs %d\n", + (int)(sizeof(rtlphy->iqk_matrix_regsetting) / + sizeof(struct iqk_matrix_regs)), + IQK_MATRIX_REG_NUM)); + /* 0xe94, 0xe9c, 0xea4, 0xeac, 0xeb4, 0xebc, 0xec4, 0xecc */ + for (i = 0; i < IQK_MATRIX_SETTINGS_NUM; i++) { + rtlphy->iqk_matrix_regsetting[i].value[0][0] = 0x100; + rtlphy->iqk_matrix_regsetting[i].value[0][2] = 0x100; + rtlphy->iqk_matrix_regsetting[i].value[0][4] = 0x100; + rtlphy->iqk_matrix_regsetting[i].value[0][6] = 0x100; + rtlphy->iqk_matrix_regsetting[i].value[0][1] = 0x0; + rtlphy->iqk_matrix_regsetting[i].value[0][3] = 0x0; + rtlphy->iqk_matrix_regsetting[i].value[0][5] = 0x0; + rtlphy->iqk_matrix_regsetting[i].value[0][7] = 0x0; + rtlphy->iqk_matrix_regsetting[i].iqk_done = false; + } +} + +static bool _rtl92d_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, + u32 *delay) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct swchnlcmd precommoncmd[MAX_PRECMD_CNT]; + u32 precommoncmdcnt; + struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT]; + u32 postcommoncmdcnt; + struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT]; + u32 rfdependcmdcnt; + struct swchnlcmd *currentcmd = NULL; + u8 rfpath; + u8 num_total_rfpath = rtlphy->num_total_rfpath; + + precommoncmdcnt = 0; + _rtl92d_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, + CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0); + _rtl92d_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + postcommoncmdcnt = 0; + _rtl92d_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, + MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); + rfdependcmdcnt = 0; + _rtl92d_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, + RF_CHNLBW, channel, 0); + _rtl92d_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_END, + 0, 0, 0); + + do { + switch (*stage) { + case 0: + currentcmd = &precommoncmd[*step]; + break; + case 1: + currentcmd = &rfdependcmd[*step]; + break; + case 2: + currentcmd = &postcommoncmd[*step]; + break; + } + if (currentcmd->cmdid == CMDID_END) { + if ((*stage) == 2) { + return true; + } else { + (*stage)++; + (*step) = 0; + continue; + } + } + switch (currentcmd->cmdid) { + case CMDID_SET_TXPOWEROWER_LEVEL: + rtl92d_phy_set_txpower_level(hw, channel); + break; + case CMDID_WRITEPORT_ULONG: + rtl_write_dword(rtlpriv, currentcmd->para1, + currentcmd->para2); + break; + case CMDID_WRITEPORT_USHORT: + rtl_write_word(rtlpriv, currentcmd->para1, + (u16)currentcmd->para2); + break; + case CMDID_WRITEPORT_UCHAR: + rtl_write_byte(rtlpriv, currentcmd->para1, + (u8)currentcmd->para2); + break; + case CMDID_RF_WRITEREG: + for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = + ((rtlphy->rfreg_chnlval[rfpath] & + 0xffffff00) | currentcmd->para2); + if (rtlpriv->rtlhal.current_bandtype == + BAND_ON_5G) { + if (currentcmd->para2 > 99) + rtlphy->rfreg_chnlval[rfpath] = + rtlphy->rfreg_chnlval + [rfpath] | (BIT(18)); + else + rtlphy->rfreg_chnlval[rfpath] = + rtlphy->rfreg_chnlval + [rfpath] & (~BIT(18)); + rtlphy->rfreg_chnlval[rfpath] |= + (BIT(16) | BIT(8)); + } else { + rtlphy->rfreg_chnlval[rfpath] &= + ~(BIT(8) | BIT(16) | BIT(18)); + } + rtl_set_rfreg(hw, (enum radio_path)rfpath, + currentcmd->para1, + BRFREGOFFSETMASK, + rtlphy->rfreg_chnlval[rfpath]); + _rtl92d_phy_reload_imr_setting(hw, channel, + rfpath); + } + _rtl92d_phy_switch_rf_setting(hw, channel); + /* do IQK when all parameters are ready */ + rtl92d_phy_reload_iqk_setting(hw, channel); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + break; + } while (true); + (*delay) = currentcmd->msdelay; + (*step)++; + return false; +} + +u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 delay; + u32 timeout = 1000, timecount = 0; + u8 channel = rtlphy->current_channel; + u32 ret_value; + + if (rtlphy->sw_chnl_inprogress) + return 0; + if (rtlphy->set_bwmode_inprogress) + return 0; + + if ((is_hal_stop(rtlhal)) || (RT_CANNOT_IO(hw))) { + RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, + ("sw_chnl_inprogress false driver sleep or unload\n")); + return 0; + } + while (rtlphy->lck_inprogress && timecount < timeout) { + mdelay(50); + timecount += 50; + } + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && + rtlhal->bandset == BAND_ON_BOTH) { + ret_value = rtl_get_bbreg(hw, RFPGA0_XAB_RFPARAMETER, + BMASKDWORD); + if (rtlphy->current_channel > 14 && !(ret_value & BIT(0))) + rtl92d_phy_switch_wirelessband(hw, BAND_ON_5G); + else if (rtlphy->current_channel <= 14 && (ret_value & BIT(0))) + rtl92d_phy_switch_wirelessband(hw, BAND_ON_2_4G); + } + switch (rtlhal->current_bandtype) { + case BAND_ON_5G: + /* Get first channel error when change between + * 5G and 2.4G band. */ + if (channel <= 14) + return 0; + RT_ASSERT((channel > 14), ("5G but channel<=14")); + break; + case BAND_ON_2_4G: + /* Get first channel error when change between + * 5G and 2.4G band. */ + if (channel > 14) + return 0; + RT_ASSERT((channel <= 14), ("2G but channel>14")); + break; + default: + RT_ASSERT(false, + ("Invalid WirelessMode(%#x)!!\n", + rtlpriv->mac80211.mode)); + break; + } + rtlphy->sw_chnl_inprogress = true; + if (channel == 0) + channel = 1; + rtlphy->sw_chnl_stage = 0; + rtlphy->sw_chnl_step = 0; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, + ("switch to channel%d\n", rtlphy->current_channel)); + + do { + if (!rtlphy->sw_chnl_inprogress) + break; + if (!_rtl92d_phy_sw_chnl_step_by_step(hw, + rtlphy->current_channel, + &rtlphy->sw_chnl_stage, &rtlphy->sw_chnl_step, &delay)) { + if (delay > 0) + mdelay(delay); + else + continue; + } else { + rtlphy->sw_chnl_inprogress = false; + } + break; + } while (true); + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); + rtlphy->sw_chnl_inprogress = false; + return 1; +} + +static void rtl92d_phy_set_io(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + ("--->Cmd(%#x), set_io_inprogress(%d)\n", + rtlphy->current_io_type, rtlphy->set_io_inprogress)); + switch (rtlphy->current_io_type) { + case IO_CMD_RESUME_DM_BY_SCAN: + de_digtable.cur_igvalue = rtlphy->initgain_backup.xaagccore1; + rtl92d_dm_write_dig(hw); + rtl92d_phy_set_txpower_level(hw, rtlphy->current_channel); + break; + case IO_CMD_PAUSE_DM_BY_SCAN: + rtlphy->initgain_backup.xaagccore1 = de_digtable.cur_igvalue; + de_digtable.cur_igvalue = 0x17; + rtl92d_dm_write_dig(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + rtlphy->set_io_inprogress = false; + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + ("<---(%#x)\n", rtlphy->current_io_type)); +} + +bool rtl92d_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool postprocessing = false; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + ("-->IO Cmd(%#x), set_io_inprogress(%d)\n", + iotype, rtlphy->set_io_inprogress)); + do { + switch (iotype) { + case IO_CMD_RESUME_DM_BY_SCAN: + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + ("[IO CMD] Resume DM after scan.\n")); + postprocessing = true; + break; + case IO_CMD_PAUSE_DM_BY_SCAN: + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + ("[IO CMD] Pause DM before scan.\n")); + postprocessing = true; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + } while (false); + if (postprocessing && !rtlphy->set_io_inprogress) { + rtlphy->set_io_inprogress = true; + rtlphy->current_io_type = iotype; + } else { + return false; + } + rtl92d_phy_set_io(hw); + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, ("<--IO Type(%#x)\n", iotype)); + return true; +} + +static void _rtl92d_phy_set_rfon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* a. SYS_CLKR 0x08[11] = 1 restore MAC clock */ + /* b. SPS_CTRL 0x11[7:0] = 0x2b */ + if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); + /* c. For PCIE: SYS_FUNC_EN 0x02[7:0] = 0xE3 enable BB TRX function */ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + /* RF_ON_EXCEP(d~g): */ + /* d. APSD_CTRL 0x600[7:0] = 0x00 */ + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); + /* e. SYS_FUNC_EN 0x02[7:0] = 0xE2 reset BB TRX function again */ + /* f. SYS_FUNC_EN 0x02[7:0] = 0xE3 enable BB TRX function*/ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + /* g. txpause 0x522[7:0] = 0x00 enable mac tx queue */ + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +} + +static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 u4btmp; + u8 delay = 5; + + /* a. TXPAUSE 0x522[7:0] = 0xFF Pause MAC TX queue */ + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + /* b. RF path 0 offset 0x00 = 0x00 disable RF */ + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + /* c. APSD_CTRL 0x600[7:0] = 0x40 */ + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + /* d. APSD_CTRL 0x600[7:0] = 0x00 + * APSD_CTRL 0x600[7:0] = 0x00 + * RF path 0 offset 0x00 = 0x00 + * APSD_CTRL 0x600[7:0] = 0x40 + * */ + u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK); + while (u4btmp != 0 && delay > 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK); + delay--; + } + if (delay == 0) { + /* Jump out the LPS turn off sequence to RF_ON_EXCEP */ + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); + + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Fail !!! Switch RF timeout.\n")); + return; + } + /* e. For PCIE: SYS_FUNC_EN 0x02[7:0] = 0xE2 reset BB TRX function */ + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + /* f. SPS_CTRL 0x11[7:0] = 0x22 */ + if (rtlpriv->rtlhal.macphymode == SINGLEMAC_SINGLEPHY) + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); + /* g. SYS_CLKR 0x08[11] = 0 gated MAC clock */ +} + +bool rtl92d_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + + bool bresult = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 i, queue_id; + struct rtl8192_tx_ring *ring = NULL; + + if (rfpwr_state == ppsc->rfpwr_state) + return false; + switch (rfpwr_state) { + case ERFON: + if ((ppsc->rfpwr_state == ERFOFF) && + RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + bool rtstatus; + u32 InitializeCount = 0; + do { + InitializeCount++; + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("IPS Set eRf nic enable\n")); + rtstatus = rtl_ps_enable_nic(hw); + } while ((rtstatus != true) && + (InitializeCount < 10)); + + RT_CLEAR_PS_LEVEL(ppsc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("awake, sleeped:%d ms state_" + "inap:%x\n", + jiffies_to_msecs(jiffies - + ppsc->last_sleep_jiffies), + rtlpriv->psc.state_inap)); + ppsc->last_awake_jiffies = jiffies; + _rtl92d_phy_set_rfon(hw); + } + + if (mac->link_state == MAC80211_LINKED) + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_LINK); + else + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + break; + case ERFOFF: + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("IPS Set eRf nic disable\n")); + rtl_ps_disable_nic(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } else { + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + else + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_POWER_OFF); + } + break; + case ERFSLEEP: + if (ppsc->rfpwr_state == ERFOFF) + break; + + for (queue_id = 0, i = 0; + queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { + ring = &pcipriv->dev.tx_ring[queue_id]; + if (skb_queue_len(&ring->queue) == 0 || + queue_id == BEACON_QUEUE) { + queue_id++; + continue; + } else if (rtlpci->pdev->current_state != PCI_D0) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("eRf Off/Sleep: %d times TcbBusyQueu" + "e[%d] !=0 but lower power state!\n", + (i + 1), queue_id)); + break; + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("eRf Off/Sleep: %d times TcbBusyQueu" + "e[%d] =%d " + "before doze!\n", (i + 1), queue_id, + skb_queue_len(&ring->queue))); + udelay(10); + i++; + } + + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("\nERFOFF: %d times TcbBusyQueue[%d] " + "= %d !\n", + MAX_DOZE_WAITING_TIMES_9x, queue_id, + skb_queue_len(&ring->queue))); + break; + } + } + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("Set rfsleep awaked:%d ms\n", + jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies))); + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ("sleep awaked:%d ms " + "state_inap:%x\n", jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies), rtlpriv->psc.state_inap)); + ppsc->last_sleep_jiffies = jiffies; + _rtl92d_phy_set_rfsleep(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + bresult = false; + break; + } + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + return bresult; +} + +void rtl92d_phy_config_macphymode(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 offset = REG_MAC_PHY_CTRL_NORMAL; + + switch (rtlhal->macphymode) { + case DUALMAC_DUALPHY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("MacPhyMode: DUALMAC_DUALPHY\n")); + rtl_write_byte(rtlpriv, offset, 0xF3); + break; + case SINGLEMAC_SINGLEPHY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("MacPhyMode: SINGLEMAC_SINGLEPHY\n")); + rtl_write_byte(rtlpriv, offset, 0xF4); + break; + case DUALMAC_SINGLEPHY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("MacPhyMode: DUALMAC_SINGLEPHY\n")); + rtl_write_byte(rtlpriv, offset, 0xF1); + break; + } +} + +void rtl92d_phy_config_macphymode_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + switch (rtlhal->macphymode) { + case DUALMAC_SINGLEPHY: + rtlphy->rf_type = RF_2T2R; + rtlhal->version |= CHIP_92D_SINGLEPHY; + rtlhal->bandset = BAND_ON_BOTH; + rtlhal->current_bandtype = BAND_ON_2_4G; + break; + + case SINGLEMAC_SINGLEPHY: + rtlphy->rf_type = RF_2T2R; + rtlhal->version |= CHIP_92D_SINGLEPHY; + rtlhal->bandset = BAND_ON_BOTH; + rtlhal->current_bandtype = BAND_ON_2_4G; + break; + + case DUALMAC_DUALPHY: + rtlphy->rf_type = RF_1T1R; + rtlhal->version &= (~CHIP_92D_SINGLEPHY); + /* Now we let MAC0 run on 5G band. */ + if (rtlhal->interfaceindex == 0) { + rtlhal->bandset = BAND_ON_5G; + rtlhal->current_bandtype = BAND_ON_5G; + } else { + rtlhal->bandset = BAND_ON_2_4G; + rtlhal->current_bandtype = BAND_ON_2_4G; + } + break; + default: + break; + } +} + +u8 rtl92d_get_chnlgroup_fromarray(u8 chnl) +{ + u8 group; + u8 channel_info[59] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, + 58, 60, 62, 64, 100, 102, 104, 106, 108, + 110, 112, 114, 116, 118, 120, 122, 124, + 126, 128, 130, 132, 134, 136, 138, 140, + 149, 151, 153, 155, 157, 159, 161, 163, + 165 + }; + + if (channel_info[chnl] <= 3) + group = 0; + else if (channel_info[chnl] <= 9) + group = 1; + else if (channel_info[chnl] <= 14) + group = 2; + else if (channel_info[chnl] <= 44) + group = 3; + else if (channel_info[chnl] <= 54) + group = 4; + else if (channel_info[chnl] <= 64) + group = 5; + else if (channel_info[chnl] <= 112) + group = 6; + else if (channel_info[chnl] <= 126) + group = 7; + else if (channel_info[chnl] <= 140) + group = 8; + else if (channel_info[chnl] <= 153) + group = 9; + else if (channel_info[chnl] <= 159) + group = 10; + else + group = 11; + return group; +} + +void rtl92d_phy_set_poweron(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flags; + u8 value8; + u16 i; + u32 mac_reg = (rtlhal->interfaceindex == 0 ? REG_MAC0 : REG_MAC1); + + /* notice fw know band status 0x81[1]/0x53[1] = 0: 5G, 1: 2G */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + value8 = rtl_read_byte(rtlpriv, mac_reg); + value8 |= BIT(1); + rtl_write_byte(rtlpriv, mac_reg, value8); + } else { + value8 = rtl_read_byte(rtlpriv, mac_reg); + value8 &= (~BIT(1)); + rtl_write_byte(rtlpriv, mac_reg, value8); + } + + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY) { + value8 = rtl_read_byte(rtlpriv, REG_MAC0); + rtl_write_byte(rtlpriv, REG_MAC0, value8 | MAC0_ON); + } else { + spin_lock_irqsave(&globalmutex_power, flags); + if (rtlhal->interfaceindex == 0) { + value8 = rtl_read_byte(rtlpriv, REG_MAC0); + rtl_write_byte(rtlpriv, REG_MAC0, value8 | MAC0_ON); + } else { + value8 = rtl_read_byte(rtlpriv, REG_MAC1); + rtl_write_byte(rtlpriv, REG_MAC1, value8 | MAC1_ON); + } + value8 = rtl_read_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS); + spin_unlock_irqrestore(&globalmutex_power, flags); + for (i = 0; i < 200; i++) { + if ((value8 & BIT(7)) == 0) { + break; + } else { + udelay(500); + spin_lock_irqsave(&globalmutex_power, flags); + value8 = rtl_read_byte(rtlpriv, + REG_POWER_OFF_IN_PROCESS); + spin_unlock_irqrestore(&globalmutex_power, + flags); + } + } + if (i == 200) + RT_ASSERT(false, ("Another mac power off over time\n")); + } +} + +void rtl92d_phy_config_maccoexist_rfpage(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (rtlpriv->rtlhal.macphymode) { + case DUALMAC_DUALPHY: + rtl_write_byte(rtlpriv, REG_DMC, 0x0); + rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x08); + rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x13ff); + break; + case DUALMAC_SINGLEPHY: + rtl_write_byte(rtlpriv, REG_DMC, 0xf8); + rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x08); + rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x13ff); + break; + case SINGLEMAC_SINGLEPHY: + rtl_write_byte(rtlpriv, REG_DMC, 0x0); + rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x10); + rtl_write_word(rtlpriv, (REG_TRXFF_BNDY + 2), 0x27FF); + break; + default: + break; + } +} + +void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 rfpath, i; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("==>\n")); + /* r_select_5G for path_A/B 0 for 2.4G, 1 for 5G */ + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* r_select_5G for path_A/B,0x878 */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(0), 0x0); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(15), 0x0); + if (rtlhal->macphymode != DUALMAC_DUALPHY) { + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(16), 0x0); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(31), 0x0); + } + /* rssi_table_select:index 0 for 2.4G.1~3 for 5G,0xc78 */ + rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, BIT(6) | BIT(7), 0x0); + /* fc_area 0xd2c */ + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(14) | BIT(13), 0x0); + /* 5G LAN ON */ + rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0xa); + /* TX BB gain shift*1,Just for testchip,0xc80,0xc88 */ + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + 0x40000100); + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, + BIT(10) | BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(3)) >> 3) | + (rtlefuse->eeprom_c9 & BIT(1)) | + ((rtlefuse->eeprom_cc & BIT(1)) << 4)); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, + BIT(10) | BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(2)) >> 2) | + ((rtlefuse->eeprom_c9 & BIT(0)) << 1) | + ((rtlefuse->eeprom_cc & BIT(0)) << 5)); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(15), 0); + } else { + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, + BIT(26) | BIT(22) | BIT(21) | BIT(10) | + BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(3)) >> 3) | + (rtlefuse->eeprom_c9 & BIT(1)) | + ((rtlefuse->eeprom_cc & BIT(1)) << 4) | + ((rtlefuse->eeprom_c9 & BIT(7)) << 9) | + ((rtlefuse->eeprom_c9 & BIT(5)) << 12) | + ((rtlefuse->eeprom_cc & BIT(3)) << 18)); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, + BIT(10) | BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(2)) >> 2) | + ((rtlefuse->eeprom_c9 & BIT(0)) << 1) | + ((rtlefuse->eeprom_cc & BIT(0)) << 5)); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, + BIT(10) | BIT(6) | BIT(5), + ((rtlefuse->eeprom_c9 & BIT(6)) >> 6) | + ((rtlefuse->eeprom_c9 & BIT(4)) >> 3) | + ((rtlefuse->eeprom_cc & BIT(2)) << 3)); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, + BIT(31) | BIT(15), 0); + } + /* 1.5V_LDO */ + } else { + /* r_select_5G for path_A/B */ + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(0), 0x1); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(15), 0x1); + if (rtlhal->macphymode != DUALMAC_DUALPHY) { + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(16), 0x1); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(31), 0x1); + } + /* rssi_table_select:index 0 for 2.4G.1~3 for 5G */ + rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, BIT(6) | BIT(7), 0x1); + /* fc_area */ + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(14) | BIT(13), 0x1); + /* 5G LAN ON */ + rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0x0); + /* TX BB gain shift,Just for testchip,0xc80,0xc88 */ + if (rtlefuse->internal_pa_5g[0]) + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + 0x2d4000b5); + else + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + 0x20000080); + if (rtlefuse->internal_pa_5g[1]) + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + 0x2d4000b5); + else + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + 0x20000080); + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, + BIT(10) | BIT(6) | BIT(5), + (rtlefuse->eeprom_cc & BIT(5))); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(10), + ((rtlefuse->eeprom_cc & BIT(4)) >> 4)); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(15), + (rtlefuse->eeprom_cc & BIT(4)) >> 4); + } else { + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, + BIT(26) | BIT(22) | BIT(21) | BIT(10) | + BIT(6) | BIT(5), + (rtlefuse->eeprom_cc & BIT(5)) | + ((rtlefuse->eeprom_cc & BIT(7)) << 14)); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(10), + ((rtlefuse->eeprom_cc & BIT(4)) >> 4)); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(10), + ((rtlefuse->eeprom_cc & BIT(6)) >> 6)); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, + BIT(31) | BIT(15), + ((rtlefuse->eeprom_cc & BIT(4)) >> 4) | + ((rtlefuse->eeprom_cc & BIT(6)) << 10)); + } + } + /* update IQK related settings */ + rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, BMASKDWORD, 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, BMASKDWORD, 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, 0xF0000000, 0x00); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(30) | BIT(28) | + BIT(26) | BIT(24), 0x00); + rtl_set_bbreg(hw, ROFDM0_XDTxAFE, 0xF0000000, 0x00); + rtl_set_bbreg(hw, 0xca0, 0xF0000000, 0x00); + rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, 0x0000F000, 0x00); + + /* Update RF */ + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | BIT(16) | + BIT(18), 0); + /* RF0x0b[16:14] =3b'111 */ + rtl_set_rfreg(hw, (enum radio_path)rfpath, 0x0B, + 0x1c000, 0x07); + } else { + /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | + BIT(16) | BIT(18), + (BIT(16) | BIT(8)) >> 8); + } + } + /* Update for all band. */ + /* DMDP */ + if (rtlphy->rf_type == RF_1T1R) { + /* Use antenna 0,0xc04,0xd04 */ + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x11); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x1); + + /* enable ad/da clock1 for dual-phy reg0x888 */ + if (rtlhal->interfaceindex == 0) { + rtl_set_bbreg(hw, RFPGA0_ADDALLOCKEN, BIT(12) | + BIT(13), 0x3); + } else { + rtl92d_phy_enable_anotherphy(hw, false); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("MAC1 use DBI to update 0x888")); + /* 0x888 */ + rtl92de_write_dword_dbi(hw, RFPGA0_ADDALLOCKEN, + rtl92de_read_dword_dbi(hw, + RFPGA0_ADDALLOCKEN, + BIT(3)) | BIT(12) | BIT(13), + BIT(3)); + rtl92d_phy_powerdown_anotherphy(hw, false); + } + } else { + /* Single PHY */ + /* Use antenna 0 & 1,0xc04,0xd04 */ + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x33); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x3); + /* disable ad/da clock1,0x888 */ + rtl_set_bbreg(hw, RFPGA0_ADDALLOCKEN, BIT(12) | BIT(13), 0); + } + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = rtl_get_rfreg(hw, rfpath, + RF_CHNLBW, BRFREGOFFSETMASK); + rtlphy->reg_rf3c[rfpath] = rtl_get_rfreg(hw, rfpath, 0x3C, + BRFREGOFFSETMASK); + } + for (i = 0; i < 2; i++) + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, ("RF 0x18 = 0x%x\n", + rtlphy->rfreg_chnlval[i])); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("<==\n")); + +} + +bool rtl92d_phy_check_poweroff(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 u1btmp; + unsigned long flags; + + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY) { + u1btmp = rtl_read_byte(rtlpriv, REG_MAC0); + rtl_write_byte(rtlpriv, REG_MAC0, u1btmp & (~MAC0_ON)); + return true; + } + spin_lock_irqsave(&globalmutex_power, flags); + if (rtlhal->interfaceindex == 0) { + u1btmp = rtl_read_byte(rtlpriv, REG_MAC0); + rtl_write_byte(rtlpriv, REG_MAC0, u1btmp & (~MAC0_ON)); + u1btmp = rtl_read_byte(rtlpriv, REG_MAC1); + u1btmp &= MAC1_ON; + } else { + u1btmp = rtl_read_byte(rtlpriv, REG_MAC1); + rtl_write_byte(rtlpriv, REG_MAC1, u1btmp & (~MAC1_ON)); + u1btmp = rtl_read_byte(rtlpriv, REG_MAC0); + u1btmp &= MAC0_ON; + } + if (u1btmp) { + spin_unlock_irqrestore(&globalmutex_power, flags); + return false; + } + u1btmp = rtl_read_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS); + u1btmp |= BIT(7); + rtl_write_byte(rtlpriv, REG_POWER_OFF_IN_PROCESS, u1btmp); + spin_unlock_irqrestore(&globalmutex_power, flags); + return true; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.h b/drivers/net/wireless/rtlwifi/rtl8192de/phy.h new file mode 100644 index 000000000000..a52c824b41e3 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.h @@ -0,0 +1,178 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92D_PHY_H__ +#define __RTL92D_PHY_H__ + +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +#define MAX_DOZE_WAITING_TIMES_9x 64 + +#define RT_CANNOT_IO(hw) false +#define HIGHPOWER_RADIOA_ARRAYLEN 22 + +#define IQK_ADDA_REG_NUM 16 +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 + +#define APK_BB_REG_NUM 5 +#define APK_AFE_REG_NUM 16 +#define APK_CURVE_REG_NUM 4 +#define PATH_NUM 2 + +#define LOOP_LIMIT 5 +#define MAX_STALL_TIME 50 +#define ANTENNA_DIVERSITY_VALUE 0x80 +#define MAX_TXPWR_IDX_NMODE_92S 63 +#define RESET_CNT_LIMIT 3 + +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM 10 +#define IQK_BB_REG_NUM_test 6 +#define IQK_MAC_REG_NUM 4 +#define RX_INDEX_MAPPING_NUM 15 + +#define IQK_DELAY_TIME 1 + +#define CT_OFFSET_MAC_ADDR 0X16 + +#define CT_OFFSET_CCK_TX_PWR_IDX 0x5A +#define CT_OFFSET_HT401S_TX_PWR_IDX 0x60 +#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF 0x66 +#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF 0x69 +#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF 0x6C + +#define CT_OFFSET_HT40_MAX_PWR_OFFSET 0x6F +#define CT_OFFSET_HT20_MAX_PWR_OFFSET 0x72 + +#define CT_OFFSET_CHANNEL_PLAH 0x75 +#define CT_OFFSET_THERMAL_METER 0x78 +#define CT_OFFSET_RF_OPTION 0x79 +#define CT_OFFSET_VERSION 0x7E +#define CT_OFFSET_CUSTOMER_ID 0x7F + +enum swchnlcmd_id { + CMDID_END, + CMDID_SET_TXPOWEROWER_LEVEL, + CMDID_BBREGWRITE10, + CMDID_WRITEPORT_ULONG, + CMDID_WRITEPORT_USHORT, + CMDID_WRITEPORT_UCHAR, + CMDID_RF_WRITEREG, +}; + +struct swchnlcmd { + enum swchnlcmd_id cmdid; + u32 para1; + u32 para2; + u32 msdelay; +}; + +enum baseband_config_type { + BASEBAND_CONFIG_PHY_REG = 0, + BASEBAND_CONFIG_AGC_TAB = 1, +}; + +enum rf_content { + radioa_txt = 0, + radiob_txt = 1, + radioc_txt = 2, + radiod_txt = 3 +}; + +static inline void rtl92d_acquire_cckandrw_pagea_ctl(struct ieee80211_hw *hw, + unsigned long *flag) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->rtlhal.interfaceindex == 1) + spin_lock_irqsave(&rtlpriv->locks.cck_and_rw_pagea_lock, *flag); +} + +static inline void rtl92d_release_cckandrw_pagea_ctl(struct ieee80211_hw *hw, + unsigned long *flag) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->rtlhal.interfaceindex == 1) + spin_unlock_irqrestore(&rtlpriv->locks.cck_and_rw_pagea_lock, + *flag); +} + +extern u32 rtl92d_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask); +extern void rtl92d_phy_set_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, u32 data); +extern u32 rtl92d_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask); +extern void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, + u32 bitmask, u32 data); +extern bool rtl92d_phy_mac_config(struct ieee80211_hw *hw); +extern bool rtl92d_phy_bb_config(struct ieee80211_hw *hw); +extern bool rtl92d_phy_rf_config(struct ieee80211_hw *hw); +extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +extern void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +extern void rtl92d_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +extern void rtl92d_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation); +extern void rtl92d_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +extern u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw); +bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum rf_content content, + enum radio_path rfpath); +bool rtl92d_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +extern bool rtl92d_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); + +void rtl92d_phy_config_macphymode(struct ieee80211_hw *hw); +void rtl92d_phy_config_macphymode_info(struct ieee80211_hw *hw); +u8 rtl92d_get_chnlgroup_fromarray(u8 chnl); +void rtl92d_phy_set_poweron(struct ieee80211_hw *hw); +void rtl92d_phy_config_maccoexist_rfpage(struct ieee80211_hw *hw); +bool rtl92d_phy_check_poweroff(struct ieee80211_hw *hw); +void rtl92d_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw); +void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw); +void rtl92d_phy_reset_iqk_result(struct ieee80211_hw *hw); +void rtl92d_release_cckandrw_pagea_ctl(struct ieee80211_hw *hw, + unsigned long *flag); +void rtl92d_acquire_cckandrw_pagea_ctl(struct ieee80211_hw *hw, + unsigned long *flag); +u8 rtl92d_get_rightchnlplace_for_iqk(u8 chnl); +void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel); +void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h new file mode 100644 index 000000000000..131acc306fcc --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h @@ -0,0 +1,1313 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92D_REG_H__ +#define __RTL92D_REG_H__ + +/* ----------------------------------------------------- */ +/* 0x0000h ~ 0x00FFh System Configuration */ +/* ----------------------------------------------------- */ +#define REG_SYS_ISO_CTRL 0x0000 +#define REG_SYS_FUNC_EN 0x0002 +#define REG_APS_FSMCO 0x0004 +#define REG_SYS_CLKR 0x0008 +#define REG_9346CR 0x000A +#define REG_EE_VPD 0x000C +#define REG_AFE_MISC 0x0010 +#define REG_SPS0_CTRL 0x0011 +#define REG_POWER_OFF_IN_PROCESS 0x0017 +#define REG_SPS_OCP_CFG 0x0018 +#define REG_RSV_CTRL 0x001C +#define REG_RF_CTRL 0x001F +#define REG_LDOA15_CTRL 0x0020 +#define REG_LDOV12D_CTRL 0x0021 +#define REG_LDOHCI12_CTRL 0x0022 +#define REG_LPLDO_CTRL 0x0023 +#define REG_AFE_XTAL_CTRL 0x0024 +#define REG_AFE_PLL_CTRL 0x0028 +/* for 92d, DMDP,SMSP,DMSP contrl */ +#define REG_MAC_PHY_CTRL 0x002c +#define REG_EFUSE_CTRL 0x0030 +#define REG_EFUSE_TEST 0x0034 +#define REG_PWR_DATA 0x0038 +#define REG_CAL_TIMER 0x003C +#define REG_ACLK_MON 0x003E +#define REG_GPIO_MUXCFG 0x0040 +#define REG_GPIO_IO_SEL 0x0042 +#define REG_MAC_PINMUX_CFG 0x0043 +#define REG_GPIO_PIN_CTRL 0x0044 +#define REG_GPIO_INTM 0x0048 +#define REG_LEDCFG0 0x004C +#define REG_LEDCFG1 0x004D +#define REG_LEDCFG2 0x004E +#define REG_LEDCFG3 0x004F +#define REG_FSIMR 0x0050 +#define REG_FSISR 0x0054 + +#define REG_MCUFWDL 0x0080 + +#define REG_HMEBOX_EXT_0 0x0088 +#define REG_HMEBOX_EXT_1 0x008A +#define REG_HMEBOX_EXT_2 0x008C +#define REG_HMEBOX_EXT_3 0x008E + +#define REG_BIST_SCAN 0x00D0 +#define REG_BIST_RPT 0x00D4 +#define REG_BIST_ROM_RPT 0x00D8 +#define REG_USB_SIE_INTF 0x00E0 +#define REG_PCIE_MIO_INTF 0x00E4 +#define REG_PCIE_MIO_INTD 0x00E8 +#define REG_HPON_FSM 0x00EC +#define REG_SYS_CFG 0x00F0 +#define REG_MAC_PHY_CTRL_NORMAL 0x00f8 + +#define REG_MAC0 0x0081 +#define REG_MAC1 0x0053 +#define FW_MAC0_READY 0x18 +#define FW_MAC1_READY 0x1A +#define MAC0_ON BIT(7) +#define MAC1_ON BIT(0) +#define MAC0_READY BIT(0) +#define MAC1_READY BIT(0) + +/* ----------------------------------------------------- */ +/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ +/* ----------------------------------------------------- */ +#define REG_CR 0x0100 +#define REG_PBP 0x0104 +#define REG_TRXDMA_CTRL 0x010C +#define REG_TRXFF_BNDY 0x0114 +#define REG_TRXFF_STATUS 0x0118 +#define REG_RXFF_PTR 0x011C +#define REG_HIMR 0x0120 +#define REG_HISR 0x0124 +#define REG_HIMRE 0x0128 +#define REG_HISRE 0x012C +#define REG_CPWM 0x012F +#define REG_FWIMR 0x0130 +#define REG_FWISR 0x0134 +#define REG_PKTBUF_DBG_CTRL 0x0140 +#define REG_PKTBUF_DBG_DATA_L 0x0144 +#define REG_PKTBUF_DBG_DATA_H 0x0148 + +#define REG_TC0_CTRL 0x0150 +#define REG_TC1_CTRL 0x0154 +#define REG_TC2_CTRL 0x0158 +#define REG_TC3_CTRL 0x015C +#define REG_TC4_CTRL 0x0160 +#define REG_TCUNIT_BASE 0x0164 +#define REG_MBIST_START 0x0174 +#define REG_MBIST_DONE 0x0178 +#define REG_MBIST_FAIL 0x017C +#define REG_C2HEVT_MSG_NORMAL 0x01A0 +#define REG_C2HEVT_MSG_TEST 0x01B8 +#define REG_C2HEVT_CLEAR 0x01BF +#define REG_MCUTST_1 0x01c0 +#define REG_FMETHR 0x01C8 +#define REG_HMETFR 0x01CC +#define REG_HMEBOX_0 0x01D0 +#define REG_HMEBOX_1 0x01D4 +#define REG_HMEBOX_2 0x01D8 +#define REG_HMEBOX_3 0x01DC + +#define REG_LLT_INIT 0x01E0 +#define REG_BB_ACCEESS_CTRL 0x01E8 +#define REG_BB_ACCESS_DATA 0x01EC + + +/* ----------------------------------------------------- */ +/* 0x0200h ~ 0x027Fh TXDMA Configuration */ +/* ----------------------------------------------------- */ +#define REG_RQPN 0x0200 +#define REG_FIFOPAGE 0x0204 +#define REG_TDECTRL 0x0208 +#define REG_TXDMA_OFFSET_CHK 0x020C +#define REG_TXDMA_STATUS 0x0210 +#define REG_RQPN_NPQ 0x0214 + +/* ----------------------------------------------------- */ +/* 0x0280h ~ 0x02FFh RXDMA Configuration */ +/* ----------------------------------------------------- */ +#define REG_RXDMA_AGG_PG_TH 0x0280 +#define REG_RXPKT_NUM 0x0284 +#define REG_RXDMA_STATUS 0x0288 + +/* ----------------------------------------------------- */ +/* 0x0300h ~ 0x03FFh PCIe */ +/* ----------------------------------------------------- */ +#define REG_PCIE_CTRL_REG 0x0300 +#define REG_INT_MIG 0x0304 +#define REG_BCNQ_DESA 0x0308 +#define REG_HQ_DESA 0x0310 +#define REG_MGQ_DESA 0x0318 +#define REG_VOQ_DESA 0x0320 +#define REG_VIQ_DESA 0x0328 +#define REG_BEQ_DESA 0x0330 +#define REG_BKQ_DESA 0x0338 +#define REG_RX_DESA 0x0340 +#define REG_DBI 0x0348 +#define REG_DBI_WDATA 0x0348 +#define REG_DBI_RDATA 0x034C +#define REG_DBI_CTRL 0x0350 +#define REG_DBI_FLAG 0x0352 +#define REG_MDIO 0x0354 +#define REG_DBG_SEL 0x0360 +#define REG_PCIE_HRPWM 0x0361 +#define REG_PCIE_HCPWM 0x0363 +#define REG_UART_CTRL 0x0364 +#define REG_UART_TX_DESA 0x0370 +#define REG_UART_RX_DESA 0x0378 + +/* ----------------------------------------------------- */ +/* 0x0400h ~ 0x047Fh Protocol Configuration */ +/* ----------------------------------------------------- */ +#define REG_VOQ_INFORMATION 0x0400 +#define REG_VIQ_INFORMATION 0x0404 +#define REG_BEQ_INFORMATION 0x0408 +#define REG_BKQ_INFORMATION 0x040C +#define REG_MGQ_INFORMATION 0x0410 +#define REG_HGQ_INFORMATION 0x0414 +#define REG_BCNQ_INFORMATION 0x0418 + + +#define REG_CPU_MGQ_INFORMATION 0x041C +#define REG_FWHW_TXQ_CTRL 0x0420 +#define REG_HWSEQ_CTRL 0x0423 +#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 +#define REG_TXPKTBUF_MGQ_BDNY 0x0425 +#define REG_MULTI_BCNQ_EN 0x0426 +#define REG_MULTI_BCNQ_OFFSET 0x0427 +#define REG_SPEC_SIFS 0x0428 +#define REG_RL 0x042A +#define REG_DARFRC 0x0430 +#define REG_RARFRC 0x0438 +#define REG_RRSR 0x0440 +#define REG_ARFR0 0x0444 +#define REG_ARFR1 0x0448 +#define REG_ARFR2 0x044C +#define REG_ARFR3 0x0450 +#define REG_AGGLEN_LMT 0x0458 +#define REG_AMPDU_MIN_SPACE 0x045C +#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D +#define REG_FAST_EDCA_CTRL 0x0460 +#define REG_RD_RESP_PKT_TH 0x0463 +#define REG_INIRTS_RATE_SEL 0x0480 +#define REG_INIDATA_RATE_SEL 0x0484 +#define REG_POWER_STATUS 0x04A4 +#define REG_POWER_STAGE1 0x04B4 +#define REG_POWER_STAGE2 0x04B8 +#define REG_PKT_LIFE_TIME 0x04C0 +#define REG_STBC_SETTING 0x04C4 +#define REG_PROT_MODE_CTRL 0x04C8 +#define REG_MAX_AGGR_NUM 0x04CA +#define REG_RTS_MAX_AGGR_NUM 0x04CB +#define REG_BAR_MODE_CTRL 0x04CC +#define REG_RA_TRY_RATE_AGG_LMT 0x04CF +#define REG_EARLY_MODE_CONTROL 0x4D0 +#define REG_NQOS_SEQ 0x04DC +#define REG_QOS_SEQ 0x04DE +#define REG_NEED_CPU_HANDLE 0x04E0 +#define REG_PKT_LOSE_RPT 0x04E1 +#define REG_PTCL_ERR_STATUS 0x04E2 +#define REG_DUMMY 0x04FC + +/* ----------------------------------------------------- */ +/* 0x0500h ~ 0x05FFh EDCA Configuration */ +/* ----------------------------------------------------- */ +#define REG_EDCA_VO_PARAM 0x0500 +#define REG_EDCA_VI_PARAM 0x0504 +#define REG_EDCA_BE_PARAM 0x0508 +#define REG_EDCA_BK_PARAM 0x050C +#define REG_BCNTCFG 0x0510 +#define REG_PIFS 0x0512 +#define REG_RDG_PIFS 0x0513 +#define REG_SIFS_CTX 0x0514 +#define REG_SIFS_TRX 0x0516 +#define REG_AGGR_BREAK_TIME 0x051A +#define REG_SLOT 0x051B +#define REG_TX_PTCL_CTRL 0x0520 +#define REG_TXPAUSE 0x0522 +#define REG_DIS_TXREQ_CLR 0x0523 +#define REG_RD_CTRL 0x0524 +#define REG_TBTT_PROHIBIT 0x0540 +#define REG_RD_NAV_NXT 0x0544 +#define REG_NAV_PROT_LEN 0x0546 +#define REG_BCN_CTRL 0x0550 +#define REG_USTIME_TSF 0x0551 +#define REG_MBID_NUM 0x0552 +#define REG_DUAL_TSF_RST 0x0553 +#define REG_BCN_INTERVAL 0x0554 +#define REG_MBSSID_BCN_SPACE 0x0554 +#define REG_DRVERLYINT 0x0558 +#define REG_BCNDMATIM 0x0559 +#define REG_ATIMWND 0x055A +#define REG_BCN_MAX_ERR 0x055D +#define REG_RXTSF_OFFSET_CCK 0x055E +#define REG_RXTSF_OFFSET_OFDM 0x055F +#define REG_TSFTR 0x0560 +#define REG_INIT_TSFTR 0x0564 +#define REG_PSTIMER 0x0580 +#define REG_TIMER0 0x0584 +#define REG_TIMER1 0x0588 +#define REG_ACMHWCTRL 0x05C0 +#define REG_ACMRSTCTRL 0x05C1 +#define REG_ACMAVG 0x05C2 +#define REG_VO_ADMTIME 0x05C4 +#define REG_VI_ADMTIME 0x05C6 +#define REG_BE_ADMTIME 0x05C8 +#define REG_EDCA_RANDOM_GEN 0x05CC +#define REG_SCH_TXCMD 0x05D0 + +/* Dual MAC Co-Existence Register */ +#define REG_DMC 0x05F0 + +/* ----------------------------------------------------- */ +/* 0x0600h ~ 0x07FFh WMAC Configuration */ +/* ----------------------------------------------------- */ +#define REG_APSD_CTRL 0x0600 +#define REG_BWOPMODE 0x0603 +#define REG_TCR 0x0604 +#define REG_RCR 0x0608 +#define REG_RX_PKT_LIMIT 0x060C +#define REG_RX_DLK_TIME 0x060D +#define REG_RX_DRVINFO_SZ 0x060F + +#define REG_MACID 0x0610 +#define REG_BSSID 0x0618 +#define REG_MAR 0x0620 +#define REG_MBIDCAMCFG 0x0628 + +#define REG_USTIME_EDCA 0x0638 +#define REG_MAC_SPEC_SIFS 0x063A +#define REG_RESP_SIFS_CCK 0x063C +#define REG_RESP_SIFS_OFDM 0x063E +#define REG_ACKTO 0x0640 +#define REG_CTS2TO 0x0641 +#define REG_EIFS 0x0642 + + +/* WMA, BA, CCX */ +#define REG_NAV_CTRL 0x0650 +#define REG_BACAMCMD 0x0654 +#define REG_BACAMCONTENT 0x0658 +#define REG_LBDLY 0x0660 +#define REG_FWDLY 0x0661 +#define REG_RXERR_RPT 0x0664 +#define REG_WMAC_TRXPTCL_CTL 0x0668 + + +/* Security */ +#define REG_CAMCMD 0x0670 +#define REG_CAMWRITE 0x0674 +#define REG_CAMREAD 0x0678 +#define REG_CAMDBG 0x067C +#define REG_SECCFG 0x0680 + +/* Power */ +#define REG_WOW_CTRL 0x0690 +#define REG_PSSTATUS 0x0691 +#define REG_PS_RX_INFO 0x0692 +#define REG_LPNAV_CTRL 0x0694 +#define REG_WKFMCAM_CMD 0x0698 +#define REG_WKFMCAM_RWD 0x069C +#define REG_RXFLTMAP0 0x06A0 +#define REG_RXFLTMAP1 0x06A2 +#define REG_RXFLTMAP2 0x06A4 +#define REG_BCN_PSR_RPT 0x06A8 +#define REG_CALB32K_CTRL 0x06AC +#define REG_PKT_MON_CTRL 0x06B4 +#define REG_BT_COEX_TABLE 0x06C0 +#define REG_WMAC_RESP_TXINFO 0x06D8 + + +/* ----------------------------------------------------- */ +/* Redifine 8192C register definition for compatibility */ +/* ----------------------------------------------------- */ +#define CR9346 REG_9346CR +#define MSR (REG_CR + 2) +#define ISR REG_HISR +#define TSFR REG_TSFTR + +#define MACIDR0 REG_MACID +#define MACIDR4 (REG_MACID + 4) + +#define PBP REG_PBP + +#define IDR0 MACIDR0 +#define IDR4 MACIDR4 + +/* ----------------------------------------------------- */ +/* 8192C (MSR) Media Status Register(Offset 0x4C, 8 bits)*/ +/* ----------------------------------------------------- */ +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +/* 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) */ +/* ----------------------------------------------------- */ +/* 8192C Response Rate Set Register(offset 0x181, 24bits)*/ +/* ----------------------------------------------------- */ +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_BW_40M 0x600000 +#define RRSR_RSC_UPSUBCHNL 0x400000 +#define RRSR_RSC_LOWSUBCHNL 0x200000 +#define RRSR_SHORT 0x800000 +#define RRSR_1M BIT0 +#define RRSR_2M BIT1 +#define RRSR_5_5M BIT2 +#define RRSR_11M BIT3 +#define RRSR_6M BIT4 +#define RRSR_9M BIT5 +#define RRSR_12M BIT6 +#define RRSR_18M BIT7 +#define RRSR_24M BIT8 +#define RRSR_36M BIT9 +#define RRSR_48M BIT10 +#define RRSR_54M BIT11 +#define RRSR_MCS0 BIT12 +#define RRSR_MCS1 BIT13 +#define RRSR_MCS2 BIT14 +#define RRSR_MCS3 BIT15 +#define RRSR_MCS4 BIT16 +#define RRSR_MCS5 BIT17 +#define RRSR_MCS6 BIT18 +#define RRSR_MCS7 BIT19 +#define BRSR_ACKSHORTPMB BIT23 + +/* ----------------------------------------------------- */ +/* 8192C Rate Definition */ +/* ----------------------------------------------------- */ +/* CCK */ +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +/* OFDM */ +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +/* MCS 1 Spatial Stream */ +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +/* MCS 2 Spatial Stream */ +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 + +/* CCK */ +#define RATE_1M BIT(0) +#define RATE_2M BIT(1) +#define RATE_5_5M BIT(2) +#define RATE_11M BIT(3) +/* OFDM */ +#define RATE_6M BIT(4) +#define RATE_9M BIT(5) +#define RATE_12M BIT(6) +#define RATE_18M BIT(7) +#define RATE_24M BIT(8) +#define RATE_36M BIT(9) +#define RATE_48M BIT(10) +#define RATE_54M BIT(11) +/* MCS 1 Spatial Stream */ +#define RATE_MCS0 BIT(12) +#define RATE_MCS1 BIT(13) +#define RATE_MCS2 BIT(14) +#define RATE_MCS3 BIT(15) +#define RATE_MCS4 BIT(16) +#define RATE_MCS5 BIT(17) +#define RATE_MCS6 BIT(18) +#define RATE_MCS7 BIT(19) +/* MCS 2 Spatial Stream */ +#define RATE_MCS8 BIT(20) +#define RATE_MCS9 BIT(21) +#define RATE_MCS10 BIT(22) +#define RATE_MCS11 BIT(23) +#define RATE_MCS12 BIT(24) +#define RATE_MCS13 BIT(25) +#define RATE_MCS14 BIT(26) +#define RATE_MCS15 BIT(27) + +/* ALL CCK Rate */ +#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | \ + RATR_11M) +#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | \ + RATR_18M | RATR_24M | \ + RATR_36M | RATR_48M | RATR_54M) +#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \ + RATR_MCS3 | RATR_MCS4 | RATR_MCS5 | \ + RATR_MCS6 | RATR_MCS7) +#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \ + RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \ + RATR_MCS14 | RATR_MCS15) + +/* ----------------------------------------------------- */ +/* 8192C BW_OPMODE bits (Offset 0x203, 8bit) */ +/* ----------------------------------------------------- */ +#define BW_OPMODE_20MHZ BIT(2) +#define BW_OPMODE_5G BIT(1) +#define BW_OPMODE_11J BIT(0) + + +/* ----------------------------------------------------- */ +/* 8192C CAM Config Setting (offset 0x250, 1 byte) */ +/* ----------------------------------------------------- */ +#define CAM_VALID BIT(15) +#define CAM_NOTVALID 0x0000 +#define CAM_USEDK BIT(5) + +#define CAM_NONE 0x0 +#define CAM_WEP40 0x01 +#define CAM_TKIP 0x02 +#define CAM_AES 0x04 +#define CAM_WEP104 0x05 +#define CAM_SMS4 0x6 + + +#define TOTAL_CAM_ENTRY 32 +#define HALF_CAM_ENTRY 16 + +#define CAM_WRITE BIT(16) +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT(31) + +/* 10. Power Save Control Registers (Offset: 0x0260 - 0x02DF) */ +#define WOW_PMEN BIT0 /* Power management Enable. */ +#define WOW_WOMEN BIT1 /* WoW function on or off. */ +#define WOW_MAGIC BIT2 /* Magic packet */ +#define WOW_UWF BIT3 /* Unicast Wakeup frame. */ + +/* 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) */ +/* ----------------------------------------------------- */ +/* 8190 IMR/ISR bits (offset 0xfd, 8bits) */ +/* ----------------------------------------------------- */ +#define IMR8190_DISABLED 0x0 +#define IMR_BCNDMAINT6 BIT(31) +#define IMR_BCNDMAINT5 BIT(30) +#define IMR_BCNDMAINT4 BIT(29) +#define IMR_BCNDMAINT3 BIT(28) +#define IMR_BCNDMAINT2 BIT(27) +#define IMR_BCNDMAINT1 BIT(26) +#define IMR_BCNDOK8 BIT(25) +#define IMR_BCNDOK7 BIT(24) +#define IMR_BCNDOK6 BIT(23) +#define IMR_BCNDOK5 BIT(22) +#define IMR_BCNDOK4 BIT(21) +#define IMR_BCNDOK3 BIT(20) +#define IMR_BCNDOK2 BIT(19) +#define IMR_BCNDOK1 BIT(18) +#define IMR_TIMEOUT2 BIT(17) +#define IMR_TIMEOUT1 BIT(16) +#define IMR_TXFOVW BIT(15) +#define IMR_PSTIMEOUT BIT(14) +#define IMR_BcnInt BIT(13) +#define IMR_RXFOVW BIT(12) +#define IMR_RDU BIT(11) +#define IMR_ATIMEND BIT(10) +#define IMR_BDOK BIT(9) +#define IMR_HIGHDOK BIT(8) +#define IMR_TBDOK BIT(7) +#define IMR_MGNTDOK BIT(6) +#define IMR_TBDER BIT(5) +#define IMR_BKDOK BIT(4) +#define IMR_BEDOK BIT(3) +#define IMR_VIDOK BIT(2) +#define IMR_VODOK BIT(1) +#define IMR_ROK BIT(0) + +#define IMR_TXERR BIT(11) +#define IMR_RXERR BIT(10) +#define IMR_C2HCMD BIT(9) +#define IMR_CPWM BIT(8) +#define IMR_OCPINT BIT(1) +#define IMR_WLANOFF BIT(0) + +/* ----------------------------------------------------- */ +/* 8192C EFUSE */ +/* ----------------------------------------------------- */ +#define HWSET_MAX_SIZE 256 +#define EFUSE_MAX_SECTION 32 +#define EFUSE_REAL_CONTENT_LEN 512 + +/* ----------------------------------------------------- */ +/* 8192C EEPROM/EFUSE share register definition. */ +/* ----------------------------------------------------- */ +#define EEPROM_DEFAULT_TSSI 0x0 +#define EEPROM_DEFAULT_CRYSTALCAP 0x0 +#define EEPROM_DEFAULT_THERMALMETER 0x12 + +#define EEPROM_DEFAULT_TXPOWERLEVEL_2G 0x2C +#define EEPROM_DEFAULT_TXPOWERLEVEL_5G 0x22 + +#define EEPROM_DEFAULT_HT40_2SDIFF 0x0 +/* HT20<->40 default Tx Power Index Difference */ +#define EEPROM_DEFAULT_HT20_DIFF 2 +/* OFDM Tx Power index diff */ +#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x4 +#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET 0 +#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET 0 + +#define EEPROM_CHANNEL_PLAN_FCC 0x0 +#define EEPROM_CHANNEL_PLAN_IC 0x1 +#define EEPROM_CHANNEL_PLAN_ETSI 0x2 +#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 +#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 +#define EEPROM_CHANNEL_PLAN_MKK 0x5 +#define EEPROM_CHANNEL_PLAN_MKK1 0x6 +#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 +#define EEPROM_CHANNEL_PLAN_TELEC 0x8 +#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 +#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA +#define EEPROM_CHANNEL_PLAN_NCC 0xB +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_TOSHIBA 0x4 +#define EEPROM_CID_CCX 0x10 +#define EEPROM_CID_QMI 0x0D +#define EEPROM_CID_WHQL 0xFE + + +#define RTL8192_EEPROM_ID 0x8129 +#define EEPROM_WAPI_SUPPORT 0x78 + + +#define RTL8190_EEPROM_ID 0x8129 /* 0-1 */ +#define EEPROM_HPON 0x02 /* LDO settings.2-5 */ +#define EEPROM_CLK 0x06 /* Clock settings.6-7 */ +#define EEPROM_MAC_FUNCTION 0x08 /* SE Test mode.8 */ + +#define EEPROM_VID 0x28 /* SE Vendor ID.A-B */ +#define EEPROM_DID 0x2A /* SE Device ID. C-D */ +#define EEPROM_SVID 0x2C /* SE Vendor ID.E-F */ +#define EEPROM_SMID 0x2E /* SE PCI Subsystem ID. 10-11 */ + +#define EEPROM_MAC_ADDR 0x16 /* SEMAC Address. 12-17 */ +#define EEPROM_MAC_ADDR_MAC0_92D 0x55 +#define EEPROM_MAC_ADDR_MAC1_92D 0x5B + +/* 2.4G band Tx power index setting */ +#define EEPROM_CCK_TX_PWR_INX_2G 0x61 +#define EEPROM_HT40_1S_TX_PWR_INX_2G 0x67 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_2G 0x6D +#define EEPROM_HT20_TX_PWR_INX_DIFF_2G 0x70 +#define EEPROM_OFDM_TX_PWR_INX_DIFF_2G 0x73 +#define EEPROM_HT40_MAX_PWR_OFFSET_2G 0x76 +#define EEPROM_HT20_MAX_PWR_OFFSET_2G 0x79 + +/*5GL channel 32-64 */ +#define EEPROM_HT40_1S_TX_PWR_INX_5GL 0x7C +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GL 0x82 +#define EEPROM_HT20_TX_PWR_INX_DIFF_5GL 0x85 +#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GL 0x88 +#define EEPROM_HT40_MAX_PWR_OFFSET_5GL 0x8B +#define EEPROM_HT20_MAX_PWR_OFFSET_5GL 0x8E + +/* 5GM channel 100-140 */ +#define EEPROM_HT40_1S_TX_PWR_INX_5GM 0x91 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GM 0x97 +#define EEPROM_HT20_TX_PWR_INX_DIFF_5GM 0x9A +#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GM 0x9D +#define EEPROM_HT40_MAX_PWR_OFFSET_5GM 0xA0 +#define EEPROM_HT20_MAX_PWR_OFFSET_5GM 0xA3 + +/* 5GH channel 149-165 */ +#define EEPROM_HT40_1S_TX_PWR_INX_5GH 0xA6 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF_5GH 0xAC +#define EEPROM_HT20_TX_PWR_INX_DIFF_5GH 0xAF +#define EEPROM_OFDM_TX_PWR_INX_DIFF_5GH 0xB2 +#define EEPROM_HT40_MAX_PWR_OFFSET_5GH 0xB5 +#define EEPROM_HT20_MAX_PWR_OFFSET_5GH 0xB8 + +/* Map of supported channels. */ +#define EEPROM_CHANNEL_PLAN 0xBB +#define EEPROM_IQK_DELTA 0xBC +#define EEPROM_LCK_DELTA 0xBC +#define EEPROM_XTAL_K 0xBD /* [7:5] */ +#define EEPROM_TSSI_A_5G 0xBE +#define EEPROM_TSSI_B_5G 0xBF +#define EEPROM_TSSI_AB_5G 0xC0 +#define EEPROM_THERMAL_METER 0xC3 /* [4:0] */ +#define EEPROM_RF_OPT1 0xC4 +#define EEPROM_RF_OPT2 0xC5 +#define EEPROM_RF_OPT3 0xC6 +#define EEPROM_RF_OPT4 0xC7 +#define EEPROM_RF_OPT5 0xC8 +#define EEPROM_RF_OPT6 0xC9 +#define EEPROM_VERSION 0xCA +#define EEPROM_CUSTOMER_ID 0xCB +#define EEPROM_RF_OPT7 0xCC + +#define EEPROM_DEF_PART_NO 0x3FD /* Byte */ +#define EEPROME_CHIP_VERSION_L 0x3FF +#define EEPROME_CHIP_VERSION_H 0x3FE + +/* + * Current IOREG MAP + * 0x0000h ~ 0x00FFh System Configuration (256 Bytes) + * 0x0100h ~ 0x01FFh MACTOP General Configuration (256 Bytes) + * 0x0200h ~ 0x027Fh TXDMA Configuration (128 Bytes) + * 0x0280h ~ 0x02FFh RXDMA Configuration (128 Bytes) + * 0x0300h ~ 0x03FFh PCIE EMAC Reserved Region (256 Bytes) + * 0x0400h ~ 0x04FFh Protocol Configuration (256 Bytes) + * 0x0500h ~ 0x05FFh EDCA Configuration (256 Bytes) + * 0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes) + * 0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes) + */ + +/* ----------------------------------------------------- */ +/* 8192C (RCR) (Offset 0x608, 32 bits) */ +/* ----------------------------------------------------- */ +#define RCR_APPFCS BIT(31) +#define RCR_APP_MIC BIT(30) +#define RCR_APP_ICV BIT(29) +#define RCR_APP_PHYST_RXFF BIT(28) +#define RCR_APP_BA_SSN BIT(27) +#define RCR_ENMBID BIT(24) +#define RCR_LSIGEN BIT(23) +#define RCR_MFBEN BIT(22) +#define RCR_HTC_LOC_CTRL BIT(14) +#define RCR_AMF BIT(13) +#define RCR_ACF BIT(12) +#define RCR_ADF BIT(11) +#define RCR_AICV BIT(9) +#define RCR_ACRC32 BIT(8) +#define RCR_CBSSID_BCN BIT(7) +#define RCR_CBSSID_DATA BIT(6) +#define RCR_APWRMGT BIT(5) +#define RCR_ADD3 BIT(4) +#define RCR_AB BIT(3) +#define RCR_AM BIT(2) +#define RCR_APM BIT(1) +#define RCR_AAP BIT(0) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + +/* ----------------------------------------------------- */ +/* 8192C Regsiter Bit and Content definition */ +/* ----------------------------------------------------- */ +/* ----------------------------------------------------- */ +/* 0x0000h ~ 0x00FFh System Configuration */ +/* ----------------------------------------------------- */ + +/* SPS0_CTRL */ +#define SW18_FPWM BIT(3) + + +/* SYS_ISO_CTRL */ +#define ISO_MD2PP BIT(0) +#define ISO_UA2USB BIT(1) +#define ISO_UD2CORE BIT(2) +#define ISO_PA2PCIE BIT(3) +#define ISO_PD2CORE BIT(4) +#define ISO_IP2MAC BIT(5) +#define ISO_DIOP BIT(6) +#define ISO_DIOE BIT(7) +#define ISO_EB2CORE BIT(8) +#define ISO_DIOR BIT(9) + +#define PWC_EV25V BIT(14) +#define PWC_EV12V BIT(15) + + +/* SYS_FUNC_EN */ +#define FEN_BBRSTB BIT(0) +#define FEN_BB_GLB_RSTn BIT(1) +#define FEN_USBA BIT(2) +#define FEN_UPLL BIT(3) +#define FEN_USBD BIT(4) +#define FEN_DIO_PCIE BIT(5) +#define FEN_PCIEA BIT(6) +#define FEN_PPLL BIT(7) +#define FEN_PCIED BIT(8) +#define FEN_DIOE BIT(9) +#define FEN_CPUEN BIT(10) +#define FEN_DCORE BIT(11) +#define FEN_ELDR BIT(12) +#define FEN_DIO_RF BIT(13) +#define FEN_HWPDN BIT(14) +#define FEN_MREGEN BIT(15) + +/* APS_FSMCO */ +#define PFM_LDALL BIT(0) +#define PFM_ALDN BIT(1) +#define PFM_LDKP BIT(2) +#define PFM_WOWL BIT(3) +#define EnPDN BIT(4) +#define PDN_PL BIT(5) +#define APFM_ONMAC BIT(8) +#define APFM_OFF BIT(9) +#define APFM_RSM BIT(10) +#define AFSM_HSUS BIT(11) +#define AFSM_PCIE BIT(12) +#define APDM_MAC BIT(13) +#define APDM_HOST BIT(14) +#define APDM_HPDN BIT(15) +#define RDY_MACON BIT(16) +#define SUS_HOST BIT(17) +#define ROP_ALD BIT(20) +#define ROP_PWR BIT(21) +#define ROP_SPS BIT(22) +#define SOP_MRST BIT(25) +#define SOP_FUSE BIT(26) +#define SOP_ABG BIT(27) +#define SOP_AMB BIT(28) +#define SOP_RCK BIT(29) +#define SOP_A8M BIT(30) +#define XOP_BTCK BIT(31) + +/* SYS_CLKR */ +#define ANAD16V_EN BIT(0) +#define ANA8M BIT(1) +#define MACSLP BIT(4) +#define LOADER_CLK_EN BIT(5) +#define _80M_SSC_DIS BIT(7) +#define _80M_SSC_EN_HO BIT(8) +#define PHY_SSC_RSTB BIT(9) +#define SEC_CLK_EN BIT(10) +#define MAC_CLK_EN BIT(11) +#define SYS_CLK_EN BIT(12) +#define RING_CLK_EN BIT(13) + + +/* 9346CR */ +#define BOOT_FROM_EEPROM BIT(4) +#define EEPROM_EN BIT(5) + +/* AFE_MISC */ +#define AFE_BGEN BIT(0) +#define AFE_MBEN BIT(1) +#define MAC_ID_EN BIT(7) + +/* RSV_CTRL */ +#define WLOCK_ALL BIT(0) +#define WLOCK_00 BIT(1) +#define WLOCK_04 BIT(2) +#define WLOCK_08 BIT(3) +#define WLOCK_40 BIT(4) +#define R_DIS_PRST_0 BIT(5) +#define R_DIS_PRST_1 BIT(6) +#define LOCK_ALL_EN BIT(7) + +/* RF_CTRL */ +#define RF_EN BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + + + +/* LDOA15_CTRL */ +#define LDA15_EN BIT(0) +#define LDA15_STBY BIT(1) +#define LDA15_OBUF BIT(2) +#define LDA15_REG_VOS BIT(3) +#define _LDA15_VOADJ(x) (((x) & 0x7) << 4) + + + +/* LDOV12D_CTRL */ +#define LDV12_EN BIT(0) +#define LDV12_SDBY BIT(1) +#define LPLDO_HSM BIT(2) +#define LPLDO_LSM_DIS BIT(3) +#define _LDV12_VADJ(x) (((x) & 0xF) << 4) + + +/* AFE_XTAL_CTRL */ +#define XTAL_EN BIT(0) +#define XTAL_BSEL BIT(1) +#define _XTAL_BOSC(x) (((x) & 0x3) << 2) +#define _XTAL_CADJ(x) (((x) & 0xF) << 4) +#define XTAL_GATE_USB BIT(8) +#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9) +#define XTAL_GATE_AFE BIT(11) +#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12) +#define XTAL_RF_GATE BIT(14) +#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15) +#define XTAL_GATE_DIG BIT(17) +#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18) +#define XTAL_BT_GATE BIT(20) +#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21) +#define _XTAL_GPIO(x) (((x) & 0x7) << 23) + + +#define CKDLY_AFE BIT(26) +#define CKDLY_USB BIT(27) +#define CKDLY_DIG BIT(28) +#define CKDLY_BT BIT(29) + + +/* AFE_PLL_CTRL */ +#define APLL_EN BIT(0) +#define APLL_320_EN BIT(1) +#define APLL_FREF_SEL BIT(2) +#define APLL_EDGE_SEL BIT(3) +#define APLL_WDOGB BIT(4) +#define APLL_LPFEN BIT(5) + +#define APLL_REF_CLK_13MHZ 0x1 +#define APLL_REF_CLK_19_2MHZ 0x2 +#define APLL_REF_CLK_20MHZ 0x3 +#define APLL_REF_CLK_25MHZ 0x4 +#define APLL_REF_CLK_26MHZ 0x5 +#define APLL_REF_CLK_38_4MHZ 0x6 +#define APLL_REF_CLK_40MHZ 0x7 + +#define APLL_320EN BIT(14) +#define APLL_80EN BIT(15) +#define APLL_1MEN BIT(24) + + +/* EFUSE_CTRL */ +#define ALD_EN BIT(18) +#define EF_PD BIT(19) +#define EF_FLAG BIT(31) + +/* EFUSE_TEST */ +#define EF_TRPT BIT(7) +#define LDOE25_EN BIT(31) + +/* MCUFWDL */ +#define MCUFWDL_EN BIT(0) +#define MCUFWDL_RDY BIT(1) +#define FWDL_ChkSum_rpt BIT(2) +#define MACINI_RDY BIT(3) +#define BBINI_RDY BIT(4) +#define RFINI_RDY BIT(5) +#define WINTINI_RDY BIT(6) +#define MAC1_WINTINI_RDY BIT(11) +#define CPRST BIT(23) + +/* REG_SYS_CFG */ +#define XCLK_VLD BIT(0) +#define ACLK_VLD BIT(1) +#define UCLK_VLD BIT(2) +#define PCLK_VLD BIT(3) +#define PCIRSTB BIT(4) +#define V15_VLD BIT(5) +#define TRP_B15V_EN BIT(7) +#define SIC_IDLE BIT(8) +#define BD_MAC2 BIT(9) +#define BD_MAC1 BIT(10) +#define IC_MACPHY_MODE BIT(11) +#define PAD_HWPD_IDN BIT(22) +#define TRP_VAUX_EN BIT(23) +#define TRP_BT_EN BIT(24) +#define BD_PKG_SEL BIT(25) +#define BD_HCI_SEL BIT(26) +#define TYPE_ID BIT(27) + +/* LLT_INIT */ +#define _LLT_NO_ACTIVE 0x0 +#define _LLT_WRITE_ACCESS 0x1 +#define _LLT_READ_ACCESS 0x2 + +#define _LLT_INIT_DATA(x) ((x) & 0xFF) +#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) +#define _LLT_OP(x) (((x) & 0x3) << 30) +#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) + + +/* ----------------------------------------------------- */ +/* 0x0400h ~ 0x047Fh Protocol Configuration */ +/* ----------------------------------------------------- */ +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + + +/* ----------------------------------------------------- */ +/* 0x0500h ~ 0x05FFh EDCA Configuration */ +/* ----------------------------------------------------- */ +/* EDCA setting */ +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +/* ACMHWCTRL */ +#define ACMHW_HWEN BIT(0) +#define ACMHW_BEQEN BIT(1) +#define ACMHW_VIQEN BIT(2) +#define ACMHW_VOQEN BIT(3) + +/* ----------------------------------------------------- */ +/* 0x0600h ~ 0x07FFh WMAC Configuration */ +/* ----------------------------------------------------- */ + +/* TCR */ +#define TSFRST BIT(0) +#define DIS_GCLK BIT(1) +#define PAD_SEL BIT(2) +#define PWR_ST BIT(6) +#define PWRBIT_OW_EN BIT(7) +#define ACRC BIT(8) +#define CFENDFORM BIT(9) +#define ICV BIT(10) + +/* SECCFG */ +#define SCR_TXUSEDK BIT(0) +#define SCR_RXUSEDK BIT(1) +#define SCR_TXENCENABLE BIT(2) +#define SCR_RXENCENABLE BIT(3) +#define SCR_SKBYA2 BIT(4) +#define SCR_NOSKMC BIT(5) +#define SCR_TXBCUSEDK BIT(6) +#define SCR_RXBCUSEDK BIT(7) + +/* General definitions */ +#define MAC_ADDR_LEN 6 +#define LAST_ENTRY_OF_TX_PKT_BUFFER 255 +#define LAST_ENTRY_OF_TX_PKT_BUFFER_DUAL_MAC 127 + +#define POLLING_LLT_THRESHOLD 20 +#define POLLING_READY_TIMEOUT_COUNT 1000 + +/* Min Spacing related settings. */ +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + + +/* BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF */ +/* 1. PMAC duplicate register due to connection: */ +/* RF_Mode, TRxRN, NumOf L-STF */ +/* 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */ +/* 3. RF register 0x00-2E */ +/* 4. Bit Mask for BB/RF register */ +/* 5. Other defintion for BB/RF R/W */ + +/* 3. Page8(0x800) */ +#define RFPGA0_RFMOD 0x800 + +#define RFPGA0_TXINFO 0x804 +#define RFPGA0_PSDFUNCTION 0x808 + +#define RFPGA0_TXGAINSTAGE 0x80c + +#define RFPGA0_RFTIMING1 0x810 +#define RFPGA0_RFTIMING2 0x814 + +#define RFPGA0_XA_HSSIPARAMETER1 0x820 +#define RFPGA0_XA_HSSIPARAMETER2 0x824 +#define RFPGA0_XB_HSSIPARAMETER1 0x828 +#define RFPGA0_XB_HSSIPARAMETER2 0x82c + +#define RFPGA0_XA_LSSIPARAMETER 0x840 +#define RFPGA0_XB_LSSIPARAMETER 0x844 + +#define RFPGA0_RFWAkEUPPARAMETER 0x850 +#define RFPGA0_RFSLEEPUPPARAMETER 0x854 + +#define RFPGA0_XAB_SWITCHCONTROL 0x858 +#define RFPGA0_XCD_SWITCHCONTROL 0x85c + +#define RFPGA0_XA_RFINTERFACEOE 0x860 +#define RFPGA0_XB_RFINTERFACEOE 0x864 + +#define RFPGA0_XAB_RFINTERFACESW 0x870 +#define RFPGA0_XCD_RFINTERFACESW 0x874 + +#define RFPGA0_XAB_RFPARAMETER 0x878 +#define RFPGA0_XCD_RFPARAMETER 0x87c + +#define RFPGA0_ANALOGPARAMETER1 0x880 +#define RFPGA0_ANALOGPARAMETER2 0x884 +#define RFPGA0_ANALOGPARAMETER3 0x888 +#define RFPGA0_ADDALLOCKEN 0x888 +#define RFPGA0_ANALOGPARAMETER4 0x88c + +#define RFPGA0_XA_LSSIREADBACK 0x8a0 +#define RFPGA0_XB_LSSIREADBACK 0x8a4 +#define RFPGA0_XC_LSSIREADBACK 0x8a8 +#define RFPGA0_XD_LSSIREADBACK 0x8ac + +#define RFPGA0_PSDREPORT 0x8b4 +#define TRANSCEIVERA_HSPI_READBACK 0x8b8 +#define TRANSCEIVERB_HSPI_READBACK 0x8bc +#define RFPGA0_XAB_RFINTERFACERB 0x8e0 +#define RFPGA0_XCD_RFINTERFACERB 0x8e4 + +/* 4. Page9(0x900) */ +#define RFPGA1_RFMOD 0x900 + +#define RFPGA1_TXBLOCK 0x904 +#define RFPGA1_DEBUGSELECT 0x908 +#define RFPGA1_TXINFO 0x90c + +/* 5. PageA(0xA00) */ +#define RCCK0_SYSTEM 0xa00 + +#define RCCK0_AFESSTTING 0xa04 +#define RCCK0_CCA 0xa08 + +#define RCCK0_RXAGC1 0xa0c +#define RCCK0_RXAGC2 0xa10 + +#define RCCK0_RXHP 0xa14 + +#define RCCK0_DSPPARAMETER1 0xa18 +#define RCCK0_DSPPARAMETER2 0xa1c + +#define RCCK0_TXFILTER1 0xa20 +#define RCCK0_TXFILTER2 0xa24 +#define RCCK0_DEBUGPORT 0xa28 +#define RCCK0_FALSEALARMREPORT 0xa2c +#define RCCK0_TRSSIREPORT 0xa50 +#define RCCK0_RXREPORT 0xa54 +#define RCCK0_FACOUNTERLOWER 0xa5c +#define RCCK0_FACOUNTERUPPER 0xa58 + +/* 6. PageC(0xC00) */ +#define ROFDM0_LSTF 0xc00 + +#define ROFDM0_TRXPATHENABLE 0xc04 +#define ROFDM0_TRMUXPAR 0xc08 +#define ROFDM0_TRSWISOLATION 0xc0c + +#define ROFDM0_XARXAFE 0xc10 +#define ROFDM0_XARXIQIMBALANCE 0xc14 +#define ROFDM0_XBRXAFE 0xc18 +#define ROFDM0_XBRXIQIMBALANCE 0xc1c +#define ROFDM0_XCRXAFE 0xc20 +#define ROFDM0_XCRXIQIMBALANCE 0xc24 +#define ROFDM0_XDRXAFE 0xc28 +#define ROFDM0_XDRXIQIMBALANCE 0xc2c + +#define ROFDM0_RXDETECTOR1 0xc30 +#define ROFDM0_RXDETECTOR2 0xc34 +#define ROFDM0_RXDETECTOR3 0xc38 +#define ROFDM0_RXDETECTOR4 0xc3c + +#define ROFDM0_RXDSP 0xc40 +#define ROFDM0_CFOANDDAGC 0xc44 +#define ROFDM0_CCADROPTHRESHOLD 0xc48 +#define ROFDM0_ECCATHRESHOLD 0xc4c + +#define ROFDM0_XAAGCCORE1 0xc50 +#define ROFDM0_XAAGCCORE2 0xc54 +#define ROFDM0_XBAGCCORE1 0xc58 +#define ROFDM0_XBAGCCORE2 0xc5c +#define ROFDM0_XCAGCCORE1 0xc60 +#define ROFDM0_XCAGCCORE2 0xc64 +#define ROFDM0_XDAGCCORE1 0xc68 +#define ROFDM0_XDAGCCORE2 0xc6c + +#define ROFDM0_AGCPARAMETER1 0xc70 +#define ROFDM0_AGCPARAMETER2 0xc74 +#define ROFDM0_AGCRSSITABLE 0xc78 +#define ROFDM0_HTSTFAGC 0xc7c + +#define ROFDM0_XATxIQIMBALANCE 0xc80 +#define ROFDM0_XATxAFE 0xc84 +#define ROFDM0_XBTxIQIMBALANCE 0xc88 +#define ROFDM0_XBTxAFE 0xc8c +#define ROFDM0_XCTxIQIMBALANCE 0xc90 +#define ROFDM0_XCTxAFE 0xc94 +#define ROFDM0_XDTxIQIMBALANCE 0xc98 +#define ROFDM0_XDTxAFE 0xc9c + +#define ROFDM0_RXHPPARAMETER 0xce0 +#define ROFDM0_TXPSEUDONOISEWGT 0xce4 +#define ROFDM0_FRAMESYNC 0xcf0 +#define ROFDM0_DFSREPORT 0xcf4 +#define ROFDM0_TXCOEFF1 0xca4 +#define ROFDM0_TXCOEFF2 0xca8 +#define ROFDM0_TXCOEFF3 0xcac +#define ROFDM0_TXCOEFF4 0xcb0 +#define ROFDM0_TXCOEFF5 0xcb4 +#define ROFDM0_TXCOEFF6 0xcb8 + +/* 7. PageD(0xD00) */ +#define ROFDM1_LSTF 0xd00 +#define ROFDM1_TRXPATHENABLE 0xd04 + +#define ROFDM1_CFO 0xd08 +#define ROFDM1_CSI1 0xd10 +#define ROFDM1_SBD 0xd14 +#define ROFDM1_CSI2 0xd18 +#define ROFDM1_CFOTRACKING 0xd2c +#define ROFDM1_TRXMESAURE1 0xd34 +#define ROFDM1_INTFDET 0xd3c +#define ROFDM1_PSEUDONOISESTATEAB 0xd50 +#define ROFDM1_PSEUDONOISESTATECD 0xd54 +#define ROFDM1_RXPSEUDONOISEWGT 0xd58 + +#define ROFDM_PHYCOUNTER1 0xda0 +#define ROFDM_PHYCOUNTER2 0xda4 +#define ROFDM_PHYCOUNTER3 0xda8 + +#define ROFDM_SHORTCFOAB 0xdac +#define ROFDM_SHORTCFOCD 0xdb0 +#define ROFDM_LONGCFOAB 0xdb4 +#define ROFDM_LONGCFOCD 0xdb8 +#define ROFDM_TAILCFOAB 0xdbc +#define ROFDM_TAILCFOCD 0xdc0 +#define ROFDM_PWMEASURE1 0xdc4 +#define ROFDM_PWMEASURE2 0xdc8 +#define ROFDM_BWREPORT 0xdcc +#define ROFDM_AGCREPORT 0xdd0 +#define ROFDM_RXSNR 0xdd4 +#define ROFDM_RXEVMCSI 0xdd8 +#define ROFDM_SIGReport 0xddc + +/* 8. PageE(0xE00) */ +#define RTXAGC_A_RATE18_06 0xe00 +#define RTXAGC_A_RATE54_24 0xe04 +#define RTXAGC_A_CCK1_MCS32 0xe08 +#define RTXAGC_A_MCS03_MCS00 0xe10 +#define RTXAGC_A_MCS07_MCS04 0xe14 +#define RTXAGC_A_MCS11_MCS08 0xe18 +#define RTXAGC_A_MCS15_MCS12 0xe1c + +#define RTXAGC_B_RATE18_06 0x830 +#define RTXAGC_B_RATE54_24 0x834 +#define RTXAGC_B_CCK1_55_MCS32 0x838 +#define RTXAGC_B_MCS03_MCS00 0x83c +#define RTXAGC_B_MCS07_MCS04 0x848 +#define RTXAGC_B_MCS11_MCS08 0x84c +#define RTXAGC_B_MCS15_MCS12 0x868 +#define RTXAGC_B_CCK11_A_CCK2_11 0x86c + +/* RL6052 Register definition */ +#define RF_AC 0x00 + +#define RF_IQADJ_G1 0x01 +#define RF_IQADJ_G2 0x02 +#define RF_POW_TRSW 0x05 + +#define RF_GAIN_RX 0x06 +#define RF_GAIN_TX 0x07 + +#define RF_TXM_IDAC 0x08 +#define RF_BS_IQGEN 0x0F + +#define RF_MODE1 0x10 +#define RF_MODE2 0x11 + +#define RF_RX_AGC_HP 0x12 +#define RF_TX_AGC 0x13 +#define RF_BIAS 0x14 +#define RF_IPA 0x15 +#define RF_POW_ABILITY 0x17 +#define RF_MODE_AG 0x18 +#define rRfChannel 0x18 +#define RF_CHNLBW 0x18 +#define RF_TOP 0x19 + +#define RF_RX_G1 0x1A +#define RF_RX_G2 0x1B + +#define RF_RX_BB2 0x1C +#define RF_RX_BB1 0x1D + +#define RF_RCK1 0x1E +#define RF_RCK2 0x1F + +#define RF_TX_G1 0x20 +#define RF_TX_G2 0x21 +#define RF_TX_G3 0x22 + +#define RF_TX_BB1 0x23 + +#define RF_T_METER 0x42 + +#define RF_SYN_G1 0x25 +#define RF_SYN_G2 0x26 +#define RF_SYN_G3 0x27 +#define RF_SYN_G4 0x28 +#define RF_SYN_G5 0x29 +#define RF_SYN_G6 0x2A +#define RF_SYN_G7 0x2B +#define RF_SYN_G8 0x2C + +#define RF_RCK_OS 0x30 + +#define RF_TXPA_G1 0x31 +#define RF_TXPA_G2 0x32 +#define RF_TXPA_G3 0x33 + +/* Bit Mask */ + +/* 2. Page8(0x800) */ +#define BRFMOD 0x1 +#define BCCKTXSC 0x30 +#define BCCKEN 0x1000000 +#define BOFDMEN 0x2000000 + +#define B3WIREDATALENGTH 0x800 +#define B3WIREADDRESSLENGTH 0x400 + +#define BRFSI_RFENV 0x10 + +#define BLSSIREADADDRESS 0x7f800000 +#define BLSSIREADEDGE 0x80000000 +#define BLSSIREADBACKDATA 0xfffff +/* 4. PageA(0xA00) */ +#define BCCKSIDEBAND 0x10 + +/* Other Definition */ +#define BBYTE0 0x1 +#define BBYTE1 0x2 +#define BBYTE2 0x4 +#define BBYTE3 0x8 +#define BWORD0 0x3 +#define BWORD1 0xc +#define BDWORD 0xf + +#define BMASKBYTE0 0xff +#define BMASKBYTE1 0xff00 +#define BMASKBYTE2 0xff0000 +#define BMASKBYTE3 0xff000000 +#define BMASKHWORD 0xffff0000 +#define BMASKLWORD 0x0000ffff +#define BMASKDWORD 0xffffffff +#define BMASK12BITS 0xfff +#define BMASKH4BITS 0xf0000000 +#define BMASKOFDM_D 0xffc00000 +#define BMASKCCK 0x3f3f3f3f + +#define BRFREGOFFSETMASK 0xfffff + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c new file mode 100644 index 000000000000..db27cebaac2c --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c @@ -0,0 +1,628 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "hw.h" + +void rtl92d_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + + switch (bandwidth) { + case HT_CHANNEL_WIDTH_20: + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = ((rtlphy->rfreg_chnlval + [rfpath] & 0xfffff3ff) | 0x0400); + rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(10) | + BIT(11), 0x01); + + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, + ("20M RF 0x18 = 0x%x\n", + rtlphy->rfreg_chnlval[rfpath])); + } + + break; + case HT_CHANNEL_WIDTH_20_40: + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = + ((rtlphy->rfreg_chnlval[rfpath] & 0xfffff3ff)); + rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(10) | BIT(11), + 0x00); + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, + ("40M RF 0x18 = 0x%x\n", + rtlphy->rfreg_chnlval[rfpath])); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", bandwidth)); + break; + } +} + +void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 tx_agc[2] = {0, 0}, tmpval; + bool turbo_scanoff = false; + u8 idx1, idx2; + u8 *ptr; + + if (rtlefuse->eeprom_regulatory != 0) + turbo_scanoff = true; + if (mac->act_scanning) { + tx_agc[RF90_PATH_A] = 0x3f3f3f3f; + tx_agc[RF90_PATH_B] = 0x3f3f3f3f; + if (turbo_scanoff) { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + } + } else { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + if (rtlefuse->eeprom_regulatory == 0) { + tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][6]) + + (rtlphy->mcs_txpwrlevel_origoffset[0][7] << 8); + tx_agc[RF90_PATH_A] += tmpval; + tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) + + (rtlphy->mcs_txpwrlevel_origoffset[0][15] << 24); + tx_agc[RF90_PATH_B] += tmpval; + } + } + + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + ptr = (u8 *) (&(tx_agc[idx1])); + for (idx2 = 0; idx2 < 4; idx2++) { + if (*ptr > RF6052_MAX_TX_PWR) + *ptr = RF6052_MAX_TX_PWR; + ptr++; + } + } + + tmpval = tx_agc[RF90_PATH_A] & 0xff; + rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, BMASKBYTE1, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_A_CCK1_MCS32)); + tmpval = tx_agc[RF90_PATH_A] >> 8; + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_B_CCK11_A_CCK2_11)); + tmpval = tx_agc[RF90_PATH_B] >> 24; + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, BMASKBYTE0, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_B_CCK11_A_CCK2_11)); + tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff; + rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_B_CCK1_55_MCS32)); +} + +static void _rtl92d_phy_get_power_base(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel, + u32 *ofdmbase, u32 *mcsbase) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 powerbase0, powerbase1; + u8 legacy_pwrdiff, ht20_pwrdiff; + u8 i, powerlevel[2]; + + for (i = 0; i < 2; i++) { + powerlevel[i] = ppowerlevel[i]; + legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1]; + powerbase0 = powerlevel[i] + legacy_pwrdiff; + powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) | + (powerbase0 << 8) | powerbase0; + *(ofdmbase + i) = powerbase0; + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + (" [OFDM power base index rf(%c) = 0x%x]\n", + ((i == 0) ? 'A' : 'B'), *(ofdmbase + i))); + } + + for (i = 0; i < 2; i++) { + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { + ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1]; + powerlevel[i] += ht20_pwrdiff; + } + powerbase1 = powerlevel[i]; + powerbase1 = (powerbase1 << 24) | (powerbase1 << 16) | + (powerbase1 << 8) | powerbase1; + *(mcsbase + i) = powerbase1; + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + (" [MCS power base index rf(%c) = 0x%x]\n", + ((i == 0) ? 'A' : 'B'), *(mcsbase + i))); + } +} + +static u8 _rtl92d_phy_get_chnlgroup_bypg(u8 chnlindex) +{ + u8 group; + u8 channel_info[59] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, + 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 136, 138, 140, 149, 151, 153, 155, 157, 159, + 161, 163, 165 + }; + + if (channel_info[chnlindex] <= 3) /* Chanel 1-3 */ + group = 0; + else if (channel_info[chnlindex] <= 9) /* Channel 4-9 */ + group = 1; + else if (channel_info[chnlindex] <= 14) /* Channel 10-14 */ + group = 2; + else if (channel_info[chnlindex] <= 64) + group = 6; + else if (channel_info[chnlindex] <= 140) + group = 7; + else + group = 8; + return group; +} + +static void _rtl92d_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, + u8 channel, u8 index, + u32 *powerbase0, + u32 *powerbase1, + u32 *p_outwriteval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 i, chnlgroup = 0, pwr_diff_limit[4]; + u32 writeval = 0, customer_limit, rf; + + for (rf = 0; rf < 2; rf++) { + switch (rtlefuse->eeprom_regulatory) { + case 0: + chnlgroup = 0; + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + + (rf ? 8 : 0)] + ((index < 2) ? + powerbase0[rf] : + powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, ("RTK better " + "performance, writeval(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeval)); + break; + case 1: + if (rtlphy->pwrgroup_cnt == 1) + chnlgroup = 0; + if (rtlphy->pwrgroup_cnt >= MAX_PG_GROUP) { + chnlgroup = _rtl92d_phy_get_chnlgroup_bypg( + channel - 1); + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20) + chnlgroup++; + else + chnlgroup += 4; + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + + (rf ? 8 : 0)] + ((index < 2) ? + powerbase0[rf] : + powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("Realtek regulatory, " + "20MHz, writeval(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), + writeval)); + } + break; + case 2: + writeval = ((index < 2) ? powerbase0[rf] : + powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, ("Better regulatory, " + "writeval(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeval)); + break; + case 3: + chnlgroup = 0; + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("customer's limit, 40MHz rf(%c) = " + "0x%x\n", ((rf == 0) ? 'A' : 'B'), + rtlefuse->pwrgroup_ht40[rf] + [channel - 1])); + } else { + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("customer's limit, 20MHz rf(%c) = " + "0x%x\n", ((rf == 0) ? 'A' : 'B'), + rtlefuse->pwrgroup_ht20[rf] + [channel - 1])); + } + for (i = 0; i < 4; i++) { + pwr_diff_limit[i] = + (u8)((rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + (rf ? 8 : 0)] & + (0x7f << (i * 8))) >> (i * 8)); + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20_40) { + if (pwr_diff_limit[i] > + rtlefuse->pwrgroup_ht40[rf] + [channel - 1]) + pwr_diff_limit[i] = + rtlefuse->pwrgroup_ht40 + [rf][channel - 1]; + } else { + if (pwr_diff_limit[i] > + rtlefuse->pwrgroup_ht20[rf][ + channel - 1]) + pwr_diff_limit[i] = + rtlefuse->pwrgroup_ht20[rf] + [channel - 1]; + } + } + customer_limit = (pwr_diff_limit[3] << 24) | + (pwr_diff_limit[2] << 16) | + (pwr_diff_limit[1] << 8) | + (pwr_diff_limit[0]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("Customer's limit rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), customer_limit)); + writeval = customer_limit + ((index < 2) ? + powerbase0[rf] : powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("Customer, writeval rf(%c)= 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeval)); + break; + default: + chnlgroup = 0; + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index + + (rf ? 8 : 0)] + ((index < 2) ? + powerbase0[rf] : powerbase1[rf]); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("RTK better performance, writeval " + "rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeval)); + break; + } + *(p_outwriteval + rf) = writeval; + } +} + +static void _rtl92d_write_ofdm_power_reg(struct ieee80211_hw *hw, + u8 index, u32 *pvalue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + static u16 regoffset_a[6] = { + RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24, + RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, + RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 + }; + static u16 regoffset_b[6] = { + RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24, + RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, + RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 + }; + u8 i, rf, pwr_val[4]; + u32 writeval; + u16 regoffset; + + for (rf = 0; rf < 2; rf++) { + writeval = pvalue[rf]; + for (i = 0; i < 4; i++) { + pwr_val[i] = (u8) ((writeval & (0x7f << + (i * 8))) >> (i * 8)); + if (pwr_val[i] > RF6052_MAX_TX_PWR) + pwr_val[i] = RF6052_MAX_TX_PWR; + } + writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) | + (pwr_val[1] << 8) | pwr_val[0]; + if (rf == 0) + regoffset = regoffset_a[index]; + else + regoffset = regoffset_b[index]; + rtl_set_bbreg(hw, regoffset, BMASKDWORD, writeval); + RTPRINT(rtlpriv, FPHY, PHY_TXPWR, + ("Set 0x%x = %08x\n", regoffset, writeval)); + if (((get_rf_type(rtlphy) == RF_2T2R) && + (regoffset == RTXAGC_A_MCS15_MCS12 || + regoffset == RTXAGC_B_MCS15_MCS12)) || + ((get_rf_type(rtlphy) != RF_2T2R) && + (regoffset == RTXAGC_A_MCS07_MCS04 || + regoffset == RTXAGC_B_MCS07_MCS04))) { + writeval = pwr_val[3]; + if (regoffset == RTXAGC_A_MCS15_MCS12 || + regoffset == RTXAGC_A_MCS07_MCS04) + regoffset = 0xc90; + if (regoffset == RTXAGC_B_MCS15_MCS12 || + regoffset == RTXAGC_B_MCS07_MCS04) + regoffset = 0xc98; + for (i = 0; i < 3; i++) { + if (i != 2) + writeval = (writeval > 8) ? + (writeval - 8) : 0; + else + writeval = (writeval > 6) ? + (writeval - 6) : 0; + rtl_write_byte(rtlpriv, (u32) (regoffset + i), + (u8) writeval); + } + } + } +} + +void rtl92d_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel) +{ + u32 writeval[2], powerbase0[2], powerbase1[2]; + u8 index; + + _rtl92d_phy_get_power_base(hw, ppowerlevel, channel, + &powerbase0[0], &powerbase1[0]); + for (index = 0; index < 6; index++) { + _rtl92d_get_txpower_writeval_by_regulatory(hw, + channel, index, &powerbase0[0], + &powerbase1[0], &writeval[0]); + _rtl92d_write_ofdm_power_reg(hw, index, &writeval[0]); + } +} + +bool rtl92d_phy_enable_anotherphy(struct ieee80211_hw *hw, bool bmac0) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 u1btmp; + u8 direct = bmac0 ? BIT(3) | BIT(2) : BIT(3); + u8 mac_reg = bmac0 ? REG_MAC1 : REG_MAC0; + u8 mac_on_bit = bmac0 ? MAC1_ON : MAC0_ON; + bool bresult = true; /* true: need to enable BB/RF power */ + + rtlhal->during_mac0init_radiob = false; + rtlhal->during_mac1init_radioa = false; + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, ("===>\n")); + /* MAC0 Need PHY1 load radio_b.txt . Driver use DBI to write. */ + u1btmp = rtl_read_byte(rtlpriv, mac_reg); + if (!(u1btmp & mac_on_bit)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("enable BB & RF\n")); + /* Enable BB and RF power */ + rtl92de_write_dword_dbi(hw, REG_SYS_ISO_CTRL, + rtl92de_read_dword_dbi(hw, REG_SYS_ISO_CTRL, direct) | + BIT(29) | BIT(16) | BIT(17), direct); + } else { + /* We think if MAC1 is ON,then radio_a.txt + * and radio_b.txt has been load. */ + bresult = false; + } + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, ("<===\n")); + return bresult; + +} + +void rtl92d_phy_powerdown_anotherphy(struct ieee80211_hw *hw, bool bmac0) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u8 u1btmp; + u8 direct = bmac0 ? BIT(3) | BIT(2) : BIT(3); + u8 mac_reg = bmac0 ? REG_MAC1 : REG_MAC0; + u8 mac_on_bit = bmac0 ? MAC1_ON : MAC0_ON; + + rtlhal->during_mac0init_radiob = false; + rtlhal->during_mac1init_radioa = false; + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, ("====>\n")); + /* check MAC0 enable or not again now, if + * enabled, not power down radio A. */ + u1btmp = rtl_read_byte(rtlpriv, mac_reg); + if (!(u1btmp & mac_on_bit)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("power down\n")); + /* power down RF radio A according to YuNan's advice. */ + rtl92de_write_dword_dbi(hw, RFPGA0_XA_LSSIPARAMETER, + 0x00000000, direct); + } + RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, ("<====\n")); +} + +bool rtl92d_phy_rf6052_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool rtstatus = true; + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 u4_regvalue = 0; + u8 rfpath; + struct bb_reg_def *pphyreg; + bool mac1_initradioa_first = false, mac0_initradiob_first = false; + bool need_pwrdown_radioa = false, need_pwrdown_radiob = false; + bool true_bpath = false; + + if (rtlphy->rf_type == RF_1T1R) + rtlphy->num_total_rfpath = 1; + else + rtlphy->num_total_rfpath = 2; + + /* Single phy mode: use radio_a radio_b config path_A path_B */ + /* seperately by MAC0, and MAC1 needn't configure RF; */ + /* Dual PHY mode:MAC0 use radio_a config 1st phy path_A, */ + /* MAC1 use radio_b config 2nd PHY path_A. */ + /* DMDP,MAC0 on G band,MAC1 on A band. */ + if (rtlhal->macphymode == DUALMAC_DUALPHY) { + if (rtlhal->current_bandtype == BAND_ON_2_4G && + rtlhal->interfaceindex == 0) { + /* MAC0 needs PHY1 load radio_b.txt. + * Driver use DBI to write. */ + if (rtl92d_phy_enable_anotherphy(hw, true)) { + rtlphy->num_total_rfpath = 2; + mac0_initradiob_first = true; + } else { + /* We think if MAC1 is ON,then radio_a.txt and + * radio_b.txt has been load. */ + return rtstatus; + } + } else if (rtlhal->current_bandtype == BAND_ON_5G && + rtlhal->interfaceindex == 1) { + /* MAC1 needs PHY0 load radio_a.txt. + * Driver use DBI to write. */ + if (rtl92d_phy_enable_anotherphy(hw, false)) { + rtlphy->num_total_rfpath = 2; + mac1_initradioa_first = true; + } else { + /* We think if MAC0 is ON,then radio_a.txt and + * radio_b.txt has been load. */ + return rtstatus; + } + } else if (rtlhal->interfaceindex == 1) { + /* MAC0 enabled, only init radia B. */ + true_bpath = true; + } + } + + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + /* Mac1 use PHY0 write */ + if (mac1_initradioa_first) { + if (rfpath == RF90_PATH_A) { + rtlhal->during_mac1init_radioa = true; + need_pwrdown_radioa = true; + } else if (rfpath == RF90_PATH_B) { + rtlhal->during_mac1init_radioa = false; + mac1_initradioa_first = false; + rfpath = RF90_PATH_A; + true_bpath = true; + rtlphy->num_total_rfpath = 1; + } + } else if (mac0_initradiob_first) { + /* Mac0 use PHY1 write */ + if (rfpath == RF90_PATH_A) + rtlhal->during_mac0init_radiob = false; + if (rfpath == RF90_PATH_B) { + rtlhal->during_mac0init_radiob = true; + mac0_initradiob_first = false; + need_pwrdown_radiob = true; + rfpath = RF90_PATH_A; + true_bpath = true; + rtlphy->num_total_rfpath = 1; + } + } + pphyreg = &rtlphy->phyreg_def[rfpath]; + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, + BRFSI_RFENV); + break; + case RF90_PATH_B: + case RF90_PATH_D: + u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, + BRFSI_RFENV << 16); + break; + } + rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1); + udelay(1); + rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); + udelay(1); + /* Set bit number of Address and Data for RF register */ + /* Set 1 to 4 bits for 8255 */ + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, + B3WIREADDRESSLENGTH, 0x0); + udelay(1); + /* Set 0 to 12 bits for 8255 */ + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0); + udelay(1); + switch (rfpath) { + case RF90_PATH_A: + if (true_bpath) + rtstatus = rtl92d_phy_config_rf_with_headerfile( + hw, radiob_txt, + (enum radio_path)rfpath); + else + rtstatus = rtl92d_phy_config_rf_with_headerfile( + hw, radioa_txt, + (enum radio_path)rfpath); + break; + case RF90_PATH_B: + rtstatus = + rtl92d_phy_config_rf_with_headerfile(hw, radiob_txt, + (enum radio_path) rfpath); + break; + case RF90_PATH_C: + break; + case RF90_PATH_D: + break; + } + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV, + u4_regvalue); + break; + case RF90_PATH_B: + case RF90_PATH_D: + rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV << 16, + u4_regvalue); + break; + } + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Radio[%d] Fail!!", rfpath)); + goto phy_rf_cfg_fail; + } + + } + + /* check MAC0 enable or not again, if enabled, + * not power down radio A. */ + /* check MAC1 enable or not again, if enabled, + * not power down radio B. */ + if (need_pwrdown_radioa) + rtl92d_phy_powerdown_anotherphy(hw, false); + else if (need_pwrdown_radiob) + rtl92d_phy_powerdown_anotherphy(hw, true); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("<---\n")); + return rtstatus; + +phy_rf_cfg_fail: + return rtstatus; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/rf.h b/drivers/net/wireless/rtlwifi/rtl8192de/rf.h new file mode 100644 index 000000000000..74b9cfc39a83 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/rf.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92D_RF_H__ +#define __RTL92D_RF_H__ + +extern void rtl92d_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +extern void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +extern void rtl92d_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); +extern bool rtl92d_phy_rf6052_config(struct ieee80211_hw *hw); +extern bool rtl92d_phy_enable_anotherphy(struct ieee80211_hw *hw, bool bmac0); +extern void rtl92d_phy_powerdown_anotherphy(struct ieee80211_hw *hw, + bool bmac0); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c new file mode 100644 index 000000000000..08837744f6f1 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -0,0 +1,423 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include <linux/vmalloc.h> + +#include "../wifi.h" +#include "../core.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "hw.h" +#include "sw.h" +#include "trx.h" +#include "led.h" + +static void rtl92d_init_aspm_vars(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + /*close ASPM for AMD defaultly */ + rtlpci->const_amdpci_aspm = 0; + + /* + * ASPM PS mode. + * 0 - Disable ASPM, + * 1 - Enable ASPM without Clock Req, + * 2 - Enable ASPM with Clock Req, + * 3 - Alwyas Enable ASPM with Clock Req, + * 4 - Always Enable ASPM without Clock Req. + * set defult to RTL8192CE:3 RTL8192E:2 + * */ + rtlpci->const_pci_aspm = 3; + + /*Setting for PCI-E device */ + rtlpci->const_devicepci_aspm_setting = 0x03; + + /*Setting for PCI-E bridge */ + rtlpci->const_hostpci_aspm_setting = 0x02; + + /* + * In Hw/Sw Radio Off situation. + * 0 - Default, + * 1 - From ASPM setting without low Mac Pwr, + * 2 - From ASPM setting with low Mac Pwr, + * 3 - Bus D3 + * set default to RTL8192CE:0 RTL8192SE:2 + */ + rtlpci->const_hwsw_rfoff_d3 = 0; + + /* + * This setting works for those device with + * backdoor ASPM setting such as EPHY setting. + * 0 - Not support ASPM, + * 1 - Support ASPM, + * 2 - According to chipset. + */ + rtlpci->const_support_pciaspm = 1; +} + +static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) +{ + int err; + u8 tid; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + const struct firmware *firmware; + static int header_print; + + rtlpriv->dm.dm_initialgain_enable = true; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.disable_framebursting = 0; + rtlpriv->dm.thermalvalue = 0; + rtlpriv->dm.useramask = 1; + + /* dual mac */ + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) + rtlpriv->phy.current_channel = 36; + else + rtlpriv->phy.current_channel = 1; + + if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { + rtlpriv->rtlhal.disable_amsdu_8k = true; + /* No long RX - reduce fragmentation */ + rtlpci->rxbuffersize = 4096; + } + + rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); + + rtlpci->receive_config = ( + RCR_APPFCS + | RCR_AMF + | RCR_ADF + | RCR_APP_MIC + | RCR_APP_ICV + | RCR_AICV + | RCR_ACRC32 + | RCR_AB + | RCR_AM + | RCR_APM + | RCR_APP_PHYST_RXFF + | RCR_HTC_LOC_CTRL + ); + + rtlpci->irq_mask[0] = (u32) ( + IMR_ROK + | IMR_VODOK + | IMR_VIDOK + | IMR_BEDOK + | IMR_BKDOK + | IMR_MGNTDOK + | IMR_HIGHDOK + | IMR_BDOK + | IMR_RDU + | IMR_RXFOVW + ); + + rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD); + + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl92d_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(0x8000); + if (!rtlpriv->rtlhal.pfirmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Can't alloc buffer for fw.\n")); + return 1; + } + + if (!header_print) { + printk(KERN_INFO "rtl8192de: Driver for Realtek RTL8192DE" + " WLAN interface"); + printk(KERN_INFO "rtl8192de: Loading firmware file %s\n", + rtlpriv->cfg->fw_name); + header_print++; + } + /* request fw */ + err = request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Failed to request firmware!\n")); + return 1; + } + if (firmware->size > 0x8000) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is too big!\n")); + release_firmware(firmware); + return 1; + } + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + release_firmware(firmware); + + /* for early mode */ + rtlpriv->rtlhal.earlymode_enable = true; + for (tid = 0; tid < 8; tid++) + skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]); + return 0; +} + +static void rtl92d_deinit_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tid; + + if (rtlpriv->rtlhal.pfirmware) { + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; + } + for (tid = 0; tid < 8; tid++) + skb_queue_purge(&rtlpriv->mac80211.skb_waitq[tid]); +} + +static struct rtl_hal_ops rtl8192de_hal_ops = { + .init_sw_vars = rtl92d_init_sw_vars, + .deinit_sw_vars = rtl92d_deinit_sw_vars, + .read_eeprom_info = rtl92de_read_eeprom_info, + .interrupt_recognized = rtl92de_interrupt_recognized, + .hw_init = rtl92de_hw_init, + .hw_disable = rtl92de_card_disable, + .hw_suspend = rtl92de_suspend, + .hw_resume = rtl92de_resume, + .enable_interrupt = rtl92de_enable_interrupt, + .disable_interrupt = rtl92de_disable_interrupt, + .set_network_type = rtl92de_set_network_type, + .set_chk_bssid = rtl92de_set_check_bssid, + .set_qos = rtl92de_set_qos, + .set_bcn_reg = rtl92de_set_beacon_related_registers, + .set_bcn_intv = rtl92de_set_beacon_interval, + .update_interrupt_mask = rtl92de_update_interrupt_mask, + .get_hw_reg = rtl92de_get_hw_reg, + .set_hw_reg = rtl92de_set_hw_reg, + .update_rate_tbl = rtl92de_update_hal_rate_tbl, + .fill_tx_desc = rtl92de_tx_fill_desc, + .fill_tx_cmddesc = rtl92de_tx_fill_cmddesc, + .query_rx_desc = rtl92de_rx_query_desc, + .set_channel_access = rtl92de_update_channel_access_setting, + .radio_onoff_checking = rtl92de_gpio_radio_on_off_checking, + .set_bw_mode = rtl92d_phy_set_bw_mode, + .switch_channel = rtl92d_phy_sw_chnl, + .dm_watchdog = rtl92d_dm_watchdog, + .scan_operation_backup = rtl92d_phy_scan_operation_backup, + .set_rf_power_state = rtl92d_phy_set_rf_power_state, + .led_control = rtl92de_led_control, + .set_desc = rtl92de_set_desc, + .get_desc = rtl92de_get_desc, + .tx_polling = rtl92de_tx_polling, + .enable_hw_sec = rtl92de_enable_hw_security_config, + .set_key = rtl92de_set_key, + .init_sw_leds = rtl92de_init_sw_leds, + .get_bbreg = rtl92d_phy_query_bb_reg, + .set_bbreg = rtl92d_phy_set_bb_reg, + .get_rfreg = rtl92d_phy_query_rf_reg, + .set_rfreg = rtl92d_phy_set_rf_reg, + .linked_set_reg = rtl92d_linked_set_reg, +}; + +static struct rtl_mod_params rtl92de_mod_params = { + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = true, + .fwctrl_lps = false, +}; + +static struct rtl_hal_cfg rtl92de_hal_cfg = { + .bar_id = 2, + .write_readback = true, + .name = "rtl8192de", + .fw_name = "rtlwifi/rtl8192defw.bin", + .ops = &rtl8192de_hal_ops, + .mod_params = &rtl92de_mod_params, + + .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, + .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, + .maps[SYS_CLK] = REG_SYS_CLKR, + .maps[MAC_RCR_AM] = RCR_AM, + .maps[MAC_RCR_AB] = RCR_AB, + .maps[MAC_RCR_ACRC32] = RCR_ACRC32, + .maps[MAC_RCR_ACF] = RCR_ACF, + .maps[MAC_RCR_AAP] = RCR_AAP, + + .maps[EFUSE_TEST] = REG_EFUSE_TEST, + .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_CLK] = 0, /* just for 92se */ + .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_PWC_EV12V] = PWC_EV12V, + .maps[EFUSE_FEN_ELDR] = FEN_ELDR, + .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, + .maps[EFUSE_ANA8M] = 0, /* just for 92se */ + .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, + .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, + .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, + + .maps[RWCAM] = REG_CAMCMD, + .maps[WCAMI] = REG_CAMWRITE, + .maps[RCAMO] = REG_CAMREAD, + .maps[CAMDBG] = REG_CAMDBG, + .maps[SECR] = REG_SECCFG, + .maps[SEC_CAM_NONE] = CAM_NONE, + .maps[SEC_CAM_WEP40] = CAM_WEP40, + .maps[SEC_CAM_TKIP] = CAM_TKIP, + .maps[SEC_CAM_AES] = CAM_AES, + .maps[SEC_CAM_WEP104] = CAM_WEP104, + + .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, + .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, + .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, + .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, + .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, + .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, + .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, + .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, + .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, + .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, + .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, + .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, + .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, + .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, + .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2, + .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1, + + .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW, + .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT, + .maps[RTL_IMR_BcnInt] = IMR_BcnInt, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_BDOK] = IMR_BDOK, + .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, + .maps[RTL_IMR_TBDER] = IMR_TBDER, + .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, + .maps[RTL_IMR_TBDOK] = IMR_TBDOK, + .maps[RTL_IMR_BKDOK] = IMR_BKDOK, + .maps[RTL_IMR_BEDOK] = IMR_BEDOK, + .maps[RTL_IMR_VIDOK] = IMR_VIDOK, + .maps[RTL_IMR_VODOK] = IMR_VODOK, + .maps[RTL_IMR_ROK] = IMR_ROK, + .maps[RTL_IBSS_INT_MASKS] = (IMR_BcnInt | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC92D_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92D_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92D_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92D_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92D_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92D_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92D_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92D_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92D_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92D_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92D_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92D_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92D_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92D_RATEMCS15, +}; + +static struct pci_device_id rtl92de_pci_ids[] __devinitdata = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8193, rtl92de_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x002B, rtl92de_hal_cfg)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, rtl92de_pci_ids); + +MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192DE 802.11n Dual Mac PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8192defw.bin"); + +module_param_named(swenc, rtl92de_mod_params.sw_crypto, bool, 0444); +module_param_named(ips, rtl92de_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl92de_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92de_mod_params.fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); +MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); +MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1" + " is open)\n"); + +static struct pci_driver rtl92de_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl92de_pci_ids, + .probe = rtl_pci_probe, + .remove = rtl_pci_disconnect, + +#ifdef CONFIG_PM + .suspend = rtl_pci_suspend, + .resume = rtl_pci_resume, +#endif + +}; + +/* add global spin lock to solve the problem that + * Dul mac register operation on the same time */ +spinlock_t globalmutex_power; +spinlock_t globalmutex_for_fwdownload; +spinlock_t globalmutex_for_power_and_efuse; + +static int __init rtl92de_module_init(void) +{ + int ret = 0; + + spin_lock_init(&globalmutex_power); + spin_lock_init(&globalmutex_for_fwdownload); + spin_lock_init(&globalmutex_for_power_and_efuse); + + ret = pci_register_driver(&rtl92de_driver); + if (ret) + RT_ASSERT(false, (": No device found\n")); + return ret; +} + +static void __exit rtl92de_module_exit(void) +{ + pci_unregister_driver(&rtl92de_driver); +} + +module_init(rtl92de_module_init); +module_exit(rtl92de_module_exit); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.h b/drivers/net/wireless/rtlwifi/rtl8192de/sw.h new file mode 100644 index 000000000000..c95e47de1346 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92DE_SW_H__ +#define __RTL92DE_SW_H__ + +extern spinlock_t globalmutex_power; +extern spinlock_t globalmutex_for_fwdownload; +extern spinlock_t globalmutex_for_power_and_efuse; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/table.c b/drivers/net/wireless/rtlwifi/rtl8192de/table.c new file mode 100644 index 000000000000..bad7f9449ecf --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/table.c @@ -0,0 +1,1690 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + * Created on 2010/12/23, 6:38 + *****************************************************************************/ + +#include <linux/types.h> + +#include "table.h" + +u32 rtl8192de_phy_reg_2tarray[PHY_REG_2T_ARRAYLENGTH] = { + 0x024, 0x0011800d, + 0x028, 0x00ffdb83, + 0x014, 0x088ba955, + 0x010, 0x49022b03, + 0x800, 0x80040002, + 0x804, 0x00000003, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x80706388, + 0x814, 0x020c3d10, + 0x818, 0x02200385, + 0x81c, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390004, + 0x828, 0x01000100, + 0x82c, 0x00390004, + 0x830, 0x27272727, + 0x834, 0x27272727, + 0x838, 0x27272727, + 0x83c, 0x27272727, + 0x840, 0x00010000, + 0x844, 0x00010000, + 0x848, 0x27272727, + 0x84c, 0x27272727, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569a569a, + 0x85c, 0x0c1b25a4, + 0x860, 0x66e60230, + 0x864, 0x061f0130, + 0x868, 0x27272727, + 0x86c, 0x272b2b2b, + 0x870, 0x07000700, + 0x874, 0x22188000, + 0x878, 0x08080808, + 0x87c, 0x00007ff8, + 0x880, 0xc0083070, + 0x884, 0x00000cd5, + 0x888, 0x00000000, + 0x88c, 0xcc0000c0, + 0x890, 0x00000800, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x81121313, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff000c, + 0xa08, 0x8c838300, + 0xa0c, 0x2e68120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x00d30000, + 0xa70, 0x101fbf00, + 0xa74, 0x00000007, + 0xc00, 0x40071d40, + 0xc04, 0x03a05633, + 0xc08, 0x001000e4, + 0xc0c, 0x6c6c6c6c, + 0xc10, 0x08800000, + 0xc14, 0x40000100, + 0xc18, 0x08800000, + 0xc1c, 0x40000100, + 0xc20, 0x00000000, + 0xc24, 0x00000000, + 0xc28, 0x00000000, + 0xc2c, 0x00000000, + 0xc30, 0x69e9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a979718, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020107, + 0xc4c, 0x007f037f, + 0xc50, 0x69543420, + 0xc54, 0x43bc009e, + 0xc58, 0x69543420, + 0xc5c, 0x433c00a8, + 0xc60, 0x00000000, + 0xc64, 0x5116848b, + 0xc68, 0x47c00bff, + 0xc6c, 0x00000036, + 0xc70, 0x2c7f000d, + 0xc74, 0x058610db, + 0xc78, 0x0000001f, + 0xc7c, 0x40b95612, + 0xc80, 0x40000100, + 0xc84, 0x20f60000, + 0xc88, 0x40000100, + 0xc8c, 0x20e00000, + 0xc90, 0x00121820, + 0xc94, 0x00000007, + 0xc98, 0x00121820, + 0xc9c, 0x00007f7f, + 0xca0, 0x00000000, + 0xca4, 0x00000080, + 0xca8, 0x00000000, + 0xcac, 0x00000000, + 0xcb0, 0x00000000, + 0xcb4, 0x00000000, + 0xcb8, 0x00000000, + 0xcbc, 0x28000000, + 0xcc0, 0x00000000, + 0xcc4, 0x00000000, + 0xcc8, 0x00000000, + 0xccc, 0x00000000, + 0xcd0, 0x00000000, + 0xcd4, 0x00000000, + 0xcd8, 0x64b11e20, + 0xcdc, 0xe8767533, + 0xce0, 0x00222222, + 0xce4, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00080740, + 0xd04, 0x00020403, + 0xd08, 0x0000907f, + 0xd0c, 0x20010201, + 0xd10, 0xa0633333, + 0xd14, 0x3333bc43, + 0xd18, 0x7a8f5b6b, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x80608404, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd4c, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x00000000, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x04518a3c, + 0xd68, 0x00002101, + 0xd6c, 0x2a201c16, + 0xd70, 0x1812362e, + 0xd74, 0x322c2220, + 0xd78, 0x000e3c24, + 0xe00, 0x2a2a2a2a, + 0xe04, 0x2a2a2a2a, + 0xe08, 0x03902a2a, + 0xe10, 0x2a2a2a2a, + 0xe14, 0x2a2a2a2a, + 0xe18, 0x2a2a2a2a, + 0xe1c, 0x2a2a2a2a, + 0xe28, 0x00000000, + 0xe30, 0x1000dc1f, + 0xe34, 0x10008c1f, + 0xe38, 0x02140102, + 0xe3c, 0x681604c2, + 0xe40, 0x01007c00, + 0xe44, 0x01004800, + 0xe48, 0xfb000000, + 0xe4c, 0x000028d1, + 0xe50, 0x1000dc1f, + 0xe54, 0x10008c1f, + 0xe58, 0x02140102, + 0xe5c, 0x28160d05, + 0xe60, 0x00000010, + 0xe68, 0x001b25a4, + 0xe6c, 0x63db25a4, + 0xe70, 0x63db25a4, + 0xe74, 0x0c126da4, + 0xe78, 0x0c126da4, + 0xe7c, 0x0c126da4, + 0xe80, 0x0c126da4, + 0xe84, 0x63db25a4, + 0xe88, 0x0c126da4, + 0xe8c, 0x63db25a4, + 0xed0, 0x63db25a4, + 0xed4, 0x63db25a4, + 0xed8, 0x63db25a4, + 0xedc, 0x001b25a4, + 0xee0, 0x001b25a4, + 0xeec, 0x6fdb25a4, + 0xf14, 0x00000003, + 0xf1c, 0x00000064, + 0xf4c, 0x00000004, + 0xf00, 0x00000300, +}; + +u32 rtl8192de_phy_reg_array_pg[PHY_REG_ARRAY_PG_LENGTH] = { + 0xe00, 0xffffffff, 0x07090c0c, + 0xe04, 0xffffffff, 0x01020405, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x0b0c0c0e, + 0xe14, 0xffffffff, 0x01030506, + 0xe18, 0xffffffff, 0x0b0c0d0e, + 0xe1c, 0xffffffff, 0x01030509, + 0x830, 0xffffffff, 0x07090c0c, + 0x834, 0xffffffff, 0x01020405, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x0b0c0c0e, + 0x848, 0xffffffff, 0x01030506, + 0x84c, 0xffffffff, 0x0b0c0d0e, + 0x868, 0xffffffff, 0x01030509, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x06060606, + 0xe14, 0xffffffff, 0x00020406, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x06060606, + 0x848, 0xffffffff, 0x00020406, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x00000000, + 0xe04, 0xffffffff, 0x00000000, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x00000000, + 0xe14, 0xffffffff, 0x00000000, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x00000000, + 0x834, 0xffffffff, 0x00000000, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x00000000, + 0x848, 0xffffffff, 0x00000000, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0x86c, 0xffffff00, 0x00000000, + 0xe10, 0xffffffff, 0x08080808, + 0xe14, 0xffffffff, 0x00040408, + 0xe18, 0xffffffff, 0x00000000, + 0xe1c, 0xffffffff, 0x00000000, + 0x830, 0xffffffff, 0x04040404, + 0x834, 0xffffffff, 0x00020204, + 0x838, 0xffffff00, 0x00000000, + 0x86c, 0x000000ff, 0x00000000, + 0x83c, 0xffffffff, 0x08080808, + 0x848, 0xffffffff, 0x00040408, + 0x84c, 0xffffffff, 0x00000000, + 0x868, 0xffffffff, 0x00000000, +}; + +u32 rtl8192de_radioa_2tarray[RADIOA_2T_ARRAYLENGTH] = { + 0x000, 0x00030000, + 0x001, 0x00030000, + 0x002, 0x00000000, + 0x003, 0x00018c63, + 0x004, 0x00018c63, + 0x008, 0x00084000, + 0x00b, 0x0001c000, + 0x00e, 0x00018c67, + 0x00f, 0x00000851, + 0x014, 0x00021440, + 0x018, 0x00017524, + 0x019, 0x00000000, + 0x01d, 0x000a1290, + 0x023, 0x00001558, + 0x01a, 0x00030a99, + 0x01b, 0x00040b00, + 0x01c, 0x000fc339, + 0x03a, 0x000a57eb, + 0x03b, 0x00020000, + 0x03c, 0x000ff454, + 0x020, 0x0000aa52, + 0x021, 0x00054000, + 0x040, 0x0000aa52, + 0x041, 0x00014000, + 0x025, 0x000803be, + 0x026, 0x000fc638, + 0x027, 0x00077c18, + 0x028, 0x000de471, + 0x029, 0x000d7110, + 0x02a, 0x0008cb04, + 0x02b, 0x0004128b, + 0x02c, 0x00001840, + 0x043, 0x0002444f, + 0x044, 0x0001adb0, + 0x045, 0x00056467, + 0x046, 0x0008992c, + 0x047, 0x0000452c, + 0x048, 0x000f9c43, + 0x049, 0x00002e0c, + 0x04a, 0x000546eb, + 0x04b, 0x0008966c, + 0x04c, 0x0000dde9, + 0x018, 0x00007401, + 0x000, 0x00070000, + 0x012, 0x000dc000, + 0x012, 0x00090000, + 0x012, 0x00051000, + 0x012, 0x00012000, + 0x013, 0x000287b7, + 0x013, 0x000247ab, + 0x013, 0x0002079f, + 0x013, 0x0001c793, + 0x013, 0x0001839b, + 0x013, 0x00014392, + 0x013, 0x0001019a, + 0x013, 0x0000c191, + 0x013, 0x00008194, + 0x013, 0x000040a0, + 0x013, 0x00000018, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x016, 0x000e1330, + 0x016, 0x000a1330, + 0x016, 0x00061330, + 0x016, 0x00021330, + 0x018, 0x00017524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x018, 0x00037524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x018, 0x00057568, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x030, 0x0004470f, + 0x031, 0x00044ff0, + 0x032, 0x00000070, + 0x033, 0x000dd480, + 0x034, 0x000ffac0, + 0x035, 0x000b80c0, + 0x036, 0x00077000, + 0x037, 0x00064ff2, + 0x038, 0x000e7661, + 0x039, 0x00000e90, + 0x000, 0x00030000, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00088009, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x01e, 0x00088001, + 0x01f, 0x00080000, + 0x0fe, 0x00000000, + 0x018, 0x00097524, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x02b, 0x00041289, + 0x0fe, 0x00000000, + 0x02d, 0x0006aaaa, + 0x02e, 0x000b4d01, + 0x02d, 0x00080000, + 0x02e, 0x00004d02, + 0x02d, 0x00095555, + 0x02e, 0x00054d03, + 0x02d, 0x000aaaaa, + 0x02e, 0x000b4d04, + 0x02d, 0x000c0000, + 0x02e, 0x00004d05, + 0x02d, 0x000d5555, + 0x02e, 0x00054d06, + 0x02d, 0x000eaaaa, + 0x02e, 0x000b4d07, + 0x02d, 0x00000000, + 0x02e, 0x00005108, + 0x02d, 0x00015555, + 0x02e, 0x00055109, + 0x02d, 0x0002aaaa, + 0x02e, 0x000b510a, + 0x02d, 0x00040000, + 0x02e, 0x0000510b, + 0x02d, 0x00055555, + 0x02e, 0x0005510c, +}; + +u32 rtl8192de_radiob_2tarray[RADIOB_2T_ARRAYLENGTH] = { + 0x000, 0x00030000, + 0x001, 0x00030000, + 0x002, 0x00000000, + 0x003, 0x00018c63, + 0x004, 0x00018c63, + 0x008, 0x00084000, + 0x00b, 0x0001c000, + 0x00e, 0x00018c67, + 0x00f, 0x00000851, + 0x014, 0x00021440, + 0x018, 0x00007401, + 0x019, 0x00000060, + 0x01d, 0x000a1290, + 0x023, 0x00001558, + 0x01a, 0x00030a99, + 0x01b, 0x00040b00, + 0x01c, 0x000fc339, + 0x03a, 0x000a57eb, + 0x03b, 0x00020000, + 0x03c, 0x000ff454, + 0x020, 0x0000aa52, + 0x021, 0x00054000, + 0x040, 0x0000aa52, + 0x041, 0x00014000, + 0x025, 0x000803be, + 0x026, 0x000fc638, + 0x027, 0x00077c18, + 0x028, 0x000d1c31, + 0x029, 0x000d7110, + 0x02a, 0x000aeb04, + 0x02b, 0x0004128b, + 0x02c, 0x00001840, + 0x043, 0x0002444f, + 0x044, 0x0001adb0, + 0x045, 0x00056467, + 0x046, 0x0008992c, + 0x047, 0x0000452c, + 0x048, 0x000f9c43, + 0x049, 0x00002e0c, + 0x04a, 0x000546eb, + 0x04b, 0x0008966c, + 0x04c, 0x0000dde9, + 0x018, 0x00007401, + 0x000, 0x00070000, + 0x012, 0x000dc000, + 0x012, 0x00090000, + 0x012, 0x00051000, + 0x012, 0x00012000, + 0x013, 0x000287b7, + 0x013, 0x000247ab, + 0x013, 0x0002079f, + 0x013, 0x0001c793, + 0x013, 0x0001839b, + 0x013, 0x00014392, + 0x013, 0x0001019a, + 0x013, 0x0000c191, + 0x013, 0x00008194, + 0x013, 0x000040a0, + 0x013, 0x00000018, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x016, 0x000e1330, + 0x016, 0x000a1330, + 0x016, 0x00061330, + 0x016, 0x00021330, + 0x018, 0x00017524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x018, 0x00037524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x018, 0x00057524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bc, + 0x013, 0x000247b0, + 0x013, 0x000203b4, + 0x013, 0x0001c3a8, + 0x013, 0x000181b4, + 0x013, 0x000141a8, + 0x013, 0x000100b0, + 0x013, 0x0000c0a4, + 0x013, 0x0000b02c, + 0x013, 0x00004020, + 0x013, 0x00000014, + 0x015, 0x0000f4c3, + 0x015, 0x0004f4c3, + 0x015, 0x0008f4c3, + 0x016, 0x000e085f, + 0x016, 0x000a085f, + 0x016, 0x0006085f, + 0x016, 0x0002085f, + 0x030, 0x0004470f, + 0x031, 0x00044ff0, + 0x032, 0x00000070, + 0x033, 0x000dd480, + 0x034, 0x000ffac0, + 0x035, 0x000b80c0, + 0x036, 0x00077000, + 0x037, 0x00064ff2, + 0x038, 0x000e7661, + 0x039, 0x00000e90, + 0x000, 0x00030000, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00088009, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x01e, 0x00088001, + 0x01f, 0x00080000, + 0x0fe, 0x00000000, + 0x018, 0x00087401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x02b, 0x00041289, + 0x0fe, 0x00000000, + 0x02d, 0x00066666, + 0x02e, 0x00064001, + 0x02d, 0x00091111, + 0x02e, 0x00014002, + 0x02d, 0x000bbbbb, + 0x02e, 0x000b4003, + 0x02d, 0x000e6666, + 0x02e, 0x00064004, + 0x02d, 0x00088888, + 0x02e, 0x00084005, + 0x02d, 0x0009dddd, + 0x02e, 0x000d4006, + 0x02d, 0x000b3333, + 0x02e, 0x00034007, + 0x02d, 0x00048888, + 0x02e, 0x00084408, + 0x02d, 0x000bbbbb, + 0x02e, 0x000b4409, + 0x02d, 0x000e6666, + 0x02e, 0x0006440a, + 0x02d, 0x00011111, + 0x02e, 0x0001480b, + 0x02d, 0x0003bbbb, + 0x02e, 0x000b480c, + 0x02d, 0x00066666, + 0x02e, 0x0006480d, + 0x02d, 0x000ccccc, + 0x02e, 0x000c480e, +}; + +u32 rtl8192de_radioa_2t_int_paarray[RADIOA_2T_INT_PA_ARRAYLENGTH] = { + 0x000, 0x00030000, + 0x001, 0x00030000, + 0x002, 0x00000000, + 0x003, 0x00018c63, + 0x004, 0x00018c63, + 0x008, 0x00084000, + 0x00b, 0x0001c000, + 0x00e, 0x00018c67, + 0x00f, 0x00000851, + 0x014, 0x00021440, + 0x018, 0x00017524, + 0x019, 0x00000000, + 0x01d, 0x000a1290, + 0x023, 0x00001558, + 0x01a, 0x00030a99, + 0x01b, 0x00040b00, + 0x01c, 0x000fc339, + 0x03a, 0x000a57eb, + 0x03b, 0x00020000, + 0x03c, 0x000ff454, + 0x020, 0x0000aa52, + 0x021, 0x00054000, + 0x040, 0x0000aa52, + 0x041, 0x00014000, + 0x025, 0x000803be, + 0x026, 0x000fc638, + 0x027, 0x00077c18, + 0x028, 0x000de471, + 0x029, 0x000d7110, + 0x02a, 0x0008eb04, + 0x02b, 0x0004128b, + 0x02c, 0x00001840, + 0x043, 0x0002444f, + 0x044, 0x0001adb0, + 0x045, 0x00056467, + 0x046, 0x0008992c, + 0x047, 0x0000452c, + 0x048, 0x000c0443, + 0x049, 0x00000730, + 0x04a, 0x00050f0f, + 0x04b, 0x000896ee, + 0x04c, 0x0000ddee, + 0x018, 0x00007401, + 0x000, 0x00070000, + 0x012, 0x000dc000, + 0x012, 0x00090000, + 0x012, 0x00051000, + 0x012, 0x00012000, + 0x013, 0x000287b7, + 0x013, 0x000247ab, + 0x013, 0x0002079f, + 0x013, 0x0001c793, + 0x013, 0x0001839b, + 0x013, 0x00014392, + 0x013, 0x0001019a, + 0x013, 0x0000c191, + 0x013, 0x00008194, + 0x013, 0x000040a0, + 0x013, 0x00000018, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x016, 0x000e1330, + 0x016, 0x000a1330, + 0x016, 0x00061330, + 0x016, 0x00021330, + 0x018, 0x00017524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x018, 0x00037564, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x018, 0x00057595, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x030, 0x0004470f, + 0x031, 0x00044ff0, + 0x032, 0x00000070, + 0x033, 0x000dd480, + 0x034, 0x000ffac0, + 0x035, 0x000b80c0, + 0x036, 0x00077000, + 0x037, 0x00064ff2, + 0x038, 0x000e7661, + 0x039, 0x00000e90, + 0x000, 0x00030000, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00088009, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x01e, 0x00088001, + 0x01f, 0x00080000, + 0x0fe, 0x00000000, + 0x018, 0x00097524, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x02b, 0x00041289, + 0x0fe, 0x00000000, + 0x02d, 0x0006aaaa, + 0x02e, 0x000b4d01, + 0x02d, 0x00080000, + 0x02e, 0x00004d02, + 0x02d, 0x00095555, + 0x02e, 0x00054d03, + 0x02d, 0x000aaaaa, + 0x02e, 0x000b4d04, + 0x02d, 0x000c0000, + 0x02e, 0x00004d05, + 0x02d, 0x000d5555, + 0x02e, 0x00054d06, + 0x02d, 0x000eaaaa, + 0x02e, 0x000b4d07, + 0x02d, 0x00000000, + 0x02e, 0x00005108, + 0x02d, 0x00015555, + 0x02e, 0x00055109, + 0x02d, 0x0002aaaa, + 0x02e, 0x000b510a, + 0x02d, 0x00040000, + 0x02e, 0x0000510b, + 0x02d, 0x00055555, + 0x02e, 0x0005510c, +}; + +u32 rtl8192de_radiob_2t_int_paarray[RADIOB_2T_INT_PA_ARRAYLENGTH] = { + 0x000, 0x00030000, + 0x001, 0x00030000, + 0x002, 0x00000000, + 0x003, 0x00018c63, + 0x004, 0x00018c63, + 0x008, 0x00084000, + 0x00b, 0x0001c000, + 0x00e, 0x00018c67, + 0x00f, 0x00000851, + 0x014, 0x00021440, + 0x018, 0x00007401, + 0x019, 0x00000060, + 0x01d, 0x000a1290, + 0x023, 0x00001558, + 0x01a, 0x00030a99, + 0x01b, 0x00040b00, + 0x01c, 0x000fc339, + 0x03a, 0x000a57eb, + 0x03b, 0x00020000, + 0x03c, 0x000ff454, + 0x020, 0x0000aa52, + 0x021, 0x00054000, + 0x040, 0x0000aa52, + 0x041, 0x00014000, + 0x025, 0x000803be, + 0x026, 0x000fc638, + 0x027, 0x00077c18, + 0x028, 0x000d1c31, + 0x029, 0x000d7110, + 0x02a, 0x000aeb04, + 0x02b, 0x0004128b, + 0x02c, 0x00001840, + 0x043, 0x0002444f, + 0x044, 0x0001adb0, + 0x045, 0x00056467, + 0x046, 0x0008992c, + 0x047, 0x0000452c, + 0x048, 0x000c0443, + 0x049, 0x00000730, + 0x04a, 0x00050f0f, + 0x04b, 0x000896ee, + 0x04c, 0x0000ddee, + 0x018, 0x00007401, + 0x000, 0x00070000, + 0x012, 0x000dc000, + 0x012, 0x00090000, + 0x012, 0x00051000, + 0x012, 0x00012000, + 0x013, 0x000287b7, + 0x013, 0x000247ab, + 0x013, 0x0002079f, + 0x013, 0x0001c793, + 0x013, 0x0001839b, + 0x013, 0x00014392, + 0x013, 0x0001019a, + 0x013, 0x0000c191, + 0x013, 0x00008194, + 0x013, 0x000040a0, + 0x013, 0x00000018, + 0x015, 0x0000f424, + 0x015, 0x0004f424, + 0x015, 0x0008f424, + 0x016, 0x000e1330, + 0x016, 0x000a1330, + 0x016, 0x00061330, + 0x016, 0x00021330, + 0x018, 0x00017524, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x018, 0x00037564, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x018, 0x00057595, + 0x000, 0x00070000, + 0x012, 0x000cf000, + 0x012, 0x000bc000, + 0x012, 0x00078000, + 0x012, 0x00000000, + 0x013, 0x000287bf, + 0x013, 0x000247b3, + 0x013, 0x000207a7, + 0x013, 0x0001c79b, + 0x013, 0x0001839f, + 0x013, 0x00014393, + 0x013, 0x00010399, + 0x013, 0x0000c38d, + 0x013, 0x00008199, + 0x013, 0x0000418d, + 0x013, 0x00000099, + 0x015, 0x0000f495, + 0x015, 0x0004f495, + 0x015, 0x0008f495, + 0x016, 0x000e1874, + 0x016, 0x000a1874, + 0x016, 0x00061874, + 0x016, 0x00021874, + 0x030, 0x0004470f, + 0x031, 0x00044ff0, + 0x032, 0x00000070, + 0x033, 0x000dd480, + 0x034, 0x000ffac0, + 0x035, 0x000b80c0, + 0x036, 0x00077000, + 0x037, 0x00064ff2, + 0x038, 0x000e7661, + 0x039, 0x00000e90, + 0x000, 0x00030000, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x01e, 0x00088009, + 0x01f, 0x00080003, + 0x0fe, 0x00000000, + 0x01e, 0x00088001, + 0x01f, 0x00080000, + 0x0fe, 0x00000000, + 0x018, 0x00087401, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x0fe, 0x00000000, + 0x02b, 0x00041289, + 0x0fe, 0x00000000, + 0x02d, 0x00066666, + 0x02e, 0x00064001, + 0x02d, 0x00091111, + 0x02e, 0x00014002, + 0x02d, 0x000bbbbb, + 0x02e, 0x000b4003, + 0x02d, 0x000e6666, + 0x02e, 0x00064004, + 0x02d, 0x00088888, + 0x02e, 0x00084005, + 0x02d, 0x0009dddd, + 0x02e, 0x000d4006, + 0x02d, 0x000b3333, + 0x02e, 0x00034007, + 0x02d, 0x00048888, + 0x02e, 0x00084408, + 0x02d, 0x000bbbbb, + 0x02e, 0x000b4409, + 0x02d, 0x000e6666, + 0x02e, 0x0006440a, + 0x02d, 0x00011111, + 0x02e, 0x0001480b, + 0x02d, 0x0003bbbb, + 0x02e, 0x000b480c, + 0x02d, 0x00066666, + 0x02e, 0x0006480d, + 0x02d, 0x000ccccc, + 0x02e, 0x000c480e, +}; + +u32 rtl8192de_mac_2tarray[MAC_2T_ARRAYLENGTH] = { + 0x420, 0x00000080, + 0x423, 0x00000000, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000006, + 0x437, 0x00000007, + 0x438, 0x00000000, + 0x439, 0x00000000, + 0x43a, 0x00000000, + 0x43b, 0x00000001, + 0x43c, 0x00000004, + 0x43d, 0x00000005, + 0x43e, 0x00000006, + 0x43f, 0x00000007, + 0x440, 0x00000050, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000015, + 0x445, 0x000000f0, + 0x446, 0x0000000f, + 0x447, 0x00000000, + 0x462, 0x00000008, + 0x463, 0x00000003, + 0x4c8, 0x000000ff, + 0x4c9, 0x00000008, + 0x4cc, 0x000000ff, + 0x4cd, 0x000000ff, + 0x4ce, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000a2, + 0x502, 0x0000002f, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000a3, + 0x506, 0x0000005e, + 0x507, 0x00000000, + 0x508, 0x0000002b, + 0x509, 0x000000a4, + 0x50a, 0x0000005e, + 0x50b, 0x00000000, + 0x50c, 0x0000004f, + 0x50d, 0x000000a4, + 0x50e, 0x00000000, + 0x50f, 0x00000000, + 0x512, 0x0000001c, + 0x514, 0x0000000a, + 0x515, 0x00000010, + 0x516, 0x0000000a, + 0x517, 0x00000010, + 0x51a, 0x00000016, + 0x524, 0x0000000f, + 0x525, 0x0000004f, + 0x546, 0x00000040, + 0x547, 0x00000000, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55a, 0x00000002, + 0x55d, 0x000000ff, + 0x605, 0x00000030, + 0x608, 0x0000000e, + 0x609, 0x0000002a, + 0x652, 0x00000020, + 0x63c, 0x0000000a, + 0x63d, 0x0000000a, + 0x63e, 0x0000000e, + 0x63f, 0x0000000e, + 0x66e, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70a, 0x00000065, + 0x70b, 0x00000087, +}; + +u32 rtl8192de_agctab_array[AGCTAB_ARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7b020001, + 0xc78, 0x7b030001, + 0xc78, 0x7b040001, + 0xc78, 0x7b050001, + 0xc78, 0x7b060001, + 0xc78, 0x7a070001, + 0xc78, 0x79080001, + 0xc78, 0x78090001, + 0xc78, 0x770a0001, + 0xc78, 0x760b0001, + 0xc78, 0x750c0001, + 0xc78, 0x740d0001, + 0xc78, 0x730e0001, + 0xc78, 0x720f0001, + 0xc78, 0x71100001, + 0xc78, 0x70110001, + 0xc78, 0x6f120001, + 0xc78, 0x6e130001, + 0xc78, 0x6d140001, + 0xc78, 0x6c150001, + 0xc78, 0x6b160001, + 0xc78, 0x6a170001, + 0xc78, 0x69180001, + 0xc78, 0x68190001, + 0xc78, 0x671a0001, + 0xc78, 0x661b0001, + 0xc78, 0x651c0001, + 0xc78, 0x641d0001, + 0xc78, 0x631e0001, + 0xc78, 0x621f0001, + 0xc78, 0x61200001, + 0xc78, 0x60210001, + 0xc78, 0x49220001, + 0xc78, 0x48230001, + 0xc78, 0x47240001, + 0xc78, 0x46250001, + 0xc78, 0x45260001, + 0xc78, 0x44270001, + 0xc78, 0x43280001, + 0xc78, 0x42290001, + 0xc78, 0x412a0001, + 0xc78, 0x402b0001, + 0xc78, 0x262c0001, + 0xc78, 0x252d0001, + 0xc78, 0x242e0001, + 0xc78, 0x232f0001, + 0xc78, 0x22300001, + 0xc78, 0x21310001, + 0xc78, 0x20320001, + 0xc78, 0x06330001, + 0xc78, 0x05340001, + 0xc78, 0x04350001, + 0xc78, 0x03360001, + 0xc78, 0x02370001, + 0xc78, 0x01380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7b400001, + 0xc78, 0x7b410001, + 0xc78, 0x7a420001, + 0xc78, 0x79430001, + 0xc78, 0x78440001, + 0xc78, 0x77450001, + 0xc78, 0x76460001, + 0xc78, 0x75470001, + 0xc78, 0x74480001, + 0xc78, 0x73490001, + 0xc78, 0x724a0001, + 0xc78, 0x714b0001, + 0xc78, 0x704c0001, + 0xc78, 0x6f4d0001, + 0xc78, 0x6e4e0001, + 0xc78, 0x6d4f0001, + 0xc78, 0x6c500001, + 0xc78, 0x6b510001, + 0xc78, 0x6a520001, + 0xc78, 0x69530001, + 0xc78, 0x68540001, + 0xc78, 0x67550001, + 0xc78, 0x66560001, + 0xc78, 0x65570001, + 0xc78, 0x64580001, + 0xc78, 0x63590001, + 0xc78, 0x625a0001, + 0xc78, 0x615b0001, + 0xc78, 0x605c0001, + 0xc78, 0x485d0001, + 0xc78, 0x475e0001, + 0xc78, 0x465f0001, + 0xc78, 0x45600001, + 0xc78, 0x44610001, + 0xc78, 0x43620001, + 0xc78, 0x42630001, + 0xc78, 0x41640001, + 0xc78, 0x40650001, + 0xc78, 0x27660001, + 0xc78, 0x26670001, + 0xc78, 0x25680001, + 0xc78, 0x24690001, + 0xc78, 0x236a0001, + 0xc78, 0x226b0001, + 0xc78, 0x216c0001, + 0xc78, 0x206d0001, + 0xc78, 0x206e0001, + 0xc78, 0x206f0001, + 0xc78, 0x20700001, + 0xc78, 0x20710001, + 0xc78, 0x20720001, + 0xc78, 0x20730001, + 0xc78, 0x20740001, + 0xc78, 0x20750001, + 0xc78, 0x20760001, + 0xc78, 0x20770001, + 0xc78, 0x20780001, + 0xc78, 0x20790001, + 0xc78, 0x207a0001, + 0xc78, 0x207b0001, + 0xc78, 0x207c0001, + 0xc78, 0x207d0001, + 0xc78, 0x207e0001, + 0xc78, 0x207f0001, + 0xc78, 0x38000002, + 0xc78, 0x38010002, + 0xc78, 0x38020002, + 0xc78, 0x38030002, + 0xc78, 0x38040002, + 0xc78, 0x38050002, + 0xc78, 0x38060002, + 0xc78, 0x38070002, + 0xc78, 0x38080002, + 0xc78, 0x3c090002, + 0xc78, 0x3e0a0002, + 0xc78, 0x400b0002, + 0xc78, 0x440c0002, + 0xc78, 0x480d0002, + 0xc78, 0x4c0e0002, + 0xc78, 0x500f0002, + 0xc78, 0x52100002, + 0xc78, 0x56110002, + 0xc78, 0x5a120002, + 0xc78, 0x5e130002, + 0xc78, 0x60140002, + 0xc78, 0x60150002, + 0xc78, 0x60160002, + 0xc78, 0x62170002, + 0xc78, 0x62180002, + 0xc78, 0x62190002, + 0xc78, 0x621a0002, + 0xc78, 0x621b0002, + 0xc78, 0x621c0002, + 0xc78, 0x621d0002, + 0xc78, 0x621e0002, + 0xc78, 0x621f0002, + 0xc78, 0x32000044, + 0xc78, 0x32010044, + 0xc78, 0x32020044, + 0xc78, 0x32030044, + 0xc78, 0x32040044, + 0xc78, 0x32050044, + 0xc78, 0x32060044, + 0xc78, 0x32070044, + 0xc78, 0x32080044, + 0xc78, 0x34090044, + 0xc78, 0x350a0044, + 0xc78, 0x360b0044, + 0xc78, 0x370c0044, + 0xc78, 0x380d0044, + 0xc78, 0x390e0044, + 0xc78, 0x3a0f0044, + 0xc78, 0x3e100044, + 0xc78, 0x42110044, + 0xc78, 0x44120044, + 0xc78, 0x46130044, + 0xc78, 0x4a140044, + 0xc78, 0x4e150044, + 0xc78, 0x50160044, + 0xc78, 0x55170044, + 0xc78, 0x5a180044, + 0xc78, 0x5e190044, + 0xc78, 0x641a0044, + 0xc78, 0x6e1b0044, + 0xc78, 0x6e1c0044, + 0xc78, 0x6e1d0044, + 0xc78, 0x6e1e0044, + 0xc78, 0x6e1f0044, + 0xc78, 0x6e1f0000, +}; + +u32 rtl8192de_agctab_5garray[AGCTAB_5G_ARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7a020001, + 0xc78, 0x79030001, + 0xc78, 0x78040001, + 0xc78, 0x77050001, + 0xc78, 0x76060001, + 0xc78, 0x75070001, + 0xc78, 0x74080001, + 0xc78, 0x73090001, + 0xc78, 0x720a0001, + 0xc78, 0x710b0001, + 0xc78, 0x700c0001, + 0xc78, 0x6f0d0001, + 0xc78, 0x6e0e0001, + 0xc78, 0x6d0f0001, + 0xc78, 0x6c100001, + 0xc78, 0x6b110001, + 0xc78, 0x6a120001, + 0xc78, 0x69130001, + 0xc78, 0x68140001, + 0xc78, 0x67150001, + 0xc78, 0x66160001, + 0xc78, 0x65170001, + 0xc78, 0x64180001, + 0xc78, 0x63190001, + 0xc78, 0x621a0001, + 0xc78, 0x611b0001, + 0xc78, 0x601c0001, + 0xc78, 0x481d0001, + 0xc78, 0x471e0001, + 0xc78, 0x461f0001, + 0xc78, 0x45200001, + 0xc78, 0x44210001, + 0xc78, 0x43220001, + 0xc78, 0x42230001, + 0xc78, 0x41240001, + 0xc78, 0x40250001, + 0xc78, 0x27260001, + 0xc78, 0x26270001, + 0xc78, 0x25280001, + 0xc78, 0x24290001, + 0xc78, 0x232a0001, + 0xc78, 0x222b0001, + 0xc78, 0x212c0001, + 0xc78, 0x202d0001, + 0xc78, 0x202e0001, + 0xc78, 0x202f0001, + 0xc78, 0x20300001, + 0xc78, 0x20310001, + 0xc78, 0x20320001, + 0xc78, 0x20330001, + 0xc78, 0x20340001, + 0xc78, 0x20350001, + 0xc78, 0x20360001, + 0xc78, 0x20370001, + 0xc78, 0x20380001, + 0xc78, 0x20390001, + 0xc78, 0x203a0001, + 0xc78, 0x203b0001, + 0xc78, 0x203c0001, + 0xc78, 0x203d0001, + 0xc78, 0x203e0001, + 0xc78, 0x203f0001, + 0xc78, 0x32000044, + 0xc78, 0x32010044, + 0xc78, 0x32020044, + 0xc78, 0x32030044, + 0xc78, 0x32040044, + 0xc78, 0x32050044, + 0xc78, 0x32060044, + 0xc78, 0x32070044, + 0xc78, 0x32080044, + 0xc78, 0x34090044, + 0xc78, 0x350a0044, + 0xc78, 0x360b0044, + 0xc78, 0x370c0044, + 0xc78, 0x380d0044, + 0xc78, 0x390e0044, + 0xc78, 0x3a0f0044, + 0xc78, 0x3e100044, + 0xc78, 0x42110044, + 0xc78, 0x44120044, + 0xc78, 0x46130044, + 0xc78, 0x4a140044, + 0xc78, 0x4e150044, + 0xc78, 0x50160044, + 0xc78, 0x55170044, + 0xc78, 0x5a180044, + 0xc78, 0x5e190044, + 0xc78, 0x641a0044, + 0xc78, 0x6e1b0044, + 0xc78, 0x6e1c0044, + 0xc78, 0x6e1d0044, + 0xc78, 0x6e1e0044, + 0xc78, 0x6e1f0044, + 0xc78, 0x6e1f0000, +}; + +u32 rtl8192de_agctab_2garray[AGCTAB_2G_ARRAYLENGTH] = { + 0xc78, 0x7b000001, + 0xc78, 0x7b010001, + 0xc78, 0x7b020001, + 0xc78, 0x7b030001, + 0xc78, 0x7b040001, + 0xc78, 0x7b050001, + 0xc78, 0x7b060001, + 0xc78, 0x7a070001, + 0xc78, 0x79080001, + 0xc78, 0x78090001, + 0xc78, 0x770a0001, + 0xc78, 0x760b0001, + 0xc78, 0x750c0001, + 0xc78, 0x740d0001, + 0xc78, 0x730e0001, + 0xc78, 0x720f0001, + 0xc78, 0x71100001, + 0xc78, 0x70110001, + 0xc78, 0x6f120001, + 0xc78, 0x6e130001, + 0xc78, 0x6d140001, + 0xc78, 0x6c150001, + 0xc78, 0x6b160001, + 0xc78, 0x6a170001, + 0xc78, 0x69180001, + 0xc78, 0x68190001, + 0xc78, 0x671a0001, + 0xc78, 0x661b0001, + 0xc78, 0x651c0001, + 0xc78, 0x641d0001, + 0xc78, 0x631e0001, + 0xc78, 0x621f0001, + 0xc78, 0x61200001, + 0xc78, 0x60210001, + 0xc78, 0x49220001, + 0xc78, 0x48230001, + 0xc78, 0x47240001, + 0xc78, 0x46250001, + 0xc78, 0x45260001, + 0xc78, 0x44270001, + 0xc78, 0x43280001, + 0xc78, 0x42290001, + 0xc78, 0x412a0001, + 0xc78, 0x402b0001, + 0xc78, 0x262c0001, + 0xc78, 0x252d0001, + 0xc78, 0x242e0001, + 0xc78, 0x232f0001, + 0xc78, 0x22300001, + 0xc78, 0x21310001, + 0xc78, 0x20320001, + 0xc78, 0x06330001, + 0xc78, 0x05340001, + 0xc78, 0x04350001, + 0xc78, 0x03360001, + 0xc78, 0x02370001, + 0xc78, 0x01380001, + 0xc78, 0x00390001, + 0xc78, 0x003a0001, + 0xc78, 0x003b0001, + 0xc78, 0x003c0001, + 0xc78, 0x003d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x38000002, + 0xc78, 0x38010002, + 0xc78, 0x38020002, + 0xc78, 0x38030002, + 0xc78, 0x38040002, + 0xc78, 0x38050002, + 0xc78, 0x38060002, + 0xc78, 0x38070002, + 0xc78, 0x38080002, + 0xc78, 0x3c090002, + 0xc78, 0x3e0a0002, + 0xc78, 0x400b0002, + 0xc78, 0x440c0002, + 0xc78, 0x480d0002, + 0xc78, 0x4c0e0002, + 0xc78, 0x500f0002, + 0xc78, 0x52100002, + 0xc78, 0x56110002, + 0xc78, 0x5a120002, + 0xc78, 0x5e130002, + 0xc78, 0x60140002, + 0xc78, 0x60150002, + 0xc78, 0x60160002, + 0xc78, 0x62170002, + 0xc78, 0x62180002, + 0xc78, 0x62190002, + 0xc78, 0x621a0002, + 0xc78, 0x621b0002, + 0xc78, 0x621c0002, + 0xc78, 0x621d0002, + 0xc78, 0x621e0002, + 0xc78, 0x621f0002, + 0xc78, 0x6e1f0000, +}; diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/table.h b/drivers/net/wireless/rtlwifi/rtl8192de/table.h new file mode 100644 index 000000000000..93f30ca62d8f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/table.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + * Created on 2010/ 5/18, 1:41 + *****************************************************************************/ + +#ifndef __RTL92DE_TABLE__H_ +#define __RTL92DE_TABLE__H_ + +/*Created on 2011/ 1/14, 1:35*/ + +#define PHY_REG_2T_ARRAYLENGTH 380 +extern u32 rtl8192de_phy_reg_2tarray[PHY_REG_2T_ARRAYLENGTH]; +#define PHY_REG_ARRAY_PG_LENGTH 624 +extern u32 rtl8192de_phy_reg_array_pg[PHY_REG_ARRAY_PG_LENGTH]; +#define RADIOA_2T_ARRAYLENGTH 378 +extern u32 rtl8192de_radioa_2tarray[RADIOA_2T_ARRAYLENGTH]; +#define RADIOB_2T_ARRAYLENGTH 384 +extern u32 rtl8192de_radiob_2tarray[RADIOB_2T_ARRAYLENGTH]; +#define RADIOA_2T_INT_PA_ARRAYLENGTH 378 +extern u32 rtl8192de_radioa_2t_int_paarray[RADIOA_2T_INT_PA_ARRAYLENGTH]; +#define RADIOB_2T_INT_PA_ARRAYLENGTH 384 +extern u32 rtl8192de_radiob_2t_int_paarray[RADIOB_2T_INT_PA_ARRAYLENGTH]; +#define MAC_2T_ARRAYLENGTH 160 +extern u32 rtl8192de_mac_2tarray[MAC_2T_ARRAYLENGTH]; +#define AGCTAB_ARRAYLENGTH 386 +extern u32 rtl8192de_agctab_array[AGCTAB_ARRAYLENGTH]; +#define AGCTAB_5G_ARRAYLENGTH 194 +extern u32 rtl8192de_agctab_5garray[AGCTAB_5G_ARRAYLENGTH]; +#define AGCTAB_2G_ARRAYLENGTH 194 +extern u32 rtl8192de_agctab_2garray[AGCTAB_2G_ARRAYLENGTH]; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c new file mode 100644 index 000000000000..dc86fcb0b3a3 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -0,0 +1,959 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "trx.h" +#include "led.h" + +static u8 _rtl92de_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) +{ + __le16 fc = rtl_get_fc(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return QSLT_BEACON; + if (ieee80211_is_mgmt(fc)) + return QSLT_MGNT; + + return skb->priority; +} + +static int _rtl92de_rate_mapping(bool isht, u8 desc_rate) +{ + int rate_idx; + + if (false == isht) { + switch (desc_rate) { + case DESC92D_RATE1M: + rate_idx = 0; + break; + case DESC92D_RATE2M: + rate_idx = 1; + break; + case DESC92D_RATE5_5M: + rate_idx = 2; + break; + case DESC92D_RATE11M: + rate_idx = 3; + break; + case DESC92D_RATE6M: + rate_idx = 4; + break; + case DESC92D_RATE9M: + rate_idx = 5; + break; + case DESC92D_RATE12M: + rate_idx = 6; + break; + case DESC92D_RATE18M: + rate_idx = 7; + break; + case DESC92D_RATE24M: + rate_idx = 8; + break; + case DESC92D_RATE36M: + rate_idx = 9; + break; + case DESC92D_RATE48M: + rate_idx = 10; + break; + case DESC92D_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 0; + break; + } + return rate_idx; + } else { + switch (desc_rate) { + case DESC92D_RATE1M: + rate_idx = 0; + break; + case DESC92D_RATE2M: + rate_idx = 1; + break; + case DESC92D_RATE5_5M: + rate_idx = 2; + break; + case DESC92D_RATE11M: + rate_idx = 3; + break; + case DESC92D_RATE6M: + rate_idx = 4; + break; + case DESC92D_RATE9M: + rate_idx = 5; + break; + case DESC92D_RATE12M: + rate_idx = 6; + break; + case DESC92D_RATE18M: + rate_idx = 7; + break; + case DESC92D_RATE24M: + rate_idx = 8; + break; + case DESC92D_RATE36M: + rate_idx = 9; + break; + case DESC92D_RATE48M: + rate_idx = 10; + break; + case DESC92D_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 11; + break; + } + return rate_idx; + } +} + +static u8 _rtl92d_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +static u8 _rtl92d_evm_db_to_percentage(char value) +{ + char ret_val = value; + + if (ret_val >= 0) + ret_val = 0; + if (ret_val <= -33) + ret_val = -33; + ret_val = 0 - ret_val; + ret_val *= 3; + if (ret_val == 99) + ret_val = 100; + return ret_val; +} + +static long _rtl92de_translate_todbm(struct ieee80211_hw *hw, + u8 signal_strength_index) +{ + long signal_power; + + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + return signal_power; +} + +static long _rtl92de_signal_scale_mapping(struct ieee80211_hw *hw, long currsig) +{ + long retsig; + + if (currsig >= 61 && currsig <= 100) + retsig = 90 + ((currsig - 60) / 4); + else if (currsig >= 41 && currsig <= 60) + retsig = 78 + ((currsig - 40) / 2); + else if (currsig >= 31 && currsig <= 40) + retsig = 66 + (currsig - 30); + else if (currsig >= 21 && currsig <= 30) + retsig = 54 + (currsig - 20); + else if (currsig >= 5 && currsig <= 20) + retsig = 42 + (((currsig - 5) * 2) / 3); + else if (currsig == 4) + retsig = 36; + else if (currsig == 3) + retsig = 27; + else if (currsig == 2) + retsig = 18; + else if (currsig == 1) + retsig = 9; + else + retsig = currsig; + return retsig; +} + +static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstats, + struct rx_desc_92d *pdesc, + struct rx_fwinfo_92d *p_drvinfo, + bool packet_match_bssid, + bool packet_toself, + bool packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + struct phy_sts_cck_8192d *cck_buf; + s8 rx_pwr_all, rx_pwr[4]; + u8 rf_rx_num = 0, evm, pwdb_all; + u8 i, max_spatial_stream; + u32 rssi, total_rssi = 0; + bool is_cck_rate; + + is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); + pstats->packet_matchbssid = packet_match_bssid; + pstats->packet_toself = packet_toself; + pstats->packet_beacon = packet_beacon; + pstats->is_cck = is_cck_rate; + pstats->rx_mimo_signalquality[0] = -1; + pstats->rx_mimo_signalquality[1] = -1; + + if (is_cck_rate) { + u8 report, cck_highpwr; + cck_buf = (struct phy_sts_cck_8192d *)p_drvinfo; + if (ppsc->rfpwr_state == ERFON) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + BIT(9)); + else + cck_highpwr = false; + if (!cck_highpwr) { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = cck_buf->cck_agc_rpt & 0xc0; + report = report >> 6; + switch (report) { + case 0x3: + rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); + break; + } + } else { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = p_drvinfo->cfosho[0] & 0x60; + report = report >> 5; + switch (report) { + case 0x3: + rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1); + break; + } + } + pwdb_all = _rtl92d_query_rxpwrpercentage(rx_pwr_all); + /* CCK gain is smaller than OFDM/MCS gain, */ + /* so we add gain diff by experiences, the val is 6 */ + pwdb_all += 6; + if (pwdb_all > 100) + pwdb_all = 100; + /* modify the offset to make the same gain index with OFDM. */ + if (pwdb_all > 34 && pwdb_all <= 42) + pwdb_all -= 2; + else if (pwdb_all > 26 && pwdb_all <= 34) + pwdb_all -= 6; + else if (pwdb_all > 14 && pwdb_all <= 26) + pwdb_all -= 8; + else if (pwdb_all > 4 && pwdb_all <= 14) + pwdb_all -= 4; + pstats->rx_pwdb_all = pwdb_all; + pstats->recvsignalpower = rx_pwr_all; + if (packet_match_bssid) { + u8 sq; + if (pstats->rx_pwdb_all > 40) { + sq = 100; + } else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + pstats->signalquality = sq; + pstats->rx_mimo_signalquality[0] = sq; + pstats->rx_mimo_signalquality[1] = -1; + } + } else { + rtlpriv->dm.rfpath_rxenable[0] = true; + rtlpriv->dm.rfpath_rxenable[1] = true; + for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) { + if (rtlpriv->dm.rfpath_rxenable[i]) + rf_rx_num++; + rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f) * 2) + - 110; + rssi = _rtl92d_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + rtlpriv->stats.rx_snr_db[i] = + (long)(p_drvinfo->rxsnr[i] / 2); + if (packet_match_bssid) + pstats->rx_mimo_signalstrength[i] = (u8) rssi; + } + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 106; + pwdb_all = _rtl92d_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->rxpower = rx_pwr_all; + pstats->recvsignalpower = rx_pwr_all; + if (pdesc->rxht && pdesc->rxmcs >= DESC92D_RATEMCS8 && + pdesc->rxmcs <= DESC92D_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + for (i = 0; i < max_spatial_stream; i++) { + evm = _rtl92d_evm_db_to_percentage(p_drvinfo->rxevm[i]); + if (packet_match_bssid) { + if (i == 0) + pstats->signalquality = + (u8)(evm & 0xff); + pstats->rx_mimo_signalquality[i] = + (u8)(evm & 0xff); + } + } + } + if (is_cck_rate) + pstats->signalstrength = (u8)(_rtl92de_signal_scale_mapping(hw, + pwdb_all)); + else if (rf_rx_num != 0) + pstats->signalstrength = (u8)(_rtl92de_signal_scale_mapping(hw, + total_rssi /= rf_rx_num)); +} + +static void rtl92d_loop_over_paths(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + pstats->rx_mimo_signalstrength[rfpath]; + + } + if (pstats->rx_mimo_signalstrength[rfpath] > + rtlpriv->stats.rx_rssi_percentage[rfpath]) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + rtlpriv->stats.rx_rssi_percentage[rfpath] = + rtlpriv->stats.rx_rssi_percentage[rfpath] + 1; + } else { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + } +} + +static void _rtl92de_process_ui_rssi(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_rssi, tmpval; + + if (pstats->packet_toself || pstats->packet_beacon) { + rtlpriv->stats.rssi_calculate_cnt++; + if (rtlpriv->stats.ui_rssi.total_num++ >= + PHY_RSSI_SLID_WIN_MAX) { + rtlpriv->stats.ui_rssi.total_num = + PHY_RSSI_SLID_WIN_MAX; + last_rssi = rtlpriv->stats.ui_rssi.elements[ + rtlpriv->stats.ui_rssi.index]; + rtlpriv->stats.ui_rssi.total_val -= last_rssi; + } + rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength; + rtlpriv->stats.ui_rssi.elements + [rtlpriv->stats.ui_rssi.index++] = + pstats->signalstrength; + if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) + rtlpriv->stats.ui_rssi.index = 0; + tmpval = rtlpriv->stats.ui_rssi.total_val / + rtlpriv->stats.ui_rssi.total_num; + rtlpriv->stats.signal_strength = _rtl92de_translate_todbm(hw, + (u8) tmpval); + pstats->rssi = rtlpriv->stats.signal_strength; + } + if (!pstats->is_cck && pstats->packet_toself) + rtl92d_loop_over_paths(hw, pstats); +} + +static void _rtl92de_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; + if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * + 5 + pstats->recvsignalpower + weighting) / 6; +} + +static void _rtl92de_process_pwdb(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if (mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_AP) + return; + else + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + + if (pstats->packet_toself || pstats->packet_beacon) { + if (undecorated_smoothed_pwdb < 0) + undecorated_smoothed_pwdb = pstats->rx_pwdb_all; + if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb + 1; + } else { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + } + rtlpriv->dm.undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb; + _rtl92de_update_rxsignalstatistics(hw, pstats); + } +} + +static void rtl92d_loop_over_streams(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int stream; + + for (stream = 0; stream < 2; stream++) { + if (pstats->rx_mimo_signalquality[stream] != -1) { + if (rtlpriv->stats.rx_evm_percentage[stream] == 0) { + rtlpriv->stats.rx_evm_percentage[stream] = + pstats->rx_mimo_signalquality[stream]; + } + rtlpriv->stats.rx_evm_percentage[stream] = + ((rtlpriv->stats.rx_evm_percentage[stream] + * (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalquality[stream] * 1)) / + (RX_SMOOTH_FACTOR); + } + } +} + +static void _rtl92de_process_ui_link_quality(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm, tmpval; + + if (pstats->signalquality == 0) + return; + if (pstats->packet_toself || pstats->packet_beacon) { + if (rtlpriv->stats.ui_link_quality.total_num++ >= + PHY_LINKQUALITY_SLID_WIN_MAX) { + rtlpriv->stats.ui_link_quality.total_num = + PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index]; + rtlpriv->stats.ui_link_quality.total_val -= last_evm; + } + rtlpriv->stats.ui_link_quality.total_val += + pstats->signalquality; + rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index++] = + pstats->signalquality; + if (rtlpriv->stats.ui_link_quality.index >= + PHY_LINKQUALITY_SLID_WIN_MAX) + rtlpriv->stats.ui_link_quality.index = 0; + tmpval = rtlpriv->stats.ui_link_quality.total_val / + rtlpriv->stats.ui_link_quality.total_num; + rtlpriv->stats.signal_quality = tmpval; + rtlpriv->stats.last_sigstrength_inpercent = tmpval; + rtl92d_loop_over_streams(hw, pstats); + } +} + +static void _rtl92de_process_phyinfo(struct ieee80211_hw *hw, + u8 *buffer, + struct rtl_stats *pcurrent_stats) +{ + + if (!pcurrent_stats->packet_matchbssid && + !pcurrent_stats->packet_beacon) + return; + + _rtl92de_process_ui_rssi(hw, pcurrent_stats); + _rtl92de_process_pwdb(hw, pcurrent_stats); + _rtl92de_process_ui_link_quality(hw, pcurrent_stats); +} + +static void _rtl92de_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_stats *pstats, + struct rx_desc_92d *pdesc, + struct rx_fwinfo_92d *p_drvinfo) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct ieee80211_hdr *hdr; + u8 *tmp_buf; + u8 *praddr; + u16 type, cfc; + __le16 fc; + bool packet_matchbssid, packet_toself, packet_beacon; + + tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; + hdr = (struct ieee80211_hdr *)tmp_buf; + fc = hdr->frame_control; + cfc = le16_to_cpu(fc); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && + (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ? + hdr->addr1 : (cfc & IEEE80211_FCTL_FROMDS) ? + hdr->addr2 : hdr->addr3)) && (!pstats->hwerror) && + (!pstats->crc) && (!pstats->icv)); + packet_toself = packet_matchbssid && + (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + if (ieee80211_is_beacon(fc)) + packet_beacon = true; + _rtl92de_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, + packet_matchbssid, packet_toself, + packet_beacon); + _rtl92de_process_phyinfo(hw, tmp_buf, pstats); +} + +bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *p_desc, struct sk_buff *skb) +{ + struct rx_fwinfo_92d *p_drvinfo; + struct rx_desc_92d *pdesc = (struct rx_desc_92d *)p_desc; + u32 phystatus = GET_RX_DESC_PHYST(pdesc); + + stats->length = (u16) GET_RX_DESC_PKT_LEN(pdesc); + stats->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) * + RX_DRV_INFO_SIZE_UNIT; + stats->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03); + stats->icv = (u16) GET_RX_DESC_ICV(pdesc); + stats->crc = (u16) GET_RX_DESC_CRC32(pdesc); + stats->hwerror = (stats->crc | stats->icv); + stats->decrypted = !GET_RX_DESC_SWDEC(pdesc); + stats->rate = (u8) GET_RX_DESC_RXMCS(pdesc); + stats->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc); + stats->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); + stats->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) + && (GET_RX_DESC_FAGGR(pdesc) == 1)); + stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); + stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + rx_status->freq = hw->conf.channel->center_freq; + rx_status->band = hw->conf.channel->band; + if (GET_RX_DESC_CRC32(pdesc)) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (!GET_RX_DESC_SWDEC(pdesc)) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (GET_RX_DESC_BW(pdesc)) + rx_status->flag |= RX_FLAG_40MHZ; + if (GET_RX_DESC_RXHT(pdesc)) + rx_status->flag |= RX_FLAG_HT; + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + if (stats->decrypted) + rx_status->flag |= RX_FLAG_DECRYPTED; + rx_status->rate_idx = _rtl92de_rate_mapping((bool) + GET_RX_DESC_RXHT(pdesc), + (u8) + GET_RX_DESC_RXMCS(pdesc)); + rx_status->mactime = GET_RX_DESC_TSFL(pdesc); + if (phystatus) { + p_drvinfo = (struct rx_fwinfo_92d *)(skb->data + + stats->rx_bufshift); + _rtl92de_translate_rx_signal_stuff(hw, + skb, stats, pdesc, + p_drvinfo); + } + /*rx_status->qual = stats->signal; */ + rx_status->signal = stats->rssi + 10; + /*rx_status->noise = -stats->noise; */ + return true; +} + +static void _rtl92de_insert_emcontent(struct rtl_tcb_desc *ptcb_desc, + u8 *virtualaddress) +{ + memset(virtualaddress, 0, 8); + + SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num); + SET_EARLYMODE_LEN0(virtualaddress, ptcb_desc->empkt_len[0]); + SET_EARLYMODE_LEN1(virtualaddress, ptcb_desc->empkt_len[1]); + SET_EARLYMODE_LEN2_1(virtualaddress, ptcb_desc->empkt_len[2] & 0xF); + SET_EARLYMODE_LEN2_2(virtualaddress, ptcb_desc->empkt_len[2] >> 4); + SET_EARLYMODE_LEN3(virtualaddress, ptcb_desc->empkt_len[3]); + SET_EARLYMODE_LEN4(virtualaddress, ptcb_desc->empkt_len[4]); +} + +void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct ieee80211_sta *sta = info->control.sta; + u8 *pdesc = (u8 *) pdesc_tx; + u16 seq_number; + __le16 fc = hdr->frame_control; + unsigned int buf_len = 0; + unsigned int skb_len = skb->len; + u8 fw_qsel = _rtl92de_map_hwqueue_to_fwqueue(skb, hw_queue); + bool firstseg = ((hdr->seq_ctrl & + cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); + bool lastseg = ((hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); + dma_addr_t mapping; + u8 bw_40 = 0; + + if (mac->opmode == NL80211_IFTYPE_STATION) { + bw_40 = mac->bw_40; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) + bw_40 = sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); + /* reserve 8 byte for AMPDU early mode */ + if (rtlhal->earlymode_enable) { + skb_push(skb, EM_HDR_LEN); + memset(skb->data, 0, EM_HDR_LEN); + } + buf_len = skb->len; + mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92d)); + if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { + firstseg = true; + lastseg = true; + } + if (firstseg) { + if (rtlhal->earlymode_enable) { + SET_TX_DESC_PKT_OFFSET(pdesc, 1); + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN + + EM_HDR_LEN); + if (ptcb_desc->empkt_num) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_LOUD, + ("Insert 8 byte.pTcb->EMPktNum:%d\n", + ptcb_desc->empkt_num)); + _rtl92de_insert_emcontent(ptcb_desc, + (u8 *)(skb->data)); + } + } else { + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + } + /* 5G have no CCK rate */ + if (rtlhal->current_bandtype == BAND_ON_5G) + if (ptcb_desc->hw_rate < DESC92D_RATE6M) + ptcb_desc->hw_rate = DESC92D_RATE6M; + SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) + SET_TX_DESC_DATA_SHORTGI(pdesc, 1); + + if (rtlhal->macphymode == DUALMAC_DUALPHY && + ptcb_desc->hw_rate == DESC92D_RATEMCS7) + SET_TX_DESC_DATA_SHORTGI(pdesc, 1); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + SET_TX_DESC_AGG_ENABLE(pdesc, 1); + SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); + } + SET_TX_DESC_SEQ(pdesc, seq_number); + SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable && + !ptcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable + || ptcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); + /* 5G have no CCK rate */ + if (rtlhal->current_bandtype == BAND_ON_5G) + if (ptcb_desc->rts_rate < DESC92D_RATE6M) + ptcb_desc->rts_rate = DESC92D_RATE6M; + SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); + SET_TX_DESC_RTS_BW(pdesc, 0); + SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= + DESC92D_RATE54M) ? + (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : + (ptcb_desc->rts_use_shortgi ? 1 : 0))); + if (bw_40) { + if (ptcb_desc->packet_bw) { + SET_TX_DESC_DATA_BW(pdesc, 1); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); + } else { + SET_TX_DESC_DATA_BW(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, + mac->cur_40_prime_sc); + } + } else { + SET_TX_DESC_DATA_BW(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + } + SET_TX_DESC_LINIP(pdesc, 0); + SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb_len); + if (sta) { + u8 ampdu_density = sta->ht_cap.ampdu_density; + SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); + } + if (info->control.hw_key) { + struct ieee80211_key_conf *keyconf; + + keyconf = info->control.hw_key; + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + break; + case WLAN_CIPHER_SUITE_CCMP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + break; + default: + SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + break; + + } + } + SET_TX_DESC_PKT_ID(pdesc, 0); + SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); + SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ? + 1 : 0); + SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0); + + /* Set TxRate and RTSRate in TxDesc */ + /* This prevent Tx initial rate of new-coming packets */ + /* from being overwritten by retried packet rate.*/ + if (!ptcb_desc->use_driver_rate) { + SET_TX_DESC_RTS_RATE(pdesc, 0x08); + /* SET_TX_DESC_TX_RATE(pdesc, 0x0b); */ + } + if (ieee80211_is_data_qos(fc)) { + if (mac->rdg_en) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + ("Enable RDG function.\n")); + SET_TX_DESC_RDG_ENABLE(pdesc, 1); + SET_TX_DESC_HTC(pdesc, 1); + } + } + } + + SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); + SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + if (rtlpriv->dm.useramask) { + SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + } else { + SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, ptcb_desc->ratr_index); + } + if (ieee80211_is_data_qos(fc)) + SET_TX_DESC_QOS(pdesc, 1); + + if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_PKT_ID(pdesc, 8); + } + SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1)); + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, ("\n")); +} + +void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, + u8 *pdesc, bool firstseg, + bool lastseg, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 fw_queue = QSLT_BEACON; + dma_addr_t mapping = pci_map_single(rtlpci->pdev, + skb->data, skb->len, PCI_DMA_TODEVICE); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + __le16 fc = hdr->frame_control; + + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); + if (firstseg) + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + /* 5G have no CCK rate + * Caution: The macros below are multi-line expansions. + * The braces are needed no matter what checkpatch says + */ + if (rtlhal->current_bandtype == BAND_ON_5G) { + SET_TX_DESC_TX_RATE(pdesc, DESC92D_RATE6M); + } else { + SET_TX_DESC_TX_RATE(pdesc, DESC92D_RATE1M); + } + SET_TX_DESC_SEQ(pdesc, 0); + SET_TX_DESC_LINIP(pdesc, 0); + SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue); + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + SET_TX_DESC_RATE_ID(pdesc, 7); + SET_TX_DESC_MACID(pdesc, 0); + SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len)); + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + SET_TX_DESC_OFFSET(pdesc, 0x20); + SET_TX_DESC_USE_RATE(pdesc, 1); + + if (!ieee80211_is_data_qos(fc) && ppsc->fwctrl_lps) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_PKT_ID(pdesc, 8); + } + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "H2C Tx Cmd Content\n", pdesc, TX_DESC_SIZE); + wmb(); + SET_TX_DESC_OWN(pdesc, 1); +} + +void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + wmb(); + SET_TX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_TX_NEXTDESC_ADDR: + SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); + break; + default: + RT_ASSERT(false, ("ERR txdesc :%d" + " not process\n", desc_name)); + break; + } + } else { + switch (desc_name) { + case HW_DESC_RXOWN: + wmb(); + SET_RX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_RXBUFF_ADDR: + SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *) val); + break; + case HW_DESC_RXPKT_LEN: + SET_RX_DESC_PKT_LEN(pdesc, *(u32 *) val); + break; + case HW_DESC_RXERO: + SET_RX_DESC_EOR(pdesc, 1); + break; + default: + RT_ASSERT(false, ("ERR rxdesc :%d " + "not process\n", desc_name)); + break; + } + } +} + +u32 rtl92de_get_desc(u8 *p_desc, bool istx, u8 desc_name) +{ + u32 ret = 0; + + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_TX_DESC_OWN(p_desc); + break; + case HW_DESC_TXBUFF_ADDR: + ret = GET_TX_DESC_TX_BUFFER_ADDRESS(p_desc); + break; + default: + RT_ASSERT(false, ("ERR txdesc :%d " + "not process\n", desc_name)); + break; + } + } else { + struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc; + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_RX_DESC_OWN(pdesc); + break; + case HW_DESC_RXPKT_LEN: + ret = GET_RX_DESC_PKT_LEN(pdesc); + break; + default: + RT_ASSERT(false, ("ERR rxdesc :%d " + "not process\n", desc_name)); + break; + } + } + return ret; +} + +void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (hw_queue == BEACON_QUEUE) + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4)); + else + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, + BIT(0) << (hw_queue)); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h new file mode 100644 index 000000000000..992d6766e667 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h @@ -0,0 +1,756 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * 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. + * + * 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, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92DE_TRX_H__ +#define __RTL92DE_TRX_H__ + +#define TX_DESC_SIZE 64 +#define TX_DESC_AGGR_SUBFRAME_SIZE 32 + +#define RX_DESC_SIZE 32 +#define RX_DRV_INFO_SIZE_UNIT 8 + +#define TX_DESC_NEXT_DESC_OFFSET 40 +#define USB_HWDESC_HEADER_LEN 32 +#define CRCLENGTH 4 + +/* Define a macro that takes a le32 word, converts it to host ordering, + * right shifts by a specified count, creates a mask of the specified + * bit count, and extracts that number of bits. + */ + +#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ + ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ + BIT_LEN_MASK_32(__mask)) + +/* Define a macro that clears a bit field in an le32 word and + * sets the specified value into that bit field. The resulting + * value remains in le32 ordering; however, it is properly converted + * to host ordering for the clear and set operations before conversion + * back to le32. + */ + +#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ + (*(__le32 *)(__pdesc) = \ + (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ + (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ + (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); + +/* macros to read/write various fields in RX or TX descriptors */ + +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_BMC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 25, 1, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GF(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_PKT_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 0, 16) +#define GET_TX_DESC_OFFSET(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 16, 8) +#define GET_TX_DESC_BMC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 24, 1) +#define GET_TX_DESC_HTC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 25, 1) +#define GET_TX_DESC_LAST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 26, 1) +#define GET_TX_DESC_FIRST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 27, 1) +#define GET_TX_DESC_LINIP(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 28, 1) +#define GET_TX_DESC_NO_ACM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 29, 1) +#define GET_TX_DESC_GF(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 30, 1) +#define GET_TX_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +#define SET_TX_DESC_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 0, 5, __val) +#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 5, 1, __val) +#define SET_TX_DESC_BK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 6, 1, __val) +#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 7, 1, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 8, 5, __val) +#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 13, 1, __val) +#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 14, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 15, 1, __val) +#define SET_TX_DESC_RATE_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 16, 4, __val) +#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 20, 1, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 22, 2, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+4, 26, 8, __val) + +#define GET_TX_DESC_MACID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 0, 5) +#define GET_TX_DESC_AGG_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 5, 1) +#define GET_TX_DESC_AGG_BREAK(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 6, 1) +#define GET_TX_DESC_RDG_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 7, 1) +#define GET_TX_DESC_QUEUE_SEL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 8, 5) +#define GET_TX_DESC_RDG_NAV_EXT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 13, 1) +#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 14, 1) +#define GET_TX_DESC_PIFS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 15, 1) +#define GET_TX_DESC_RATE_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 16, 4) +#define GET_TX_DESC_NAV_USE_HDR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 20, 1) +#define GET_TX_DESC_EN_DESC_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 21, 1) +#define GET_TX_DESC_SEC_TYPE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 22, 2) +#define GET_TX_DESC_PKT_OFFSET(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 24, 8) + +#define SET_TX_DESC_RTS_RC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 0, 6, __val) +#define SET_TX_DESC_DATA_RC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 6, 6, __val) +#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 14, 2, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 17, 1, __val) +#define SET_TX_DESC_RAW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 18, 1, __val) +#define SET_TX_DESC_CCX(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 19, 1, __val) +#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 20, 3, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 24, 1, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 25, 1, __val) +#define SET_TX_DESC_TX_ANT_CCK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 26, 2, __val) +#define SET_TX_DESC_TX_ANTL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 28, 2, __val) +#define SET_TX_DESC_TX_ANT_HT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+8, 30, 2, __val) + +#define GET_TX_DESC_RTS_RC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 0, 6) +#define GET_TX_DESC_DATA_RC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 6, 6) +#define GET_TX_DESC_BAR_RTY_TH(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 14, 2) +#define GET_TX_DESC_MORE_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 17, 1) +#define GET_TX_DESC_RAW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 18, 1) +#define GET_TX_DESC_CCX(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 19, 1) +#define GET_TX_DESC_AMPDU_DENSITY(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 20, 3) +#define GET_TX_DESC_ANTSEL_A(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 24, 1) +#define GET_TX_DESC_ANTSEL_B(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 25, 1) +#define GET_TX_DESC_TX_ANT_CCK(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 26, 2) +#define GET_TX_DESC_TX_ANTL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 28, 2) +#define GET_TX_DESC_TX_ANT_HT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 30, 2) + +#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 0, 8, __val) +#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 8, 8, __val) +#define SET_TX_DESC_SEQ(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 16, 12, __val) +#define SET_TX_DESC_PKT_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+12, 28, 4, __val) + +#define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 0, 8) +#define GET_TX_DESC_TAIL_PAGE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 8, 8) +#define GET_TX_DESC_SEQ(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 16, 12) +#define GET_TX_DESC_PKT_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 28, 4) + +#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 0, 5, __val) +#define SET_TX_DESC_AP_DCFE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 5, 1, __val) +#define SET_TX_DESC_QOS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 6, 1, __val) +#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 7, 1, __val) +#define SET_TX_DESC_USE_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 8, 1, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 9, 1, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 10, 1, __val) +#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 12, 1, __val) +#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 13, 1, __val) +#define SET_TX_DESC_PORT_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 14, 1, __val) +#define SET_TX_DESC_WAIT_DCTS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 18, 1, __val) +#define SET_TX_DESC_CTS2AP_EN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 19, 1, __val) +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 20, 2, __val) +#define SET_TX_DESC_TX_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 22, 2, __val) +#define SET_TX_DESC_DATA_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 24, 1, __val) +#define SET_TX_DESC_DATA_BW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 25, 1, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 26, 1, __val) +#define SET_TX_DESC_RTS_BW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 27, 1, __val) +#define SET_TX_DESC_RTS_SC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 28, 2, __val) +#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+16, 30, 2, __val) + +#define GET_TX_DESC_RTS_RATE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 0, 5) +#define GET_TX_DESC_AP_DCFE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 5, 1) +#define GET_TX_DESC_QOS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 6, 1) +#define GET_TX_DESC_HWSEQ_EN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 7, 1) +#define GET_TX_DESC_USE_RATE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 8, 1) +#define GET_TX_DESC_DISABLE_RTS_FB(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 9, 1) +#define GET_TX_DESC_DISABLE_FB(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 10, 1) +#define GET_TX_DESC_CTS2SELF(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 11, 1) +#define GET_TX_DESC_RTS_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 12, 1) +#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 13, 1) +#define GET_TX_DESC_PORT_ID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 14, 1) +#define GET_TX_DESC_WAIT_DCTS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 18, 1) +#define GET_TX_DESC_CTS2AP_EN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 19, 1) +#define GET_TX_DESC_TX_SUB_CARRIER(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 20, 2) +#define GET_TX_DESC_TX_STBC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 22, 2) +#define GET_TX_DESC_DATA_SHORT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 24, 1) +#define GET_TX_DESC_DATA_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 25, 1) +#define GET_TX_DESC_RTS_SHORT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 26, 1) +#define GET_TX_DESC_RTS_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 27, 1) +#define GET_TX_DESC_RTS_SC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 28, 2) +#define GET_TX_DESC_RTS_STBC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 30, 2) + +#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 0, 6, __val) +#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 6, 1, __val) +#define SET_TX_DESC_CCX_TAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 7, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 8, 5, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 17, 1, __val) +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 18, 6, __val) +#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+20, 24, 8, __val) + +#define GET_TX_DESC_TX_RATE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 0, 6) +#define GET_TX_DESC_DATA_SHORTGI(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 6, 1) +#define GET_TX_DESC_CCX_TAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 7, 1) +#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 8, 5) +#define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 13, 4) +#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 17, 1) +#define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 18, 6) +#define GET_TX_DESC_USB_TXAGG_NUM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 24, 8) + +#define SET_TX_DESC_TXAGC_A(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 0, 5, __val) +#define SET_TX_DESC_TXAGC_B(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 5, 5, __val) +#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 10, 1, __val) +#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 11, 5, __val) +#define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 16, 4, __val) +#define SET_TX_DESC_MCSG2_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 20, 4, __val) +#define SET_TX_DESC_MCSG3_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 24, 4, __val) +#define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 28, 4, __val) + +#define GET_TX_DESC_TXAGC_A(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 0, 5) +#define GET_TX_DESC_TXAGC_B(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 5, 5) +#define GET_TX_DESC_USE_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 10, 1) +#define GET_TX_DESC_MAX_AGG_NUM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 11, 5) +#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 16, 4) +#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 20, 4) +#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 24, 4) +#define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 0, 16, __val) +#define SET_TX_DESC_MCSG4_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 16, 4, __val) +#define SET_TX_DESC_MCSG5_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 20, 4, __val) +#define SET_TX_DESC_MCSG6_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 24, 4, __val) +#define SET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 28, 4, __val) + +#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 0, 16) +#define GET_TX_DESC_MCSG4_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 16, 4) +#define GET_TX_DESC_MCSG5_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 20, 4) +#define GET_TX_DESC_MCSG6_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 24, 4) +#define GET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+32, 0, 32, __val) +#define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+36, 0, 32, __val) + +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+32, 0, 32) +#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+36, 0, 32) + +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+40, 0, 32, __val) +#define SET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+44, 0, 32, __val) + +#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+40, 0, 32) +#define GET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+44, 0, 32) + +#define GET_RX_DESC_PKT_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 0, 14) +#define GET_RX_DESC_CRC32(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 14, 1) +#define GET_RX_DESC_ICV(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 15, 1) +#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 16, 4) +#define GET_RX_DESC_SECURITY(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 20, 3) +#define GET_RX_DESC_QOS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 23, 1) +#define GET_RX_DESC_SHIFT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 24, 2) +#define GET_RX_DESC_PHYST(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 26, 1) +#define GET_RX_DESC_SWDEC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 27, 1) +#define GET_RX_DESC_LS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 28, 1) +#define GET_RX_DESC_FS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 29, 1) +#define GET_RX_DESC_EOR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 30, 1) +#define GET_RX_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) +#define SET_RX_DESC_EOR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_RX_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_RX_DESC_MACID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 0, 5) +#define GET_RX_DESC_TID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 5, 4) +#define GET_RX_DESC_HWRSVD(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 9, 5) +#define GET_RX_DESC_PAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 14, 1) +#define GET_RX_DESC_FAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 15, 1) +#define GET_RX_DESC_A1_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 16, 4) +#define GET_RX_DESC_A2_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 20, 4) +#define GET_RX_DESC_PAM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 24, 1) +#define GET_RX_DESC_PWR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 25, 1) +#define GET_RX_DESC_MD(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 26, 1) +#define GET_RX_DESC_MF(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 27, 1) +#define GET_RX_DESC_TYPE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 28, 2) +#define GET_RX_DESC_MC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 30, 1) +#define GET_RX_DESC_BC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+4, 31, 1) +#define GET_RX_DESC_SEQ(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 0, 12) +#define GET_RX_DESC_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 12, 4) +#define GET_RX_DESC_NEXT_PKT_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 16, 14) +#define GET_RX_DESC_NEXT_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 30, 1) +#define GET_RX_DESC_RSVD(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+8, 31, 1) + +#define GET_RX_DESC_RXMCS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 0, 6) +#define GET_RX_DESC_RXHT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 6, 1) +#define GET_RX_DESC_SPLCP(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 8, 1) +#define GET_RX_DESC_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 9, 1) +#define GET_RX_DESC_HTC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 10, 1) +#define GET_RX_DESC_HWPC_ERR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 14, 1) +#define GET_RX_DESC_HWPC_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 15, 1) +#define GET_RX_DESC_IV0(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+12, 16, 16) + +#define GET_RX_DESC_IV1(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+16, 0, 32) +#define GET_RX_DESC_TSFL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+20, 0, 32) + +#define GET_RX_DESC_BUFF_ADDR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+24, 0, 32) +#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc+28, 0, 32) + +#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+24, 0, 32, __val) +#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc+28, 0, 32, __val) + +#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ +do { \ + if (_size > TX_DESC_NEXT_DESC_OFFSET) \ + memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ + else \ + memset((void *)__pdesc, 0, _size); \ +} while (0); + +#define RX_HAL_IS_CCK_RATE(_pdesc)\ + (_pdesc->rxmcs == DESC92D_RATE1M || \ + _pdesc->rxmcs == DESC92D_RATE2M || \ + _pdesc->rxmcs == DESC92D_RATE5_5M || \ + _pdesc->rxmcs == DESC92D_RATE11M) + +/* For 92D early mode */ +#define SET_EARLYMODE_PKTNUM(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr, 0, 3, __value) +#define SET_EARLYMODE_LEN0(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr, 4, 12, __value) +#define SET_EARLYMODE_LEN1(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr, 16, 12, __value) +#define SET_EARLYMODE_LEN2_1(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr, 28, 4, __value) +#define SET_EARLYMODE_LEN2_2(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr+4, 0, 8, __value) +#define SET_EARLYMODE_LEN3(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr+4, 8, 12, __value) +#define SET_EARLYMODE_LEN4(__paddr, __value) \ + SET_BITS_OFFSET_LE(__paddr+4, 20, 12, __value) + +struct rx_fwinfo_92d { + u8 gain_trsw[4]; + u8 pwdb_all; + u8 cfosho[4]; + u8 cfotail[4]; + char rxevm[2]; + char rxsnr[4]; + u8 pdsnr[2]; + u8 csi_current[2]; + u8 csi_target[2]; + u8 sigevm; + u8 max_ex_pwr; + u8 ex_intf_flag:1; + u8 sgi_en:1; + u8 rxsc:2; + u8 reserve:4; +} __packed; + +struct tx_desc_92d { + u32 pktsize:16; + u32 offset:8; + u32 bmc:1; + u32 htc:1; + u32 lastseg:1; + u32 firstseg:1; + u32 linip:1; + u32 noacm:1; + u32 gf:1; + u32 own:1; + + u32 macid:5; + u32 agg_en:1; + u32 bk:1; + u32 rdg_en:1; + u32 queuesel:5; + u32 rd_nav_ext:1; + u32 lsig_txop_en:1; + u32 pifs:1; + u32 rateid:4; + u32 nav_usehdr:1; + u32 en_descid:1; + u32 sectype:2; + u32 pktoffset:8; + + u32 rts_rc:6; + u32 data_rc:6; + u32 rsvd0:2; + u32 bar_retryht:2; + u32 rsvd1:1; + u32 morefrag:1; + u32 raw:1; + u32 ccx:1; + u32 ampdudensity:3; + u32 rsvd2:1; + u32 ant_sela:1; + u32 ant_selb:1; + u32 txant_cck:2; + u32 txant_l:2; + u32 txant_ht:2; + + u32 nextheadpage:8; + u32 tailpage:8; + u32 seq:12; + u32 pktid:4; + + u32 rtsrate:5; + u32 apdcfe:1; + u32 qos:1; + u32 hwseq_enable:1; + u32 userrate:1; + u32 dis_rtsfb:1; + u32 dis_datafb:1; + u32 cts2self:1; + u32 rts_en:1; + u32 hwrts_en:1; + u32 portid:1; + u32 rsvd3:3; + u32 waitdcts:1; + u32 cts2ap_en:1; + u32 txsc:2; + u32 stbc:2; + u32 txshort:1; + u32 txbw:1; + u32 rtsshort:1; + u32 rtsbw:1; + u32 rtssc:2; + u32 rtsstbc:2; + + u32 txrate:6; + u32 shortgi:1; + u32 ccxt:1; + u32 txrate_fb_lmt:5; + u32 rtsrate_fb_lmt:4; + u32 retrylmt_en:1; + u32 txretrylmt:6; + u32 usb_txaggnum:8; + + u32 txagca:5; + u32 txagcb:5; + u32 usemaxlen:1; + u32 maxaggnum:5; + u32 mcsg1maxlen:4; + u32 mcsg2maxlen:4; + u32 mcsg3maxlen:4; + u32 mcs7sgimaxlen:4; + + u32 txbuffersize:16; + u32 mcsg4maxlen:4; + u32 mcsg5maxlen:4; + u32 mcsg6maxlen:4; + u32 mcsg15sgimaxlen:4; + + u32 txbuffaddr; + u32 txbufferaddr64; + u32 nextdescaddress; + u32 nextdescaddress64; + + u32 reserve_pass_pcie_mm_limit[4]; +} __packed; + +struct rx_desc_92d { + u32 length:14; + u32 crc32:1; + u32 icverror:1; + u32 drv_infosize:4; + u32 security:3; + u32 qos:1; + u32 shift:2; + u32 phystatus:1; + u32 swdec:1; + u32 lastseg:1; + u32 firstseg:1; + u32 eor:1; + u32 own:1; + + u32 macid:5; + u32 tid:4; + u32 hwrsvd:5; + u32 paggr:1; + u32 faggr:1; + u32 a1_fit:4; + u32 a2_fit:4; + u32 pam:1; + u32 pwr:1; + u32 moredata:1; + u32 morefrag:1; + u32 type:2; + u32 mc:1; + u32 bc:1; + + u32 seq:12; + u32 frag:4; + u32 nextpktlen:14; + u32 nextind:1; + u32 rsvd:1; + + u32 rxmcs:6; + u32 rxht:1; + u32 amsdu:1; + u32 splcp:1; + u32 bandwidth:1; + u32 htc:1; + u32 tcpchk_rpt:1; + u32 ipcchk_rpt:1; + u32 tcpchk_valid:1; + u32 hwpcerr:1; + u32 hwpcind:1; + u32 iv0:16; + + u32 iv1; + + u32 tsfl; + + u32 bufferaddress; + u32 bufferaddress64; + +} __packed; + +void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, + u8 *pdesc, struct ieee80211_tx_info *info, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); +bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, + u8 *pdesc, struct sk_buff *skb); +void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl92de_get_desc(u8 *pdesc, bool istx, u8 desc_name); +void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); +void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool b_firstseg, bool b_lastseg, + struct sk_buff *skb); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 13da7b3c0202..b1d0213dc60e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -1214,8 +1214,6 @@ void rtl92se_enable_interrupt(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]); /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */ rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F); - - rtlpci->irq_enabled = true; } void rtl92se_disable_interrupt(struct ieee80211_hw *hw) @@ -1226,7 +1224,6 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, INTA_MASK, 0); rtl_write_dword(rtlpriv, INTA_MASK + 4, 0); - rtlpci->irq_enabled = false; synchronize_irq(rtlpci->pdev->irq); } diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index c54cda5ce22a..491e97fc0343 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -303,9 +303,6 @@ enum hw_variables { HW_VAR_DATA_FILTER, }; -#define HWSET_MAX_SIZE 128 -#define EFUSE_MAX_SECTION 16 - enum _RT_MEDIA_STATUS { RT_MEDIA_DISCONNECT = 0, RT_MEDIA_CONNECT = 1 diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 35ce7b0f4a60..07bcb1548d8b 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -11,7 +11,6 @@ config WL12XX depends on WL12XX_MENU && GENERIC_HARDIRQS depends on INET select FW_LOADER - select CRC7 ---help--- This module adds support for wireless adapters based on TI wl1271 and TI wl1273 chipsets. This module does *not* include support for wl1251. @@ -33,6 +32,7 @@ config WL12XX_HT config WL12XX_SPI tristate "TI wl12xx SPI support" depends on WL12XX && SPI_MASTER + select CRC7 ---help--- This module adds support for the SPI interface of adapters using TI wl12xx chipsets. Select this if your platform is using diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index c6ee530e5bf7..7e33f1f4f3d4 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -25,7 +25,6 @@ #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/crc7.h> #include <linux/spi/spi.h> #include <linux/slab.h> @@ -91,7 +90,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power) struct acx_current_tx_power *acx; int ret; - wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr %d", power); if (power < 0 || power > 25) return -EINVAL; @@ -1068,6 +1067,7 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) mem_conf->tx_free_req = mem->min_req_tx_blocks; mem_conf->rx_free_req = mem->min_req_rx_blocks; mem_conf->tx_min = mem->tx_min; + mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks; ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); @@ -1577,22 +1577,69 @@ out: return ret; } -int wl1271_acx_max_tx_retry(struct wl1271 *wl) +int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable) { - struct wl1271_acx_max_tx_retry *acx = NULL; + struct wl1271_acx_ps_rx_streaming *rx_streaming; + u32 conf_queues, enable_queues; + int i, ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ps rx streaming"); + + rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL); + if (!rx_streaming) { + ret = -ENOMEM; + goto out; + } + + conf_queues = wl->conf.rx_streaming.queues; + if (enable) + enable_queues = conf_queues; + else + enable_queues = 0; + + for (i = 0; i < 8; i++) { + /* + * Skip non-changed queues, to avoid redundant acxs. + * this check assumes conf.rx_streaming.queues can't + * be changed while rx_streaming is enabled. + */ + if (!(conf_queues & BIT(i))) + continue; + + rx_streaming->tid = i; + rx_streaming->enable = enable_queues & BIT(i); + rx_streaming->period = wl->conf.rx_streaming.interval; + rx_streaming->timeout = wl->conf.rx_streaming.interval; + + ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING, + rx_streaming, + sizeof(*rx_streaming)); + if (ret < 0) { + wl1271_warning("acx ps rx streaming failed: %d", ret); + goto out; + } + } +out: + kfree(rx_streaming); + return ret; +} + +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl) +{ + struct wl1271_acx_ap_max_tx_retry *acx = NULL; int ret; - wl1271_debug(DEBUG_ACX, "acx max tx retry"); + wl1271_debug(DEBUG_ACX, "acx ap max tx retry"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) return -ENOMEM; - acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); + acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); if (ret < 0) { - wl1271_warning("acx max tx retry failed: %d", ret); + wl1271_warning("acx ap max tx retry failed: %d", ret); goto out; } diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 9a895e3cc613..d2eb86eccc04 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -828,6 +828,8 @@ struct wl1271_acx_sta_config_memory { u8 tx_free_req; u8 rx_free_req; u8 tx_min; + u8 fwlog_blocks; + u8 padding[3]; } __packed; struct wl1271_acx_mem_map { @@ -1153,7 +1155,20 @@ struct wl1271_acx_fw_tsf_information { u8 padding[3]; } __packed; -struct wl1271_acx_max_tx_retry { +struct wl1271_acx_ps_rx_streaming { + struct acx_header header; + + u8 tid; + u8 enable; + + /* interval between triggers (10-100 msec) */ + u8 period; + + /* timeout before first trigger (0-200 msec) */ + u8 timeout; +} __packed; + +struct wl1271_acx_ap_max_tx_retry { struct acx_header header; /* @@ -1384,7 +1399,8 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl, int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); -int wl1271_acx_max_tx_retry(struct wl1271 *wl); +int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable); +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable); diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 7ccec07a600c..5ebc64d89407 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -102,6 +102,33 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); } +static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl) +{ + unsigned int quirks = 0; + unsigned int *fw_ver = wl->chip.fw_ver; + + /* Only for wl127x */ + if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) && + /* Check STA version */ + (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) || + /* Check AP version */ + ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN)))) + quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS; + + /* Only new station firmwares support routing fw logs to the host */ + if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN)) + quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED; + + /* This feature is not yet supported for AP mode */ + if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) + quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED; + + return quirks; +} + static void wl1271_parse_fw_ver(struct wl1271 *wl) { int ret; @@ -116,6 +143,9 @@ static void wl1271_parse_fw_ver(struct wl1271 *wl) memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); return; } + + /* Check if any quirks are needed with older fw versions */ + wl->quirks |= wl12xx_get_fw_ver_quirks(wl); } static void wl1271_boot_fw_version(struct wl1271 *wl) @@ -483,7 +513,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) PERIODIC_SCAN_COMPLETE_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; + wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID | + INACTIVE_STA_EVENT_ID | + MAX_TX_RETRY_EVENT_ID; else wl->event_mask |= DUMMY_PACKET_EVENT_ID | BA_SESSION_RX_CONSTRAINT_EVENT_ID; @@ -749,6 +781,9 @@ int wl1271_load_firmware(struct wl1271 *wl) clk |= (wl->ref_clock << 1) << 4; } + if (wl->quirks & WL12XX_QUIRK_LPD_MODE) + clk |= SCRATCH_ENABLE_LPD; + wl1271_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 42935ac72663..97dd237a9580 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -23,7 +23,6 @@ #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/crc7.h> #include <linux/spi/spi.h> #include <linux/etherdevice.h> #include <linux/ieee80211.h> @@ -106,7 +105,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, fail: WARN_ON(1); - ieee80211_queue_work(wl->hw, &wl->recovery_work); + wl12xx_queue_recovery_work(wl); return ret; } @@ -135,6 +134,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) /* Override the REF CLK from the NVS with the one from platform data */ gen_parms->general_params.ref_clock = wl->ref_clock; + /* LPD mode enable (bits 6-7) in WL1271 AP mode only */ + if (wl->quirks & WL12XX_QUIRK_LPD_MODE) + gen_parms->general_params.general_settings |= + GENERAL_SETTINGS_DRPW_LPD; + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); if (ret < 0) { wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); @@ -352,7 +356,7 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); if (ret != 0) { - ieee80211_queue_work(wl->hw, &wl->recovery_work); + wl12xx_queue_recovery_work(wl); return ret; } @@ -396,10 +400,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; - /* reset TX security counters */ - wl->tx_security_last_seq = 0; - wl->tx_security_seq = 0; - wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x", join->basic_rate_set, join->supported_rate_set); @@ -1080,7 +1080,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl) memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); - cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); + cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->global_hlid = WL1271_AP_GLOBAL_HLID; cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; @@ -1167,14 +1167,7 @@ int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->aid = sta->aid; cmd->hlid = hlid; - - /* - * FIXME: Does STA support QOS? We need to propagate this info from - * hostapd. Currently not that important since this is only used for - * sending the correct flavor of null-data packet in response to a - * trigger. - */ - cmd->wmm = 0; + cmd->wmm = sta->wme ? 1 : 0; cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta->supp_rates[wl->band])); @@ -1230,3 +1223,87 @@ out_free: out: return ret; } + +int wl12xx_cmd_config_fwlog(struct wl1271 *wl) +{ + struct wl12xx_cmd_config_fwlog *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd config firmware logger"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->logger_mode = wl->conf.fwlog.mode; + cmd->log_severity = wl->conf.fwlog.severity; + cmd->timestamp = wl->conf.fwlog.timestamp; + cmd->output = wl->conf.fwlog.output; + cmd->threshold = wl->conf.fwlog.threshold; + + ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send config firmware logger command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_start_fwlog(struct wl1271 *wl) +{ + struct wl12xx_cmd_start_fwlog *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd start firmware logger"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send start firmware logger command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_stop_fwlog(struct wl1271 *wl) +{ + struct wl12xx_cmd_stop_fwlog *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd stop firmware logger"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send stop firmware logger command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 5cac95d9480c..1f7037292c15 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -70,6 +70,9 @@ int wl1271_cmd_start_bss(struct wl1271 *wl); int wl1271_cmd_stop_bss(struct wl1271 *wl); int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid); int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid); +int wl12xx_cmd_config_fwlog(struct wl1271 *wl); +int wl12xx_cmd_start_fwlog(struct wl1271 *wl); +int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); enum wl1271_commands { CMD_INTERROGATE = 1, /*use this to read information elements*/ @@ -107,6 +110,9 @@ enum wl1271_commands { CMD_START_PERIODIC_SCAN = 50, CMD_STOP_PERIODIC_SCAN = 51, CMD_SET_STA_STATE = 52, + CMD_CONFIG_FWLOGGER = 53, + CMD_START_FWLOGGER = 54, + CMD_STOP_FWLOGGER = 55, /* AP mode commands */ CMD_BSS_START = 60, @@ -575,4 +581,60 @@ struct wl1271_cmd_remove_sta { u8 padding1; } __packed; +/* + * Continuous mode - packets are transferred to the host periodically + * via the data path. + * On demand - Log messages are stored in a cyclic buffer in the + * firmware, and only transferred to the host when explicitly requested + */ +enum wl12xx_fwlogger_log_mode { + WL12XX_FWLOG_CONTINUOUS, + WL12XX_FWLOG_ON_DEMAND +}; + +/* Include/exclude timestamps from the log messages */ +enum wl12xx_fwlogger_timestamp { + WL12XX_FWLOG_TIMESTAMP_DISABLED, + WL12XX_FWLOG_TIMESTAMP_ENABLED +}; + +/* + * Logs can be routed to the debug pinouts (where available), to the host bus + * (SDIO/SPI), or dropped + */ +enum wl12xx_fwlogger_output { + WL12XX_FWLOG_OUTPUT_NONE, + WL12XX_FWLOG_OUTPUT_DBG_PINS, + WL12XX_FWLOG_OUTPUT_HOST, +}; + +struct wl12xx_cmd_config_fwlog { + struct wl1271_cmd_header header; + + /* See enum wl12xx_fwlogger_log_mode */ + u8 logger_mode; + + /* Minimum log level threshold */ + u8 log_severity; + + /* Include/exclude timestamps from the log messages */ + u8 timestamp; + + /* See enum wl1271_fwlogger_output */ + u8 output; + + /* Regulates the frequency of log messages */ + u8 threshold; + + u8 padding[3]; +} __packed; + +struct wl12xx_cmd_start_fwlog { + struct wl1271_cmd_header header; +} __packed; + +struct wl12xx_cmd_stop_fwlog { + struct wl1271_cmd_header header; +} __packed; + #endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index c83fefb6662f..6080e01d92c6 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -713,8 +713,16 @@ struct conf_tx_settings { /* * AP-mode - allow this number of TX retries to a station before an * event is triggered from FW. + * In AP-mode the hlids of unreachable stations are given in the + * "sta_tx_retry_exceeded" member in the event mailbox. */ - u16 ap_max_tx_retries; + u8 max_tx_retries; + + /* + * AP-mode - after this number of seconds a connected station is + * considered inactive. + */ + u16 ap_aging_period; /* * Configuration for TID parameters. @@ -1248,6 +1256,59 @@ struct conf_fm_coex { u8 swallow_clk_diff; }; +struct conf_rx_streaming_settings { + /* + * RX Streaming duration (in msec) from last tx/rx + * + * Range: u32 + */ + u32 duration; + + /* + * Bitmap of tids to be polled during RX streaming. + * (Note: it doesn't look like it really matters) + * + * Range: 0x1-0xff + */ + u8 queues; + + /* + * RX Streaming interval. + * (Note:this value is also used as the rx streaming timeout) + * Range: 0 (disabled), 10 - 100 + */ + u8 interval; + + /* + * enable rx streaming also when there is no coex activity + */ + u8 always; +}; + +struct conf_fwlog { + /* Continuous or on-demand */ + u8 mode; + + /* + * Number of memory blocks dedicated for the FW logger + * + * Range: 1-3, or 0 to disable the FW logger + */ + u8 mem_blocks; + + /* Minimum log level threshold */ + u8 severity; + + /* Include/exclude timestamps from the log messages */ + u8 timestamp; + + /* See enum wl1271_fwlogger_output */ + u8 output; + + /* Regulates the frequency of log messages */ + u8 threshold; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1263,6 +1324,8 @@ struct conf_drv_settings { struct conf_memory_settings mem_wl127x; struct conf_memory_settings mem_wl128x; struct conf_fm_coex fm_coex; + struct conf_rx_streaming_settings rx_streaming; + struct conf_fwlog fwlog; u8 hci_io_ds; }; diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index f1f8df9b6cd7..37934b5601cd 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -30,6 +30,7 @@ #include "acx.h" #include "ps.h" #include "io.h" +#include "tx.h" /* ms */ #define WL1271_DEBUGFS_STATS_LIFETIME 1000 @@ -71,6 +72,14 @@ static const struct file_operations name## _ops = { \ if (!entry || IS_ERR(entry)) \ goto err; \ +#define DEBUGFS_ADD_PREFIX(prefix, name, parent) \ + do { \ + entry = debugfs_create_file(#name, 0400, parent, \ + wl, &prefix## _## name## _ops); \ + if (!entry || IS_ERR(entry)) \ + goto err; \ + } while (0); + #define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \ static ssize_t sub## _ ##name## _read(struct file *file, \ char __user *userbuf, \ @@ -225,7 +234,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, char buf[20]; int res; - queue_len = wl->tx_queue_count; + queue_len = wl1271_tx_total_queue_count(wl); res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); return simple_read_from_buffer(userbuf, count, ppos, buf, res); @@ -298,7 +307,7 @@ static ssize_t start_recovery_write(struct file *file, struct wl1271 *wl = file->private_data; mutex_lock(&wl->mutex); - ieee80211_queue_work(wl->hw, &wl->recovery_work); + wl12xx_queue_recovery_work(wl); mutex_unlock(&wl->mutex); return count; @@ -330,10 +339,16 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, #define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x") DRIVER_STATE_PRINT_INT(tx_blocks_available); - DRIVER_STATE_PRINT_INT(tx_allocated_blocks); + DRIVER_STATE_PRINT_INT(tx_allocated_blocks[0]); + DRIVER_STATE_PRINT_INT(tx_allocated_blocks[1]); + DRIVER_STATE_PRINT_INT(tx_allocated_blocks[2]); + DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]); DRIVER_STATE_PRINT_INT(tx_frames_cnt); DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); - DRIVER_STATE_PRINT_INT(tx_queue_count); + DRIVER_STATE_PRINT_INT(tx_queue_count[0]); + DRIVER_STATE_PRINT_INT(tx_queue_count[1]); + DRIVER_STATE_PRINT_INT(tx_queue_count[2]); + DRIVER_STATE_PRINT_INT(tx_queue_count[3]); DRIVER_STATE_PRINT_INT(tx_packets_count); DRIVER_STATE_PRINT_INT(tx_results_count); DRIVER_STATE_PRINT_LHEX(flags); @@ -341,7 +356,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]); DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]); DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]); - DRIVER_STATE_PRINT_INT(tx_security_last_seq); + DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb); DRIVER_STATE_PRINT_INT(rx_counter); DRIVER_STATE_PRINT_INT(session_counter); DRIVER_STATE_PRINT_INT(state); @@ -527,11 +542,129 @@ static const struct file_operations beacon_interval_ops = { .llseek = default_llseek, }; +static ssize_t rx_streaming_interval_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = kstrtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value in rx_streaming_interval!"); + return -EINVAL; + } + + /* valid values: 0, 10-100 */ + if (value && (value < 10 || value > 100)) { + wl1271_warning("value is not in range!"); + return -ERANGE; + } + + mutex_lock(&wl->mutex); + + wl->conf.rx_streaming.interval = value; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1271_recalc_rx_streaming(wl); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static ssize_t rx_streaming_interval_read(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + return wl1271_format_buffer(userbuf, count, ppos, + "%d\n", wl->conf.rx_streaming.interval); +} + +static const struct file_operations rx_streaming_interval_ops = { + .read = rx_streaming_interval_read, + .write = rx_streaming_interval_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + +static ssize_t rx_streaming_always_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = kstrtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value in rx_streaming_write!"); + return -EINVAL; + } + + /* valid values: 0, 10-100 */ + if (!(value == 0 || value == 1)) { + wl1271_warning("value is not in valid!"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + + wl->conf.rx_streaming.always = value; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1271_recalc_rx_streaming(wl); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static ssize_t rx_streaming_always_read(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + return wl1271_format_buffer(userbuf, count, ppos, + "%d\n", wl->conf.rx_streaming.always); +} + +static const struct file_operations rx_streaming_always_ops = { + .read = rx_streaming_always_read, + .write = rx_streaming_always_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + static int wl1271_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { int ret = 0; - struct dentry *entry, *stats; + struct dentry *entry, *stats, *streaming; stats = debugfs_create_dir("fw-statistics", rootdir); if (!stats || IS_ERR(stats)) { @@ -640,6 +773,14 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(dtim_interval, rootdir); DEBUGFS_ADD(beacon_interval, rootdir); + streaming = debugfs_create_dir("rx_streaming", rootdir); + if (!streaming || IS_ERR(streaming)) + goto err; + + DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming); + DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming); + + return 0; err: diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 94bbd00ec31b..304aaa2ee011 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -133,10 +133,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl, if (ret < 0) break; - /* enable beacon early termination */ - ret = wl1271_acx_bet_enable(wl, true); - if (ret < 0) - break; + /* + * BET has only a minor effect in 5GHz and masks + * channel switch IEs, so we only enable BET on 2.4GHz + */ + if (wl->band == IEEE80211_BAND_2GHZ) + /* enable beacon early termination */ + ret = wl1271_acx_bet_enable(wl, true); if (wl->ps_compl) { complete(wl->ps_compl); @@ -183,6 +186,21 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed) ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid); } +static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, + u8 enable) +{ + if (enable) { + /* disable dynamic PS when requested by the firmware */ + ieee80211_disable_dyn_ps(wl->vif); + set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags); + } else { + ieee80211_enable_dyn_ps(wl->vif); + clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags); + wl1271_recalc_rx_streaming(wl); + } + +} + static void wl1271_event_mbox_dump(struct event_mailbox *mbox) { wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); @@ -196,6 +214,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) u32 vector; bool beacon_loss = false; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + bool disconnect_sta = false; + unsigned long sta_bitmap = 0; wl1271_event_mbox_dump(mbox); @@ -226,14 +246,10 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) } } - /* disable dynamic PS when requested by the firmware */ if (vector & SOFT_GEMINI_SENSE_EVENT_ID && - wl->bss_type == BSS_TYPE_STA_BSS) { - if (mbox->soft_gemini_sense_info) - ieee80211_disable_dyn_ps(wl->vif); - else - ieee80211_enable_dyn_ps(wl->vif); - } + wl->bss_type == BSS_TYPE_STA_BSS) + wl12xx_event_soft_gemini_sense(wl, + mbox->soft_gemini_sense_info); /* * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon @@ -281,6 +297,46 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_tx_dummy_packet(wl); } + /* + * "TX retries exceeded" has a different meaning according to mode. + * In AP mode the offending station is disconnected. + */ + if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) { + wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); + sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); + disconnect_sta = true; + } + + if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { + wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); + sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); + disconnect_sta = true; + } + + if (is_ap && disconnect_sta) { + u32 num_packets = wl->conf.tx.max_tx_retries; + struct ieee80211_sta *sta; + const u8 *addr; + int h; + + for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); + h < AP_MAX_LINKS; + h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { + if (!wl1271_is_active_sta(wl, h)) + continue; + + addr = wl->links[h].addr; + + rcu_read_lock(); + sta = ieee80211_find_sta(wl->vif, addr); + if (sta) { + wl1271_debug(DEBUG_EVENT, "remove sta %d", h); + ieee80211_report_low_ack(sta, num_packets); + } + rcu_read_unlock(); + } + } + if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index ce99adf4256e..e524ad6fe4e3 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -58,13 +58,16 @@ enum { CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), BSS_LOSE_EVENT_ID = BIT(18), REGAINED_BSS_EVENT_ID = BIT(19), - ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), + MAX_TX_RETRY_EVENT_ID = BIT(20), /* STA: dummy paket for dynamic mem blocks */ DUMMY_PACKET_EVENT_ID = BIT(21), /* AP: STA remove complete */ STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), + /* STA: SG prediction */ SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), + /* AP: Inactive STA */ + INACTIVE_STA_EVENT_ID = BIT(23), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), DBG_EVENT_ID = BIT(26), @@ -119,7 +122,11 @@ struct event_mailbox { /* AP FW only */ u8 hlid_removed; + + /* a bitmap of hlids for stations that have been inactive too long */ __le16 sta_aging_status; + + /* a bitmap of hlids for stations which didn't respond to TX */ __le16 sta_tx_retry_exceeded; /* @@ -143,4 +150,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl); int wl1271_event_handle(struct wl1271 *wl, u8 mbox); void wl1271_pspoll_work(struct work_struct *work); +/* Functions from main.c */ +bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid); + #endif diff --git a/drivers/net/wireless/wl12xx/ini.h b/drivers/net/wireless/wl12xx/ini.h index 1420c842b8f1..4cf9ecc56212 100644 --- a/drivers/net/wireless/wl12xx/ini.h +++ b/drivers/net/wireless/wl12xx/ini.h @@ -24,6 +24,9 @@ #ifndef __INI_H__ #define __INI_H__ +#define GENERAL_SETTINGS_DRPW_LPD 0xc0 +#define SCRATCH_ENABLE_LPD BIT(25) + #define WL1271_INI_MAX_SMART_REFLEX_PARAM 16 struct wl1271_ini_general_params { diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index f5c2c9e6f84b..c3e9a2e4410e 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -321,6 +321,20 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl) return 0; } +static int wl12xx_init_fwlog(struct wl1271 *wl) +{ + int ret; + + if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) + return 0; + + ret = wl12xx_cmd_config_fwlog(wl); + if (ret < 0) + return ret; + + return 0; +} + static int wl1271_sta_hw_init(struct wl1271 *wl) { int ret; @@ -382,6 +396,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + /* Configure the FW logger */ + ret = wl12xx_init_fwlog(wl); + if (ret < 0) + return ret; + return 0; } @@ -428,7 +447,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_max_tx_retry(wl); + ret = wl1271_acx_ap_max_tx_retry(wl); if (ret < 0) return ret; @@ -436,6 +455,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + /* initialize Tx power */ + ret = wl1271_acx_tx_power(wl, wl->power_level); + if (ret < 0) + return ret; + return 0; } diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c index da5c1ad942a4..c2da66f45046 100644 --- a/drivers/net/wireless/wl12xx/io.c +++ b/drivers/net/wireless/wl12xx/io.c @@ -23,7 +23,6 @@ #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/crc7.h> #include <linux/spi/spi.h> #include "wl12xx.h" @@ -128,12 +127,14 @@ EXPORT_SYMBOL_GPL(wl1271_set_partition); void wl1271_io_reset(struct wl1271 *wl) { - wl->if_ops->reset(wl); + if (wl->if_ops->reset) + wl->if_ops->reset(wl); } void wl1271_io_init(struct wl1271 *wl) { - wl->if_ops->init(wl); + if (wl->if_ops->init) + wl->if_ops->init(wl); } void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index beed621a8ae0..cfb3588a4ddf 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -128,6 +128,20 @@ static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf, wl1271_raw_write(wl, physical, buf, len, fixed); } +static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, + void *buf, size_t len, bool fixed) +{ + int physical; + int addr; + + /* Addresses are stored internally as addresses to 32 bytes blocks */ + addr = hwaddr << 5; + + physical = wl1271_translate_addr(wl, addr); + + wl1271_raw_read(wl, physical, buf, len, fixed); +} + static inline u32 wl1271_read32(struct wl1271 *wl, int addr) { return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr)); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index f37f0b873c73..e58c22d21e39 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -31,6 +31,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/wl12xx.h> +#include <linux/sched.h> #include "wl12xx.h" #include "wl12xx_80211.h" @@ -209,7 +210,8 @@ static struct conf_drv_settings default_conf = { .tx_op_limit = 1504, }, }, - .ap_max_tx_retries = 100, + .max_tx_retries = 100, + .ap_aging_period = 300, .tid_conf_count = 4, .tid_conf = { [CONF_TX_AC_BE] = { @@ -362,9 +364,25 @@ static struct conf_drv_settings default_conf = { .fm_disturbed_band_margin = 0xff, /* default */ .swallow_clk_diff = 0xff, /* default */ }, + .rx_streaming = { + .duration = 150, + .queues = 0x1, + .interval = 20, + .always = 0, + }, + .fwlog = { + .mode = WL12XX_FWLOG_ON_DEMAND, + .mem_blocks = 2, + .severity = 0, + .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED, + .output = WL12XX_FWLOG_OUTPUT_HOST, + .threshold = 0, + }, .hci_io_ds = HCI_IO_DS_6MA, }; +static char *fwlog_param; + static void __wl1271_op_remove_interface(struct wl1271 *wl, bool reset_tx_queues); static void wl1271_free_ap_keys(struct wl1271 *wl); @@ -388,6 +406,22 @@ static struct platform_device wl1271_device = { static DEFINE_MUTEX(wl_list_mutex); static LIST_HEAD(wl_list); +static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate) +{ + int ret; + if (operstate != IF_OPER_UP) + return 0; + + if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) + return 0; + + ret = wl1271_cmd_set_sta_state(wl); + if (ret < 0) + return ret; + + wl1271_info("Association completed."); + return 0; +} static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, void *arg) { @@ -437,11 +471,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, if (ret < 0) goto out; - if ((dev->operstate == IF_OPER_UP) && - !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) { - wl1271_cmd_set_sta_state(wl); - wl1271_info("Association completed."); - } + wl1271_check_operstate(wl, dev->operstate); wl1271_ps_elp_sleep(wl); @@ -473,6 +503,117 @@ static int wl1271_reg_notify(struct wiphy *wiphy, return 0; } +static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable) +{ + int ret = 0; + + /* we should hold wl->mutex */ + ret = wl1271_acx_ps_rx_streaming(wl, enable); + if (ret < 0) + goto out; + + if (enable) + set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags); + else + clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags); +out: + return ret; +} + +/* + * this function is being called when the rx_streaming interval + * has beed changed or rx_streaming should be disabled + */ +int wl1271_recalc_rx_streaming(struct wl1271 *wl) +{ + int ret = 0; + int period = wl->conf.rx_streaming.interval; + + /* don't reconfigure if rx_streaming is disabled */ + if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) + goto out; + + /* reconfigure/disable according to new streaming_period */ + if (period && + test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) && + (wl->conf.rx_streaming.always || + test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) + ret = wl1271_set_rx_streaming(wl, true); + else { + ret = wl1271_set_rx_streaming(wl, false); + /* don't cancel_work_sync since we might deadlock */ + del_timer_sync(&wl->rx_streaming_timer); + } +out: + return ret; +} + +static void wl1271_rx_streaming_enable_work(struct work_struct *work) +{ + int ret; + struct wl1271 *wl = + container_of(work, struct wl1271, rx_streaming_enable_work); + + mutex_lock(&wl->mutex); + + if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) || + !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || + (!wl->conf.rx_streaming.always && + !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) + goto out; + + if (!wl->conf.rx_streaming.interval) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_set_rx_streaming(wl, true); + if (ret < 0) + goto out_sleep; + + /* stop it after some time of inactivity */ + mod_timer(&wl->rx_streaming_timer, + jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration)); + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static void wl1271_rx_streaming_disable_work(struct work_struct *work) +{ + int ret; + struct wl1271 *wl = + container_of(work, struct wl1271, rx_streaming_disable_work); + + mutex_lock(&wl->mutex); + + if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_set_rx_streaming(wl, false); + if (ret) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static void wl1271_rx_streaming_timer(unsigned long data) +{ + struct wl1271 *wl = (struct wl1271 *)data; + ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work); +} + static void wl1271_conf_init(struct wl1271 *wl) { @@ -488,8 +629,24 @@ static void wl1271_conf_init(struct wl1271 *wl) /* apply driver default configuration */ memcpy(&wl->conf, &default_conf, sizeof(default_conf)); -} + /* Adjust settings according to optional module parameters */ + if (fwlog_param) { + if (!strcmp(fwlog_param, "continuous")) { + wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; + } else if (!strcmp(fwlog_param, "ondemand")) { + wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND; + } else if (!strcmp(fwlog_param, "dbgpins")) { + wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; + wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS; + } else if (!strcmp(fwlog_param, "disable")) { + wl->conf.fwlog.mem_blocks = 0; + wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE; + } else { + wl1271_error("Unknown fwlog parameter %s", fwlog_param); + } + } +} static int wl1271_plt_init(struct wl1271 *wl) { @@ -667,13 +824,24 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl, } } +static u32 wl1271_tx_allocated_blocks(struct wl1271 *wl) +{ + int i; + u32 total_alloc_blocks = 0; + + for (i = 0; i < NUM_TX_QUEUES; i++) + total_alloc_blocks += wl->tx_allocated_blocks[i]; + + return total_alloc_blocks; +} + static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_full_status *full_status) { struct wl1271_fw_common_status *status = &full_status->common; struct timespec ts; u32 old_tx_blk_count = wl->tx_blocks_available; - u32 freed_blocks = 0; + u32 freed_blocks = 0, ac_freed_blocks; int i; if (wl->bss_type == BSS_TYPE_AP_BSS) { @@ -693,21 +861,23 @@ static void wl1271_fw_status(struct wl1271 *wl, /* update number of available TX blocks */ for (i = 0; i < NUM_TX_QUEUES; i++) { - freed_blocks += le32_to_cpu(status->tx_released_blks[i]) - - wl->tx_blocks_freed[i]; + ac_freed_blocks = le32_to_cpu(status->tx_released_blks[i]) - + wl->tx_blocks_freed[i]; + freed_blocks += ac_freed_blocks; + + wl->tx_allocated_blocks[i] -= ac_freed_blocks; wl->tx_blocks_freed[i] = le32_to_cpu(status->tx_released_blks[i]); } - wl->tx_allocated_blocks -= freed_blocks; - if (wl->bss_type == BSS_TYPE_AP_BSS) { /* Update num of allocated TX blocks per link and ps status */ wl1271_irq_update_links_status(wl, &full_status->ap); wl->tx_blocks_available += freed_blocks; } else { - int avail = full_status->sta.tx_total - wl->tx_allocated_blocks; + int avail = full_status->sta.tx_total - + wl1271_tx_allocated_blocks(wl); /* * The FW might change the total number of TX memblocks before @@ -741,7 +911,7 @@ static void wl1271_flush_deferred_work(struct wl1271 *wl) /* Return sent skbs to the network stack */ while ((skb = skb_dequeue(&wl->deferred_tx_queue))) - ieee80211_tx_status(wl->hw, skb); + ieee80211_tx_status_ni(wl->hw, skb); } static void wl1271_netstack_work(struct work_struct *work) @@ -808,7 +978,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie) if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { wl1271_error("watchdog interrupt received! " "starting recovery."); - ieee80211_queue_work(wl->hw, &wl->recovery_work); + wl12xx_queue_recovery_work(wl); /* restarting the chip. ignore any other interrupt. */ goto out; @@ -822,7 +992,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie) /* Check if any tx blocks were freed */ spin_lock_irqsave(&wl->wl_lock, flags); if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && - wl->tx_queue_count) { + wl1271_tx_total_queue_count(wl) > 0) { spin_unlock_irqrestore(&wl->wl_lock, flags); /* * In order to avoid starvation of the TX path, @@ -870,7 +1040,7 @@ out: /* In case TX was not handled here, queue TX work */ clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags); if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && - wl->tx_queue_count) + wl1271_tx_total_queue_count(wl) > 0) ieee80211_queue_work(wl->hw, &wl->tx_work); spin_unlock_irqrestore(&wl->wl_lock, flags); @@ -970,6 +1140,89 @@ out: return ret; } +void wl12xx_queue_recovery_work(struct wl1271 *wl) +{ + if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) + ieee80211_queue_work(wl->hw, &wl->recovery_work); +} + +size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) +{ + size_t len = 0; + + /* The FW log is a length-value list, find where the log end */ + while (len < maxlen) { + if (memblock[len] == 0) + break; + if (len + memblock[len] + 1 > maxlen) + break; + len += memblock[len] + 1; + } + + /* Make sure we have enough room */ + len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size)); + + /* Fill the FW log file, consumed by the sysfs fwlog entry */ + memcpy(wl->fwlog + wl->fwlog_size, memblock, len); + wl->fwlog_size += len; + + return len; +} + +static void wl12xx_read_fwlog_panic(struct wl1271 *wl) +{ + u32 addr; + u32 first_addr; + u8 *block; + + if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) || + (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) || + (wl->conf.fwlog.mem_blocks == 0)) + return; + + wl1271_info("Reading FW panic log"); + + block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL); + if (!block) + return; + + /* + * Make sure the chip is awake and the logger isn't active. + * This might fail if the firmware hanged. + */ + if (!wl1271_ps_elp_wakeup(wl)) + wl12xx_cmd_stop_fwlog(wl); + + /* Read the first memory block address */ + wl1271_fw_status(wl, wl->fw_status); + first_addr = __le32_to_cpu(wl->fw_status->sta.log_start_addr); + if (!first_addr) + goto out; + + /* Traverse the memory blocks linked list */ + addr = first_addr; + do { + memset(block, 0, WL12XX_HW_BLOCK_SIZE); + wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE, + false); + + /* + * Memory blocks are linked to one another. The first 4 bytes + * of each memory block hold the hardware address of the next + * one. The last memory block points to the first one. + */ + addr = __le32_to_cpup((__le32 *)block); + if (!wl12xx_copy_fwlog(wl, block + sizeof(addr), + WL12XX_HW_BLOCK_SIZE - sizeof(addr))) + break; + } while (addr && (addr != first_addr)); + + wake_up_interruptible(&wl->fwlog_waitq); + +out: + kfree(block); +} + static void wl1271_recovery_work(struct work_struct *work) { struct wl1271 *wl = @@ -980,9 +1233,23 @@ static void wl1271_recovery_work(struct work_struct *work) if (wl->state != WL1271_STATE_ON) goto out; + /* Avoid a recursive recovery */ + set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); + + wl12xx_read_fwlog_panic(wl); + wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); + /* + * Advance security sequence number to overcome potential progress + * in the firmware during recovery. This doens't hurt if the network is + * not encrypted. + */ + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || + test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) + wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING; + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ieee80211_connection_loss(wl->vif); @@ -996,6 +1263,9 @@ static void wl1271_recovery_work(struct work_struct *work) /* reboot the chipset */ __wl1271_op_remove_interface(wl, false); + + clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); + ieee80211_restart_hw(wl->hw); /* @@ -1074,9 +1344,13 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl->chip.id); - /* end-of-transaction flag should be set in wl127x AP mode */ + /* + * 'end-of-transaction flag' and 'LPD mode flag' + * should be set in wl127x AP mode only + */ if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; + wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION | + WL12XX_QUIRK_LPD_MODE); ret = wl1271_setup(wl); if (ret < 0) @@ -1089,6 +1363,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) goto out; + if (wl1271_set_block_size(wl)) wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT; break; @@ -1117,24 +1392,6 @@ out: return ret; } -static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl) -{ - unsigned int quirks = 0; - unsigned int *fw_ver = wl->chip.fw_ver; - - /* Only for wl127x */ - if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) && - /* Check STA version */ - (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && - (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) || - /* Check AP version */ - ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) && - (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN)))) - quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS; - - return quirks; -} - int wl1271_plt_start(struct wl1271 *wl) { int retries = WL1271_BOOT_RETRIES; @@ -1171,8 +1428,6 @@ int wl1271_plt_start(struct wl1271 *wl) wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver_str); - /* Check if any quirks are needed with older fw versions */ - wl->quirks |= wl1271_get_fw_ver_quirks(wl); goto out; irq_disable: @@ -1242,26 +1497,27 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1271 *wl = hw->priv; unsigned long flags; - int q; + int q, mapping; u8 hlid = 0; - q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + mapping = skb_get_queue_mapping(skb); + q = wl1271_tx_get_queue(mapping); if (wl->bss_type == BSS_TYPE_AP_BSS) hlid = wl1271_tx_get_hlid(skb); spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count++; + wl->tx_queue_count[q]++; /* * The workqueue is slow to process the tx_queue and we need stop * the queue here, otherwise the queue will get too long. */ - if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) { - wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); - ieee80211_stop_queues(wl->hw); - set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); + if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { + wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); + ieee80211_stop_queue(wl->hw, mapping); + set_bit(q, &wl->stopped_queues_map); } /* queue the packet */ @@ -1287,10 +1543,11 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) int wl1271_tx_dummy_packet(struct wl1271 *wl) { unsigned long flags; + int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); spin_lock_irqsave(&wl->wl_lock, flags); set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); - wl->tx_queue_count++; + wl->tx_queue_count[q]++; spin_unlock_irqrestore(&wl->wl_lock, flags); /* The FW is low on RX memory blocks, so send the dummy packet asap */ @@ -1352,15 +1609,15 @@ static struct notifier_block wl1271_dev_notifier = { }; #ifdef CONFIG_PM -static int wl1271_configure_suspend(struct wl1271 *wl) +static int wl1271_configure_suspend_sta(struct wl1271 *wl) { - int ret; - - if (wl->bss_type != BSS_TYPE_STA_BSS) - return 0; + int ret = 0; mutex_lock(&wl->mutex); + if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + goto out_unlock; + ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out_unlock; @@ -1403,11 +1660,44 @@ out: } +static int wl1271_configure_suspend_ap(struct wl1271 *wl) +{ + int ret = 0; + + mutex_lock(&wl->mutex); + + if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) + goto out_unlock; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + ret = wl1271_acx_set_ap_beacon_filter(wl, true); + + wl1271_ps_elp_sleep(wl); +out_unlock: + mutex_unlock(&wl->mutex); + return ret; + +} + +static int wl1271_configure_suspend(struct wl1271 *wl) +{ + if (wl->bss_type == BSS_TYPE_STA_BSS) + return wl1271_configure_suspend_sta(wl); + if (wl->bss_type == BSS_TYPE_AP_BSS) + return wl1271_configure_suspend_ap(wl); + return 0; +} + static void wl1271_configure_resume(struct wl1271 *wl) { int ret; + bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS; + bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS; - if (wl->bss_type != BSS_TYPE_STA_BSS) + if (!is_sta && !is_ap) return; mutex_lock(&wl->mutex); @@ -1415,10 +1705,14 @@ static void wl1271_configure_resume(struct wl1271 *wl) if (ret < 0) goto out; - /* exit psm if it wasn't configured */ - if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) - wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, - wl->basic_rate, true); + if (is_sta) { + /* exit psm if it wasn't configured */ + if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) + wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, + wl->basic_rate, true); + } else if (is_ap) { + wl1271_acx_set_ap_beacon_filter(wl, false); + } wl1271_ps_elp_sleep(wl); out: @@ -1429,69 +1723,68 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow) { struct wl1271 *wl = hw->priv; + int ret; + wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); - wl->wow_enabled = !!wow; - if (wl->wow_enabled) { - int ret; - ret = wl1271_configure_suspend(wl); - if (ret < 0) { - wl1271_warning("couldn't prepare device to suspend"); - return ret; - } - /* flush any remaining work */ - wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); - flush_delayed_work(&wl->scan_complete_work); + WARN_ON(!wow || !wow->any); - /* - * disable and re-enable interrupts in order to flush - * the threaded_irq - */ - wl1271_disable_interrupts(wl); + wl->wow_enabled = true; + ret = wl1271_configure_suspend(wl); + if (ret < 0) { + wl1271_warning("couldn't prepare device to suspend"); + return ret; + } + /* flush any remaining work */ + wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); - /* - * set suspended flag to avoid triggering a new threaded_irq - * work. no need for spinlock as interrupts are disabled. - */ - set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); + /* + * disable and re-enable interrupts in order to flush + * the threaded_irq + */ + wl1271_disable_interrupts(wl); + + /* + * set suspended flag to avoid triggering a new threaded_irq + * work. no need for spinlock as interrupts are disabled. + */ + set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); + + wl1271_enable_interrupts(wl); + flush_work(&wl->tx_work); + flush_delayed_work(&wl->pspoll_work); + flush_delayed_work(&wl->elp_work); - wl1271_enable_interrupts(wl); - flush_work(&wl->tx_work); - flush_delayed_work(&wl->pspoll_work); - flush_delayed_work(&wl->elp_work); - } return 0; } static int wl1271_op_resume(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; + unsigned long flags; + bool run_irq_work = false; + wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", wl->wow_enabled); + WARN_ON(!wl->wow_enabled); /* * re-enable irq_work enqueuing, and call irq_work directly if * there is a pending work. */ - if (wl->wow_enabled) { - struct wl1271 *wl = hw->priv; - unsigned long flags; - bool run_irq_work = false; - - spin_lock_irqsave(&wl->wl_lock, flags); - clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags); - if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags)) - run_irq_work = true; - spin_unlock_irqrestore(&wl->wl_lock, flags); - - if (run_irq_work) { - wl1271_debug(DEBUG_MAC80211, - "run postponed irq_work directly"); - wl1271_irq(0, wl); - wl1271_enable_interrupts(wl); - } + spin_lock_irqsave(&wl->wl_lock, flags); + clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags); + if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags)) + run_irq_work = true; + spin_unlock_irqrestore(&wl->wl_lock, flags); - wl1271_configure_resume(wl); + if (run_irq_work) { + wl1271_debug(DEBUG_MAC80211, + "run postponed irq_work directly"); + wl1271_irq(0, wl); + wl1271_enable_interrupts(wl); } + wl1271_configure_resume(wl); + wl->wow_enabled = false; return 0; } @@ -1629,9 +1922,6 @@ power_off: strncpy(wiphy->fw_version, wl->chip.fw_ver_str, sizeof(wiphy->fw_version)); - /* Check if any quirks are needed with older fw versions */ - wl->quirks |= wl1271_get_fw_ver_quirks(wl); - /* * Now we know if 11a is supported (info from the NVS), so disable * 11a channels if not supported @@ -1694,6 +1984,9 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, cancel_delayed_work_sync(&wl->scan_complete_work); cancel_work_sync(&wl->netstack_work); cancel_work_sync(&wl->tx_work); + del_timer_sync(&wl->rx_streaming_timer); + cancel_work_sync(&wl->rx_streaming_enable_work); + cancel_work_sync(&wl->rx_streaming_disable_work); cancel_delayed_work_sync(&wl->pspoll_work); cancel_delayed_work_sync(&wl->elp_work); @@ -1714,11 +2007,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl->psm_entry_retry = 0; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; - wl->tx_allocated_blocks = 0; wl->tx_results_count = 0; wl->tx_packets_count = 0; - wl->tx_security_last_seq = 0; - wl->tx_security_seq = 0; wl->time_offset = 0; wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; @@ -1737,8 +2027,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, */ wl->flags = 0; - for (i = 0; i < NUM_TX_QUEUES; i++) + for (i = 0; i < NUM_TX_QUEUES; i++) { wl->tx_blocks_freed[i] = 0; + wl->tx_allocated_blocks[i] = 0; + } wl1271_debugfs_reset(wl); @@ -1891,6 +2183,10 @@ static int wl1271_unjoin(struct wl1271 *wl) clear_bit(WL1271_FLAG_JOINED, &wl->flags); memset(wl->bssid, 0, ETH_ALEN); + /* reset TX security counters on a clean disconnect */ + wl->tx_security_last_seq_lsb = 0; + wl->tx_security_seq = 0; + /* stop filtering packets based on bssid */ wl1271_configure_filters(wl, FIF_OTHER_BSS); @@ -1983,6 +2279,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl->channel = channel; } + if ((changed & IEEE80211_CONF_CHANGE_POWER)) + wl->power_level = conf->power_level; + goto out; } @@ -2490,6 +2789,44 @@ out: return ret; } +static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + if (wl->scan.state == WL1271_SCAN_STATE_IDLE) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (wl->scan.state != WL1271_SCAN_STATE_DONE) { + ret = wl1271_scan_stop(wl); + if (ret < 0) + goto out_sleep; + } + wl->scan.state = WL1271_SCAN_STATE_IDLE; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + wl->scan.req = NULL; + ieee80211_scan_completed(wl->hw, true); + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + cancel_delayed_work_sync(&wl->scan_complete_work); +} + static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, @@ -2780,24 +3117,6 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, } } - if (changed & BSS_CHANGED_IBSS) { - wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d", - bss_conf->ibss_joined); - - if (bss_conf->ibss_joined) { - u32 rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, - rates); - wl->basic_rate = wl1271_tx_min_rate_get(wl); - - /* by default, use 11b rates */ - wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES; - ret = wl1271_acx_sta_rate_policies(wl); - if (ret < 0) - goto out; - } - } - ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); if (ret < 0) goto out; @@ -3023,6 +3342,24 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } } + if (changed & BSS_CHANGED_IBSS) { + wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d", + bss_conf->ibss_joined); + + if (bss_conf->ibss_joined) { + u32 rates = bss_conf->basic_rates; + wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, + rates); + wl->basic_rate = wl1271_tx_min_rate_get(wl); + + /* by default, use 11b rates */ + wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES; + ret = wl1271_acx_sta_rate_policies(wl); + if (ret < 0) + goto out; + } + } + ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); if (ret < 0) goto out; @@ -3061,6 +3398,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, wl1271_warning("cmd join failed %d", ret); goto out; } + wl1271_check_operstate(wl, ieee80211_get_operstate(vif)); } out: @@ -3251,6 +3589,12 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); } +bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) +{ + int id = hlid - WL1271_AP_STA_HLID_START; + return test_bit(id, wl->ap_hlid_map); +} + static int wl1271_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -3409,7 +3753,7 @@ static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) goto out; /* packets are considered pending if in the TX queue or the FW */ - ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0); + ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0); /* the above is appropriate for STA mode for PS purposes */ WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); @@ -3572,40 +3916,40 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { /* 5 GHz band channels for WL1273 */ static struct ieee80211_channel wl1271_channels_5ghz[] = { - { .hw_value = 7, .center_freq = 5035}, - { .hw_value = 8, .center_freq = 5040}, - { .hw_value = 9, .center_freq = 5045}, - { .hw_value = 11, .center_freq = 5055}, - { .hw_value = 12, .center_freq = 5060}, - { .hw_value = 16, .center_freq = 5080}, - { .hw_value = 34, .center_freq = 5170}, - { .hw_value = 36, .center_freq = 5180}, - { .hw_value = 38, .center_freq = 5190}, - { .hw_value = 40, .center_freq = 5200}, - { .hw_value = 42, .center_freq = 5210}, - { .hw_value = 44, .center_freq = 5220}, - { .hw_value = 46, .center_freq = 5230}, - { .hw_value = 48, .center_freq = 5240}, - { .hw_value = 52, .center_freq = 5260}, - { .hw_value = 56, .center_freq = 5280}, - { .hw_value = 60, .center_freq = 5300}, - { .hw_value = 64, .center_freq = 5320}, - { .hw_value = 100, .center_freq = 5500}, - { .hw_value = 104, .center_freq = 5520}, - { .hw_value = 108, .center_freq = 5540}, - { .hw_value = 112, .center_freq = 5560}, - { .hw_value = 116, .center_freq = 5580}, - { .hw_value = 120, .center_freq = 5600}, - { .hw_value = 124, .center_freq = 5620}, - { .hw_value = 128, .center_freq = 5640}, - { .hw_value = 132, .center_freq = 5660}, - { .hw_value = 136, .center_freq = 5680}, - { .hw_value = 140, .center_freq = 5700}, - { .hw_value = 149, .center_freq = 5745}, - { .hw_value = 153, .center_freq = 5765}, - { .hw_value = 157, .center_freq = 5785}, - { .hw_value = 161, .center_freq = 5805}, - { .hw_value = 165, .center_freq = 5825}, + { .hw_value = 7, .center_freq = 5035, .max_power = 25 }, + { .hw_value = 8, .center_freq = 5040, .max_power = 25 }, + { .hw_value = 9, .center_freq = 5045, .max_power = 25 }, + { .hw_value = 11, .center_freq = 5055, .max_power = 25 }, + { .hw_value = 12, .center_freq = 5060, .max_power = 25 }, + { .hw_value = 16, .center_freq = 5080, .max_power = 25 }, + { .hw_value = 34, .center_freq = 5170, .max_power = 25 }, + { .hw_value = 36, .center_freq = 5180, .max_power = 25 }, + { .hw_value = 38, .center_freq = 5190, .max_power = 25 }, + { .hw_value = 40, .center_freq = 5200, .max_power = 25 }, + { .hw_value = 42, .center_freq = 5210, .max_power = 25 }, + { .hw_value = 44, .center_freq = 5220, .max_power = 25 }, + { .hw_value = 46, .center_freq = 5230, .max_power = 25 }, + { .hw_value = 48, .center_freq = 5240, .max_power = 25 }, + { .hw_value = 52, .center_freq = 5260, .max_power = 25 }, + { .hw_value = 56, .center_freq = 5280, .max_power = 25 }, + { .hw_value = 60, .center_freq = 5300, .max_power = 25 }, + { .hw_value = 64, .center_freq = 5320, .max_power = 25 }, + { .hw_value = 100, .center_freq = 5500, .max_power = 25 }, + { .hw_value = 104, .center_freq = 5520, .max_power = 25 }, + { .hw_value = 108, .center_freq = 5540, .max_power = 25 }, + { .hw_value = 112, .center_freq = 5560, .max_power = 25 }, + { .hw_value = 116, .center_freq = 5580, .max_power = 25 }, + { .hw_value = 120, .center_freq = 5600, .max_power = 25 }, + { .hw_value = 124, .center_freq = 5620, .max_power = 25 }, + { .hw_value = 128, .center_freq = 5640, .max_power = 25 }, + { .hw_value = 132, .center_freq = 5660, .max_power = 25 }, + { .hw_value = 136, .center_freq = 5680, .max_power = 25 }, + { .hw_value = 140, .center_freq = 5700, .max_power = 25 }, + { .hw_value = 149, .center_freq = 5745, .max_power = 25 }, + { .hw_value = 153, .center_freq = 5765, .max_power = 25 }, + { .hw_value = 157, .center_freq = 5785, .max_power = 25 }, + { .hw_value = 161, .center_freq = 5805, .max_power = 25 }, + { .hw_value = 165, .center_freq = 5825, .max_power = 25 }, }; /* mapping to indexes for wl1271_rates_5ghz */ @@ -3666,6 +4010,7 @@ static const struct ieee80211_ops wl1271_ops = { .tx = wl1271_op_tx, .set_key = wl1271_op_set_key, .hw_scan = wl1271_op_hw_scan, + .cancel_hw_scan = wl1271_op_cancel_hw_scan, .sched_scan_start = wl1271_op_sched_scan_start, .sched_scan_stop = wl1271_op_sched_scan_stop, .bss_info_changed = wl1271_op_bss_info_changed, @@ -3784,6 +4129,69 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR, wl1271_sysfs_show_hw_pg_ver, NULL); +static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buffer, loff_t pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct wl1271 *wl = dev_get_drvdata(dev); + ssize_t len; + int ret; + + ret = mutex_lock_interruptible(&wl->mutex); + if (ret < 0) + return -ERESTARTSYS; + + /* Let only one thread read the log at a time, blocking others */ + while (wl->fwlog_size == 0) { + DEFINE_WAIT(wait); + + prepare_to_wait_exclusive(&wl->fwlog_waitq, + &wait, + TASK_INTERRUPTIBLE); + + if (wl->fwlog_size != 0) { + finish_wait(&wl->fwlog_waitq, &wait); + break; + } + + mutex_unlock(&wl->mutex); + + schedule(); + finish_wait(&wl->fwlog_waitq, &wait); + + if (signal_pending(current)) + return -ERESTARTSYS; + + ret = mutex_lock_interruptible(&wl->mutex); + if (ret < 0) + return -ERESTARTSYS; + } + + /* Check if the fwlog is still valid */ + if (wl->fwlog_size < 0) { + mutex_unlock(&wl->mutex); + return 0; + } + + /* Seeking is not supported - old logs are not kept. Disregard pos. */ + len = min(count, (size_t)wl->fwlog_size); + wl->fwlog_size -= len; + memcpy(buffer, wl->fwlog, len); + + /* Make room for new messages */ + memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size); + + mutex_unlock(&wl->mutex); + + return len; +} + +static struct bin_attribute fwlog_attr = { + .attr = {.name = "fwlog", .mode = S_IRUSR}, + .read = wl1271_sysfs_read_fwlog, +}; + int wl1271_register_hw(struct wl1271 *wl) { int ret; @@ -3964,6 +4372,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void) INIT_WORK(&wl->tx_work, wl1271_tx_work); INIT_WORK(&wl->recovery_work, wl1271_recovery_work); INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); + INIT_WORK(&wl->rx_streaming_enable_work, + wl1271_rx_streaming_enable_work); + INIT_WORK(&wl->rx_streaming_disable_work, + wl1271_rx_streaming_disable_work); + + wl->freezable_wq = create_freezable_workqueue("wl12xx_wq"); + if (!wl->freezable_wq) { + ret = -ENOMEM; + goto err_hw; + } + wl->channel = WL1271_DEFAULT_CHANNEL; wl->beacon_int = WL1271_DEFAULT_BEACON_INT; wl->default_key = 0; @@ -3989,6 +4408,13 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->quirks = 0; wl->platform_quirks = 0; wl->sched_scanning = false; + wl->tx_security_seq = 0; + wl->tx_security_last_seq_lsb = 0; + + setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer, + (unsigned long) wl); + wl->fwlog_size = 0; + init_waitqueue_head(&wl->fwlog_waitq); memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) @@ -4006,7 +4432,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); if (!wl->aggr_buf) { ret = -ENOMEM; - goto err_hw; + goto err_wq; } wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); @@ -4015,11 +4441,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void) goto err_aggr; } + /* Allocate one page for the FW log */ + wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL); + if (!wl->fwlog) { + ret = -ENOMEM; + goto err_dummy_packet; + } + /* Register platform device */ ret = platform_device_register(wl->plat_dev); if (ret) { wl1271_error("couldn't register platform device"); - goto err_dummy_packet; + goto err_fwlog; } dev_set_drvdata(&wl->plat_dev->dev, wl); @@ -4037,20 +4470,36 @@ struct ieee80211_hw *wl1271_alloc_hw(void) goto err_bt_coex_state; } + /* Create sysfs file for the FW log */ + ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr); + if (ret < 0) { + wl1271_error("failed to create sysfs file fwlog"); + goto err_hw_pg_ver; + } + return hw; +err_hw_pg_ver: + device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver); + err_bt_coex_state: device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); err_platform: platform_device_unregister(wl->plat_dev); +err_fwlog: + free_page((unsigned long)wl->fwlog); + err_dummy_packet: dev_kfree_skb(wl->dummy_packet); err_aggr: free_pages((unsigned long)wl->aggr_buf, order); +err_wq: + destroy_workqueue(wl->freezable_wq); + err_hw: wl1271_debugfs_exit(wl); kfree(plat_dev); @@ -4066,7 +4515,15 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw); int wl1271_free_hw(struct wl1271 *wl) { + /* Unblock any fwlog readers */ + mutex_lock(&wl->mutex); + wl->fwlog_size = -1; + wake_up_interruptible_all(&wl->fwlog_waitq); + mutex_unlock(&wl->mutex); + + device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr); platform_device_unregister(wl->plat_dev); + free_page((unsigned long)wl->fwlog); dev_kfree_skb(wl->dummy_packet); free_pages((unsigned long)wl->aggr_buf, get_order(WL1271_AGGR_BUFFER_SIZE)); @@ -4081,6 +4538,7 @@ int wl1271_free_hw(struct wl1271 *wl) kfree(wl->fw_status); kfree(wl->tx_res_if); + destroy_workqueue(wl->freezable_wq); ieee80211_free_hw(wl->hw); @@ -4093,6 +4551,10 @@ EXPORT_SYMBOL_GPL(wl12xx_debug_level); module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); +module_param_named(fwlog, fwlog_param, charp, 0); +MODULE_PARM_DESC(keymap, + "FW logger options: continuous, ondemand, dbgpins or disable"); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index b59b67711a17..3548377ab9c2 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -118,7 +118,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); if (ret == 0) { wl1271_error("ELP wakeup timeout!"); - ieee80211_queue_work(wl->hw, &wl->recovery_work); + wl12xx_queue_recovery_work(wl); ret = -ETIMEDOUT; goto err; } else if (ret < 0) { @@ -169,9 +169,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, wl1271_debug(DEBUG_PSM, "leaving psm"); /* disable beacon early termination */ - ret = wl1271_acx_bet_enable(wl, false); - if (ret < 0) - return ret; + if (wl->band == IEEE80211_BAND_2GHZ) { + ret = wl1271_acx_bet_enable(wl, false); + if (ret < 0) + return ret; + } /* disable beacon filtering */ ret = wl1271_acx_beacon_filter_opt(wl, false); @@ -191,24 +193,27 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) { - int i, filtered = 0; + int i; struct sk_buff *skb; struct ieee80211_tx_info *info; unsigned long flags; + int filtered[NUM_TX_QUEUES]; /* filter all frames currently the low level queus for this hlid */ for (i = 0; i < NUM_TX_QUEUES; i++) { + filtered[i] = 0; while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { info = IEEE80211_SKB_CB(skb); info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->status.rates[0].idx = -1; - ieee80211_tx_status(wl->hw, skb); - filtered++; + ieee80211_tx_status_ni(wl->hw, skb); + filtered[i]++; } } spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count -= filtered; + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_queue_count[i] -= filtered[i]; spin_unlock_irqrestore(&wl->wl_lock, flags); wl1271_handle_tx_low_watermark(wl); diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 70091035e019..0450fb49dbb1 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -22,6 +22,7 @@ */ #include <linux/gfp.h> +#include <linux/sched.h> #include "wl12xx.h" #include "acx.h" @@ -95,6 +96,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; + u8 is_data = 0; /* * In PLT mode we seem to get frames and mac80211 warns about them, @@ -106,6 +108,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; + if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { + size_t len = length - sizeof(*desc); + wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); + wake_up_interruptible(&wl->fwlog_waitq); + return 0; + } + switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { /* discard corrupted packets */ case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: @@ -137,6 +146,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; + if (ieee80211_is_data_present(hdr->frame_control)) + is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); @@ -147,9 +158,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) skb_trim(skb, skb->len - desc->pad_len); skb_queue_tail(&wl->deferred_rx_queue, skb); - ieee80211_queue_work(wl->hw, &wl->netstack_work); + queue_work(wl->freezable_wq, &wl->netstack_work); - return 0; + return is_data; } void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) @@ -162,6 +173,8 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) u32 mem_block; u32 pkt_length; u32 pkt_offset; + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + bool had_data = false; while (drv_rx_counter != fw_rx_counter) { buf_size = 0; @@ -214,9 +227,11 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) * conditions, in that case the received frame will just * be dropped. */ - wl1271_rx_handle_data(wl, - wl->aggr_buf + pkt_offset, - pkt_length); + if (wl1271_rx_handle_data(wl, + wl->aggr_buf + pkt_offset, + pkt_length) == 1) + had_data = true; + wl->rx_counter++; drv_rx_counter++; drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; @@ -230,6 +245,20 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) */ if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); + + if (!is_ap && wl->conf.rx_streaming.interval && had_data && + (wl->conf.rx_streaming.always || + test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) { + u32 timeout = wl->conf.rx_streaming.duration; + + /* restart rx streaming */ + if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) + ieee80211_queue_work(wl->hw, + &wl->rx_streaming_enable_work); + + mod_timer(&wl->rx_streaming_timer, + jiffies + msecs_to_jiffies(timeout)); + } } void wl1271_set_default_filters(struct wl1271 *wl) diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h index 75fabf836491..c88e3fa1d603 100644 --- a/drivers/net/wireless/wl12xx/rx.h +++ b/drivers/net/wireless/wl12xx/rx.h @@ -97,6 +97,18 @@ #define RX_BUF_SIZE_MASK 0xFFF00 #define RX_BUF_SIZE_SHIFT_DIV 6 +enum { + WL12XX_RX_CLASS_UNKNOWN, + WL12XX_RX_CLASS_MANAGEMENT, + WL12XX_RX_CLASS_DATA, + WL12XX_RX_CLASS_QOS_DATA, + WL12XX_RX_CLASS_BCN_PRBRSP, + WL12XX_RX_CLASS_EAPOL, + WL12XX_RX_CLASS_BA_EVENT, + WL12XX_RX_CLASS_AMSDU, + WL12XX_RX_CLASS_LOGGER, +}; + struct wl1271_rx_descriptor { __le16 length; u8 status; diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 56f76abc754d..edfe01c321ca 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -62,7 +62,7 @@ void wl1271_scan_complete_work(struct work_struct *work) if (wl->scan.failed) { wl1271_info("Scan completed due to error."); - ieee80211_queue_work(wl->hw, &wl->recovery_work); + wl12xx_queue_recovery_work(wl); } out: @@ -321,12 +321,39 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, return 0; } +int wl1271_scan_stop(struct wl1271 *wl) +{ + struct wl1271_cmd_header *cmd = NULL; + int ret = 0; + + if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE)) + return -EINVAL; + + wl1271_debug(DEBUG_CMD, "cmd scan stop"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("cmd stop_scan failed"); + goto out; + } +out: + kfree(cmd); + return ret; +} + static int wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, struct cfg80211_sched_scan_request *req, struct conn_scan_ch_params *channels, u32 band, bool radar, bool passive, - int start) + int start, int max_channels) { struct conf_sched_scan_settings *c = &wl->conf.sched_scan; int i, j; @@ -334,7 +361,7 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, bool force_passive = !req->n_ssids; for (i = 0, j = start; - i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS; + i < req->n_channels && j < max_channels; i++) { flags = req->channels[i]->flags; @@ -380,46 +407,42 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, return j - start; } -static int +static bool wl1271_scan_sched_scan_channels(struct wl1271 *wl, struct cfg80211_sched_scan_request *req, struct wl1271_cmd_sched_scan_config *cfg) { - int idx = 0; - cfg->passive[0] = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, IEEE80211_BAND_2GHZ, - false, true, idx); - idx += cfg->passive[0]; - + false, true, 0, + MAX_CHANNELS_2GHZ); cfg->active[0] = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, IEEE80211_BAND_2GHZ, - false, false, idx); - /* - * 5GHz channels always start at position 14, not immediately - * after the last 2.4GHz channel - */ - idx = 14; - + false, false, + cfg->passive[0], + MAX_CHANNELS_2GHZ); cfg->passive[1] = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, IEEE80211_BAND_5GHZ, - false, true, idx); - idx += cfg->passive[1]; - + false, true, 0, + MAX_CHANNELS_5GHZ); cfg->dfs = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, IEEE80211_BAND_5GHZ, - true, true, idx); - idx += cfg->dfs; - + true, true, + cfg->passive[1], + MAX_CHANNELS_5GHZ); cfg->active[1] = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, IEEE80211_BAND_5GHZ, - false, false, idx); - idx += cfg->active[1]; + false, false, + cfg->passive[1] + cfg->dfs, + MAX_CHANNELS_5GHZ); + /* 802.11j channels are not supported yet */ + cfg->passive[2] = 0; + cfg->active[2] = 0; wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d", cfg->active[0], cfg->passive[0]); @@ -427,7 +450,9 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl, cfg->active[1], cfg->passive[1]); wl1271_debug(DEBUG_SCAN, " DFS: %d", cfg->dfs); - return idx; + return cfg->passive[0] || cfg->active[0] || + cfg->passive[1] || cfg->active[1] || cfg->dfs || + cfg->passive[2] || cfg->active[2]; } int wl1271_scan_sched_scan_config(struct wl1271 *wl, @@ -436,7 +461,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, { struct wl1271_cmd_sched_scan_config *cfg = NULL; struct conf_sched_scan_settings *c = &wl->conf.sched_scan; - int i, total_channels, ret; + int i, ret; bool force_passive = !req->n_ssids; wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); @@ -471,8 +496,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, cfg->ssid_len = 0; } - total_channels = wl1271_scan_sched_scan_channels(wl, req, cfg); - if (total_channels == 0) { + if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { wl1271_error("scan channel list is empty"); ret = -EINVAL; goto out; diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h index a0b6c5d67b07..d882e4da71b7 100644 --- a/drivers/net/wireless/wl12xx/scan.h +++ b/drivers/net/wireless/wl12xx/scan.h @@ -28,6 +28,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req); +int wl1271_scan_stop(struct wl1271 *wl); int wl1271_scan_build_probe_req(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len, u8 band); @@ -112,19 +113,14 @@ struct wl1271_cmd_trigger_scan_to { __le32 timeout; } __packed; -#define MAX_CHANNELS_ALL_BANDS 41 +#define MAX_CHANNELS_2GHZ 14 +#define MAX_CHANNELS_5GHZ 23 +#define MAX_CHANNELS_4GHZ 4 + #define SCAN_MAX_CYCLE_INTERVALS 16 #define SCAN_MAX_BANDS 3 enum { - SCAN_CHANNEL_TYPE_2GHZ_PASSIVE, - SCAN_CHANNEL_TYPE_2GHZ_ACTIVE, - SCAN_CHANNEL_TYPE_5GHZ_PASSIVE, - SCAN_CHANNEL_TYPE_5GHZ_ACTIVE, - SCAN_CHANNEL_TYPE_5GHZ_DFS, -}; - -enum { SCAN_SSID_FILTER_ANY = 0, SCAN_SSID_FILTER_SPECIFIC = 1, SCAN_SSID_FILTER_LIST = 2, @@ -182,7 +178,9 @@ struct wl1271_cmd_sched_scan_config { u8 padding[3]; - struct conn_scan_ch_params channels[MAX_CHANNELS_ALL_BANDS]; + struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; + struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ]; + struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; } __packed; diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 536e5065454b..5cf18c2c23f0 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -23,7 +23,6 @@ #include <linux/irq.h> #include <linux/module.h> -#include <linux/crc7.h> #include <linux/vmalloc.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> @@ -45,7 +44,7 @@ #define SDIO_DEVICE_ID_TI_WL1271 0x4076 #endif -static const struct sdio_device_id wl1271_devices[] = { +static const struct sdio_device_id wl1271_devices[] __devinitconst = { { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, {} }; @@ -107,14 +106,6 @@ static void wl1271_sdio_enable_interrupts(struct wl1271 *wl) enable_irq(wl->irq); } -static void wl1271_sdio_reset(struct wl1271 *wl) -{ -} - -static void wl1271_sdio_init(struct wl1271 *wl) -{ -} - static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { @@ -170,15 +161,17 @@ static int wl1271_sdio_power_on(struct wl1271 *wl) struct sdio_func *func = wl_to_func(wl); int ret; - /* Make sure the card will not be powered off by runtime PM */ - ret = pm_runtime_get_sync(&func->dev); - if (ret < 0) - goto out; - - /* Runtime PM might be disabled, so power up the card manually */ - ret = mmc_power_restore_host(func->card->host); - if (ret < 0) - goto out; + /* If enabled, tell runtime PM not to power off the card */ + if (pm_runtime_enabled(&func->dev)) { + ret = pm_runtime_get_sync(&func->dev); + if (ret) + goto out; + } else { + /* Runtime PM is disabled: power up the card manually */ + ret = mmc_power_restore_host(func->card->host); + if (ret < 0) + goto out; + } sdio_claim_host(func); sdio_enable_func(func); @@ -195,13 +188,16 @@ static int wl1271_sdio_power_off(struct wl1271 *wl) sdio_disable_func(func); sdio_release_host(func); - /* Runtime PM might be disabled, so power off the card manually */ + /* Power off the card manually, even if runtime PM is enabled. */ ret = mmc_power_save_host(func->card->host); if (ret < 0) return ret; - /* Let runtime PM know the card is powered off */ - return pm_runtime_put_sync(&func->dev); + /* If enabled, let runtime PM know the card is powered off */ + if (pm_runtime_enabled(&func->dev)) + ret = pm_runtime_put_sync(&func->dev); + + return ret; } static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) @@ -215,8 +211,6 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) static struct wl1271_if_operations sdio_ops = { .read = wl1271_sdio_raw_read, .write = wl1271_sdio_raw_write, - .reset = wl1271_sdio_reset, - .init = wl1271_sdio_init, .power = wl1271_sdio_set_power, .dev = wl1271_sdio_wl_to_dev, .enable_irq = wl1271_sdio_enable_interrupts, @@ -278,17 +272,19 @@ static int __devinit wl1271_probe(struct sdio_func *func, goto out_free; } - enable_irq_wake(wl->irq); - device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1); + ret = enable_irq_wake(wl->irq); + if (!ret) { + wl->irq_wake_enabled = true; + device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1); - disable_irq(wl->irq); - - /* if sdio can keep power while host is suspended, enable wow */ - mmcflags = sdio_get_host_pm_caps(func); - wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags); + /* if sdio can keep power while host is suspended, enable wow */ + mmcflags = sdio_get_host_pm_caps(func); + wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags); - if (mmcflags & MMC_PM_KEEP_POWER) - hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; + if (mmcflags & MMC_PM_KEEP_POWER) + hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; + } + disable_irq(wl->irq); ret = wl1271_init_ieee80211(wl); if (ret) @@ -303,8 +299,6 @@ static int __devinit wl1271_probe(struct sdio_func *func, /* Tell PM core that we don't need the card to be powered now */ pm_runtime_put_noidle(&func->dev); - wl1271_notice("initialized"); - return 0; out_irq: @@ -324,8 +318,10 @@ static void __devexit wl1271_remove(struct sdio_func *func) pm_runtime_get_noresume(&func->dev); wl1271_unregister_hw(wl); - device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0); - disable_irq_wake(wl->irq); + if (wl->irq_wake_enabled) { + device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0); + disable_irq_wake(wl->irq); + } free_irq(wl->irq, wl); wl1271_free_hw(wl); } @@ -402,23 +398,12 @@ static struct sdio_driver wl1271_sdio_driver = { static int __init wl1271_init(void) { - int ret; - - ret = sdio_register_driver(&wl1271_sdio_driver); - if (ret < 0) { - wl1271_error("failed to register sdio driver: %d", ret); - goto out; - } - -out: - return ret; + return sdio_register_driver(&wl1271_sdio_driver); } static void __exit wl1271_exit(void) { sdio_unregister_driver(&wl1271_sdio_driver); - - wl1271_notice("unloaded"); } module_init(wl1271_init); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 51662bb68019..b73cee117ada 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -435,8 +435,6 @@ static int __devinit wl1271_probe(struct spi_device *spi) if (ret) goto out_irq; - wl1271_notice("initialized"); - return 0; out_irq: @@ -473,23 +471,12 @@ static struct spi_driver wl1271_spi_driver = { static int __init wl1271_init(void) { - int ret; - - ret = spi_register_driver(&wl1271_spi_driver); - if (ret < 0) { - wl1271_error("failed to register spi driver: %d", ret); - goto out; - } - -out: - return ret; + return spi_register_driver(&wl1271_spi_driver); } static void __exit wl1271_exit(void) { spi_unregister_driver(&wl1271_spi_driver); - - wl1271_notice("unloaded"); } module_init(wl1271_init); diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c index da351d7cd1f2..5d5e1ef87206 100644 --- a/drivers/net/wireless/wl12xx/testmode.c +++ b/drivers/net/wireless/wl12xx/testmode.c @@ -260,7 +260,7 @@ static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) { wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); - ieee80211_queue_work(wl->hw, &wl->recovery_work); + wl12xx_queue_recovery_work(wl); return 0; } diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index ca3ab1c1acef..48fde96ce0d4 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -168,7 +168,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 len; u32 total_blocks; - int id, ret = -EBUSY; + int id, ret = -EBUSY, ac; u32 spare_blocks; if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) @@ -206,7 +206,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, desc->id = id; wl->tx_blocks_available -= total_blocks; - wl->tx_allocated_blocks += total_blocks; + + ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + wl->tx_allocated_blocks[ac] += total_blocks; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->links[hlid].allocated_blks += total_blocks; @@ -383,6 +385,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (ret < 0) return ret; + wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); + if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); wl1271_tx_regulate_link(wl, hlid); @@ -390,8 +394,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, wl1271_tx_update_filters(wl, skb); } - wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); - /* * The length of each packet is stored in terms of * words. Thus, we must pad the skb data to make sure its @@ -442,37 +444,62 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) void wl1271_handle_tx_low_watermark(struct wl1271 *wl) { unsigned long flags; + int i; - if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && - wl->tx_queue_count <= WL1271_TX_QUEUE_LOW_WATERMARK) { - /* firmware buffer has space, restart queues */ - spin_lock_irqsave(&wl->wl_lock, flags); - ieee80211_wake_queues(wl->hw); - clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); - spin_unlock_irqrestore(&wl->wl_lock, flags); + for (i = 0; i < NUM_TX_QUEUES; i++) { + if (test_bit(i, &wl->stopped_queues_map) && + wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { + /* firmware buffer has space, restart queues */ + spin_lock_irqsave(&wl->wl_lock, flags); + ieee80211_wake_queue(wl->hw, + wl1271_tx_get_mac80211_queue(i)); + clear_bit(i, &wl->stopped_queues_map); + spin_unlock_irqrestore(&wl->wl_lock, flags); + } } } +static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, + struct sk_buff_head *queues) +{ + int i, q = -1; + u32 min_blks = 0xffffffff; + + /* + * Find a non-empty ac where: + * 1. There are packets to transmit + * 2. The FW has the least allocated blocks + */ + for (i = 0; i < NUM_TX_QUEUES; i++) + if (!skb_queue_empty(&queues[i]) && + (wl->tx_allocated_blocks[i] < min_blks)) { + q = i; + min_blks = wl->tx_allocated_blocks[q]; + } + + if (q == -1) + return NULL; + + return &queues[q]; +} + static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) { struct sk_buff *skb = NULL; unsigned long flags; + struct sk_buff_head *queue; - skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]); - if (skb) - goto out; - skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]); - if (skb) - goto out; - skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]); - if (skb) + queue = wl1271_select_queue(wl, wl->tx_queue); + if (!queue) goto out; - skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]); + + skb = skb_dequeue(queue); out: if (skb) { + int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count--; + wl->tx_queue_count[q]--; spin_unlock_irqrestore(&wl->wl_lock, flags); } @@ -484,6 +511,7 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) struct sk_buff *skb = NULL; unsigned long flags; int i, h, start_hlid; + struct sk_buff_head *queue; /* start from the link after the last one */ start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; @@ -492,25 +520,25 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) for (i = 0; i < AP_MAX_LINKS; i++) { h = (start_hlid + i) % AP_MAX_LINKS; - skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]); - if (skb) - goto out; - skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]); - if (skb) - goto out; - skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]); - if (skb) - goto out; - skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]); + /* only consider connected stations */ + if (h >= WL1271_AP_STA_HLID_START && + !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map)) + continue; + + queue = wl1271_select_queue(wl, wl->links[h].tx_queue); + if (!queue) + continue; + + skb = skb_dequeue(queue); if (skb) - goto out; + break; } -out: if (skb) { + int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); wl->last_tx_hlid = h; spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count--; + wl->tx_queue_count[q]--; spin_unlock_irqrestore(&wl->wl_lock, flags); } else { wl->last_tx_hlid = 0; @@ -531,9 +559,12 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) if (!skb && test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { + int q; + skb = wl->dummy_packet; + q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count--; + wl->tx_queue_count[q]--; spin_unlock_irqrestore(&wl->wl_lock, flags); } @@ -558,21 +589,33 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) } spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count++; + wl->tx_queue_count[q]++; spin_unlock_irqrestore(&wl->wl_lock, flags); } +static bool wl1271_tx_is_data_present(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + + return ieee80211_is_data_present(hdr->frame_control); +} + void wl1271_tx_work_locked(struct wl1271 *wl) { struct sk_buff *skb; u32 buf_offset = 0; bool sent_packets = false; + bool had_data = false; + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); int ret; if (unlikely(wl->state == WL1271_STATE_OFF)) return; while ((skb = wl1271_skb_dequeue(wl))) { + if (wl1271_tx_is_data_present(skb)) + had_data = true; + ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); if (ret == -EAGAIN) { /* @@ -619,6 +662,19 @@ out_ack: wl1271_handle_tx_low_watermark(wl); } + if (!is_ap && wl->conf.rx_streaming.interval && had_data && + (wl->conf.rx_streaming.always || + test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) { + u32 timeout = wl->conf.rx_streaming.duration; + + /* enable rx streaming */ + if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) + ieee80211_queue_work(wl->hw, + &wl->rx_streaming_enable_work); + + mod_timer(&wl->rx_streaming_timer, + jiffies + msecs_to_jiffies(timeout)); + } } void wl1271_tx_work(struct work_struct *work) @@ -679,10 +735,24 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, wl->stats.retry_count += result->ack_failures; - /* update security sequence number */ - wl->tx_security_seq += (result->lsb_security_sequence_number - - wl->tx_security_last_seq); - wl->tx_security_last_seq = result->lsb_security_sequence_number; + /* + * update sequence number only when relevant, i.e. only in + * sessions of TKIP, AES and GEM (not in open or WEP sessions) + */ + if (info->control.hw_key && + (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP || + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || + info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { + u8 fw_lsb = result->tx_security_sequence_number_lsb; + u8 cur_lsb = wl->tx_security_last_seq_lsb; + + /* + * update security sequence number, taking care of potential + * wrap-around + */ + wl->tx_security_seq += (fw_lsb - cur_lsb + 256) % 256; + wl->tx_security_last_seq_lsb = fw_lsb; + } /* remove private header from packet */ skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); @@ -702,7 +772,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, /* return the packet to the stack */ skb_queue_tail(&wl->deferred_tx_queue, skb); - ieee80211_queue_work(wl->hw, &wl->netstack_work); + queue_work(wl->freezable_wq, &wl->netstack_work); wl1271_free_tx_id(wl, result->id); } @@ -747,23 +817,26 @@ void wl1271_tx_complete(struct wl1271 *wl) void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) { struct sk_buff *skb; - int i, total = 0; + int i; unsigned long flags; struct ieee80211_tx_info *info; + int total[NUM_TX_QUEUES]; for (i = 0; i < NUM_TX_QUEUES; i++) { + total[i] = 0; while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); info = IEEE80211_SKB_CB(skb); info->status.rates[0].idx = -1; info->status.rates[0].count = 0; - ieee80211_tx_status(wl->hw, skb); - total++; + ieee80211_tx_status_ni(wl->hw, skb); + total[i]++; } } spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count -= total; + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_queue_count[i] -= total[i]; spin_unlock_irqrestore(&wl->wl_lock, flags); wl1271_handle_tx_low_watermark(wl); @@ -795,13 +868,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) info = IEEE80211_SKB_CB(skb); info->status.rates[0].idx = -1; info->status.rates[0].count = 0; - ieee80211_tx_status(wl->hw, skb); + ieee80211_tx_status_ni(wl->hw, skb); } } + wl->tx_queue_count[i] = 0; } } - wl->tx_queue_count = 0; + wl->stopped_queues_map = 0; /* * Make sure the driver is at a consistent state, in case this @@ -838,7 +912,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) info->status.rates[0].idx = -1; info->status.rates[0].count = 0; - ieee80211_tx_status(wl->hw, skb); + ieee80211_tx_status_ni(wl->hw, skb); } } } @@ -854,8 +928,10 @@ void wl1271_tx_flush(struct wl1271 *wl) while (!time_after(jiffies, timeout)) { mutex_lock(&wl->mutex); wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", - wl->tx_frames_cnt, wl->tx_queue_count); - if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) { + wl->tx_frames_cnt, + wl1271_tx_total_queue_count(wl)); + if ((wl->tx_frames_cnt == 0) && + (wl1271_tx_total_queue_count(wl) == 0)) { mutex_unlock(&wl->mutex); return; } diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 832f9258d675..5d719b5a3d1d 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -150,7 +150,7 @@ struct wl1271_tx_hw_res_descr { (from 1st EDCA AIFS counter until TX Complete). */ __le32 medium_delay; /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ - u8 lsb_security_sequence_number; + u8 tx_security_sequence_number_lsb; /* Retry count - number of transmissions without successful ACK.*/ u8 ack_failures; /* The rate that succeeded getting ACK @@ -182,6 +182,32 @@ static inline int wl1271_tx_get_queue(int queue) } } +static inline int wl1271_tx_get_mac80211_queue(int queue) +{ + switch (queue) { + case CONF_TX_AC_VO: + return 0; + case CONF_TX_AC_VI: + return 1; + case CONF_TX_AC_BE: + return 2; + case CONF_TX_AC_BK: + return 3; + default: + return 2; + } +} + +static inline int wl1271_tx_total_queue_count(struct wl1271 *wl) +{ + int i, count = 0; + + for (i = 0; i < NUM_TX_QUEUES; i++) + count += wl->tx_queue_count[i]; + + return count; +} + void wl1271_tx_work(struct work_struct *work); void wl1271_tx_work_locked(struct wl1271 *wl); void wl1271_tx_complete(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 3bc794a1ee75..1a8751eb8140 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -144,6 +144,7 @@ extern u32 wl12xx_debug_level; #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) +#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff #define WL1271_CIPHER_SUITE_GEM 0x00147201 @@ -172,7 +173,6 @@ extern u32 wl12xx_debug_level; #define WL1271_PS_STA_MAX_BLOCKS (2 * 9) #define WL1271_AP_BSS_INDEX 0 -#define WL1271_AP_DEF_INACTIV_SEC 300 #define WL1271_AP_DEF_BEACON_EXP 20 #define ACX_TX_DESCRIPTORS 32 @@ -226,6 +226,8 @@ enum { #define FW_VER_MINOR_1_SPARE_STA_MIN 58 #define FW_VER_MINOR_1_SPARE_AP_MIN 47 +#define FW_VER_MINOR_FWLOG_STA_MIN 70 + struct wl1271_chip { u32 id; char fw_ver_str[ETHTOOL_BUSINFO_LEN]; @@ -284,8 +286,7 @@ struct wl1271_fw_sta_status { u8 tx_total; u8 reserved1; __le16 reserved2; - /* Total structure size is 68 bytes */ - u32 padding; + __le32 log_start_addr; } __packed; struct wl1271_fw_full_status { @@ -359,6 +360,9 @@ enum wl12xx_flags { WL1271_FLAG_DUMMY_PACKET_PENDING, WL1271_FLAG_SUSPENDED, WL1271_FLAG_PENDING_WORK, + WL1271_FLAG_SOFT_GEMINI, + WL1271_FLAG_RX_STREAMING_STARTED, + WL1271_FLAG_RECOVERY_IN_PROGRESS, }; struct wl1271_link { @@ -420,7 +424,7 @@ struct wl1271 { /* Accounting for allocated / available TX blocks on HW */ u32 tx_blocks_freed[NUM_TX_QUEUES]; u32 tx_blocks_available; - u32 tx_allocated_blocks; + u32 tx_allocated_blocks[NUM_TX_QUEUES]; u32 tx_results_count; /* Transmitted TX packets counter for chipset interface */ @@ -434,7 +438,8 @@ struct wl1271 { /* Frames scheduled for transmission, not handled yet */ struct sk_buff_head tx_queue[NUM_TX_QUEUES]; - int tx_queue_count; + int tx_queue_count[NUM_TX_QUEUES]; + long stopped_queues_map; /* Frames received, not handled yet by mac80211 */ struct sk_buff_head deferred_rx_queue; @@ -443,15 +448,23 @@ struct wl1271 { struct sk_buff_head deferred_tx_queue; struct work_struct tx_work; + struct workqueue_struct *freezable_wq; /* Pending TX frames */ unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)]; struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; int tx_frames_cnt; - /* Security sequence number counters */ - u8 tx_security_last_seq; - s64 tx_security_seq; + /* + * Security sequence number + * bits 0-15: lower 16 bits part of sequence number + * bits 16-47: higher 32 bits part of sequence number + * bits 48-63: not in use + */ + u64 tx_security_seq; + + /* 8 bits of the last sequence number in use */ + u8 tx_security_last_seq_lsb; /* FW Rx counter */ u32 rx_counter; @@ -468,6 +481,15 @@ struct wl1271 { /* Network stack work */ struct work_struct netstack_work; + /* FW log buffer */ + u8 *fwlog; + + /* Number of valid bytes in the FW log buffer */ + ssize_t fwlog_size; + + /* Sysfs FW log entry readers wait queue */ + wait_queue_head_t fwlog_waitq; + /* Hardware recovery work */ struct work_struct recovery_work; @@ -508,6 +530,11 @@ struct wl1271 { /* Default key (for WEP) */ u32 default_key; + /* Rx Streaming */ + struct work_struct rx_streaming_enable_work; + struct work_struct rx_streaming_disable_work; + struct timer_list rx_streaming_timer; + unsigned int filters; unsigned int rx_config; unsigned int rx_filter; @@ -573,6 +600,7 @@ struct wl1271 { * (currently, only "ANY" trigger is supported) */ bool wow_enabled; + bool irq_wake_enabled; /* * AP-mode - links indexed by HLID. The global and broadcast links @@ -602,6 +630,9 @@ struct wl1271_station { int wl1271_plt_start(struct wl1271 *wl); int wl1271_plt_stop(struct wl1271 *wl); +int wl1271_recalc_rx_streaming(struct wl1271 *wl); +void wl12xx_queue_recovery_work(struct wl1271 *wl); +size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ @@ -609,8 +640,8 @@ int wl1271_plt_stop(struct wl1271 *wl); #define WL1271_DEFAULT_POWER_LEVEL 0 -#define WL1271_TX_QUEUE_LOW_WATERMARK 10 -#define WL1271_TX_QUEUE_HIGH_WATERMARK 25 +#define WL1271_TX_QUEUE_LOW_WATERMARK 32 +#define WL1271_TX_QUEUE_HIGH_WATERMARK 256 #define WL1271_DEFERRED_QUEUE_LIMIT 64 @@ -637,4 +668,15 @@ int wl1271_plt_stop(struct wl1271 *wl); /* WL128X requires aggregated packets to be aligned to the SDIO block size */ #define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) +/* + * WL127X AP mode requires Low Power DRPw (LPD) enable to reduce power + * consumption + */ +#define WL12XX_QUIRK_LPD_MODE BIT(3) + +/* Older firmwares did not implement the FW logger over bus feature */ +#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4) + +#define WL12XX_HW_BLOCK_SIZE 256 + #endif diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index ea1580085347..2acff4307ca4 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -2,17 +2,8 @@ # Near Field Communication (NFC) devices # -menuconfig NFC_DEVICES - bool "Near Field Communication (NFC) devices" - default n - ---help--- - You'll have to say Y if your computer contains an NFC device that - you want to use under Linux. - - You can say N here if you don't have any Near Field Communication - devices connected to your computer. - -if NFC_DEVICES +menu "Near Field Communication (NFC) devices" + depends on NFC config PN544_NFC tristate "PN544 NFC driver" @@ -26,5 +17,14 @@ config PN544_NFC To compile this driver as a module, choose m here. The module will be called pn544. +config NFC_PN533 + tristate "NXP PN533 USB driver" + depends on USB + help + NXP PN533 USB driver. + This driver provides support for NFC NXP PN533 devices. + + Say Y here to compile support for PN533 devices into the + kernel or say M to compile it as module (pn533). -endif # NFC_DEVICES +endmenu diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index a4efb164ec49..8ef446d2c1bd 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -3,3 +3,6 @@ # obj-$(CONFIG_PN544_NFC) += pn544.o +obj-$(CONFIG_NFC_PN533) += pn533.o + +ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c new file mode 100644 index 000000000000..037231540719 --- /dev/null +++ b/drivers/nfc/pn533.c @@ -0,0 +1,1632 @@ +/* + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * + * Authors: + * Lauro Ramos Venancio <lauro.venancio@openbossa.org> + * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/nfc.h> +#include <linux/netdevice.h> +#include <net/nfc.h> + +#define VERSION "0.1" + +#define PN533_VENDOR_ID 0x4CC +#define PN533_PRODUCT_ID 0x2533 + +#define SCM_VENDOR_ID 0x4E6 +#define SCL3711_PRODUCT_ID 0x5591 + +static const struct usb_device_id pn533_table[] = { + { USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID) }, + { USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID) }, + { } +}; +MODULE_DEVICE_TABLE(usb, pn533_table); + +/* frame definitions */ +#define PN533_FRAME_TAIL_SIZE 2 +#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \ + PN533_FRAME_TAIL_SIZE) +#define PN533_FRAME_ACK_SIZE (sizeof(struct pn533_frame) + 1) +#define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen]) +#define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1]) + +/* start of frame */ +#define PN533_SOF 0x00FF + +/* frame identifier: in/out/error */ +#define PN533_FRAME_IDENTIFIER(f) (f->data[0]) +#define PN533_DIR_OUT 0xD4 +#define PN533_DIR_IN 0xD5 + +/* PN533 Commands */ +#define PN533_FRAME_CMD(f) (f->data[1]) +#define PN533_FRAME_CMD_PARAMS_PTR(f) (&f->data[2]) +#define PN533_FRAME_CMD_PARAMS_LEN(f) (f->datalen - 2) + +#define PN533_CMD_GET_FIRMWARE_VERSION 0x02 +#define PN533_CMD_RF_CONFIGURATION 0x32 +#define PN533_CMD_IN_DATA_EXCHANGE 0x40 +#define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A +#define PN533_CMD_IN_ATR 0x50 +#define PN533_CMD_IN_RELEASE 0x52 + +#define PN533_CMD_RESPONSE(cmd) (cmd + 1) + +/* PN533 Return codes */ +#define PN533_CMD_RET_MASK 0x3F +#define PN533_CMD_MI_MASK 0x40 +#define PN533_CMD_RET_SUCCESS 0x00 + +struct pn533; + +typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, + u8 *params, int params_len); + +/* structs for pn533 commands */ + +/* PN533_CMD_GET_FIRMWARE_VERSION */ +struct pn533_fw_version { + u8 ic; + u8 ver; + u8 rev; + u8 support; +}; + +/* PN533_CMD_RF_CONFIGURATION */ +#define PN533_CFGITEM_MAX_RETRIES 0x05 + +#define PN533_CONFIG_MAX_RETRIES_NO_RETRY 0x00 +#define PN533_CONFIG_MAX_RETRIES_ENDLESS 0xFF + +struct pn533_config_max_retries { + u8 mx_rty_atr; + u8 mx_rty_psl; + u8 mx_rty_passive_act; +} __packed; + +/* PN533_CMD_IN_LIST_PASSIVE_TARGET */ + +/* felica commands opcode */ +#define PN533_FELICA_OPC_SENSF_REQ 0 +#define PN533_FELICA_OPC_SENSF_RES 1 +/* felica SENSF_REQ parameters */ +#define PN533_FELICA_SENSF_SC_ALL 0xFFFF +#define PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE 0 +#define PN533_FELICA_SENSF_RC_SYSTEM_CODE 1 +#define PN533_FELICA_SENSF_RC_ADVANCED_PROTOCOL 2 + +/* type B initiator_data values */ +#define PN533_TYPE_B_AFI_ALL_FAMILIES 0 +#define PN533_TYPE_B_POLL_METHOD_TIMESLOT 0 +#define PN533_TYPE_B_POLL_METHOD_PROBABILISTIC 1 + +union pn533_cmd_poll_initdata { + struct { + u8 afi; + u8 polling_method; + } __packed type_b; + struct { + u8 opcode; + __be16 sc; + u8 rc; + u8 tsn; + } __packed felica; +}; + +/* Poll modulations */ +enum { + PN533_POLL_MOD_106KBPS_A, + PN533_POLL_MOD_212KBPS_FELICA, + PN533_POLL_MOD_424KBPS_FELICA, + PN533_POLL_MOD_106KBPS_JEWEL, + PN533_POLL_MOD_847KBPS_B, + + __PN533_POLL_MOD_AFTER_LAST, +}; +#define PN533_POLL_MOD_MAX (__PN533_POLL_MOD_AFTER_LAST - 1) + +struct pn533_poll_modulations { + struct { + u8 maxtg; + u8 brty; + union pn533_cmd_poll_initdata initiator_data; + } __packed data; + u8 len; +}; + +const struct pn533_poll_modulations poll_mod[] = { + [PN533_POLL_MOD_106KBPS_A] = { + .data = { + .maxtg = 1, + .brty = 0, + }, + .len = 2, + }, + [PN533_POLL_MOD_212KBPS_FELICA] = { + .data = { + .maxtg = 1, + .brty = 1, + .initiator_data.felica = { + .opcode = PN533_FELICA_OPC_SENSF_REQ, + .sc = PN533_FELICA_SENSF_SC_ALL, + .rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE, + .tsn = 0, + }, + }, + .len = 7, + }, + [PN533_POLL_MOD_424KBPS_FELICA] = { + .data = { + .maxtg = 1, + .brty = 2, + .initiator_data.felica = { + .opcode = PN533_FELICA_OPC_SENSF_REQ, + .sc = PN533_FELICA_SENSF_SC_ALL, + .rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE, + .tsn = 0, + }, + }, + .len = 7, + }, + [PN533_POLL_MOD_106KBPS_JEWEL] = { + .data = { + .maxtg = 1, + .brty = 4, + }, + .len = 2, + }, + [PN533_POLL_MOD_847KBPS_B] = { + .data = { + .maxtg = 1, + .brty = 8, + .initiator_data.type_b = { + .afi = PN533_TYPE_B_AFI_ALL_FAMILIES, + .polling_method = + PN533_TYPE_B_POLL_METHOD_TIMESLOT, + }, + }, + .len = 3, + }, +}; + +/* PN533_CMD_IN_ATR */ + +struct pn533_cmd_activate_param { + u8 tg; + u8 next; +} __packed; + +struct pn533_cmd_activate_response { + u8 status; + u8 nfcid3t[10]; + u8 didt; + u8 bst; + u8 brt; + u8 to; + u8 ppt; + /* optional */ + u8 gt[]; +} __packed; + + +struct pn533 { + struct usb_device *udev; + struct usb_interface *interface; + struct nfc_dev *nfc_dev; + + struct urb *out_urb; + int out_maxlen; + struct pn533_frame *out_frame; + + struct urb *in_urb; + int in_maxlen; + struct pn533_frame *in_frame; + + struct tasklet_struct tasklet; + struct pn533_frame *tklt_in_frame; + int tklt_in_error; + + pn533_cmd_complete_t cmd_complete; + void *cmd_complete_arg; + struct semaphore cmd_lock; + u8 cmd; + + struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1]; + u8 poll_mod_count; + u8 poll_mod_curr; + u32 poll_protocols; + + u8 tgt_available_prots; + u8 tgt_active_prot; +}; + +struct pn533_frame { + u8 preamble; + __be16 start_frame; + u8 datalen; + u8 datalen_checksum; + u8 data[]; +} __packed; + +/* The rule: value + checksum = 0 */ +static inline u8 pn533_checksum(u8 value) +{ + return ~value + 1; +} + +/* The rule: sum(data elements) + checksum = 0 */ +static u8 pn533_data_checksum(u8 *data, int datalen) +{ + u8 sum = 0; + int i; + + for (i = 0; i < datalen; i++) + sum += data[i]; + + return pn533_checksum(sum); +} + +/** + * pn533_tx_frame_ack - create a ack frame + * @frame: The frame to be set as ack + * + * Ack is different type of standard frame. As a standard frame, it has + * preamble and start_frame. However the checksum of this frame must fail, + * i.e. datalen + datalen_checksum must NOT be zero. When the checksum test + * fails and datalen = 0 and datalen_checksum = 0xFF, the frame is a ack. + * After datalen_checksum field, the postamble is placed. + */ +static void pn533_tx_frame_ack(struct pn533_frame *frame) +{ + frame->preamble = 0; + frame->start_frame = cpu_to_be16(PN533_SOF); + frame->datalen = 0; + frame->datalen_checksum = 0xFF; + /* data[0] is used as postamble */ + frame->data[0] = 0; +} + +static void pn533_tx_frame_init(struct pn533_frame *frame, u8 cmd) +{ + frame->preamble = 0; + frame->start_frame = cpu_to_be16(PN533_SOF); + PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT; + PN533_FRAME_CMD(frame) = cmd; + frame->datalen = 2; +} + +static void pn533_tx_frame_finish(struct pn533_frame *frame) +{ + frame->datalen_checksum = pn533_checksum(frame->datalen); + + PN533_FRAME_CHECKSUM(frame) = + pn533_data_checksum(frame->data, frame->datalen); + + PN533_FRAME_POSTAMBLE(frame) = 0; +} + +static bool pn533_rx_frame_is_valid(struct pn533_frame *frame) +{ + u8 checksum; + + if (frame->start_frame != cpu_to_be16(PN533_SOF)) + return false; + + checksum = pn533_checksum(frame->datalen); + if (checksum != frame->datalen_checksum) + return false; + + checksum = pn533_data_checksum(frame->data, frame->datalen); + if (checksum != PN533_FRAME_CHECKSUM(frame)) + return false; + + return true; +} + +static bool pn533_rx_frame_is_ack(struct pn533_frame *frame) +{ + if (frame->start_frame != cpu_to_be16(PN533_SOF)) + return false; + + if (frame->datalen != 0 || frame->datalen_checksum != 0xFF) + return false; + + return true; +} + +static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd) +{ + return (PN533_FRAME_CMD(frame) == PN533_CMD_RESPONSE(cmd)); +} + +static void pn533_tasklet_cmd_complete(unsigned long arg) +{ + struct pn533 *dev = (struct pn533 *) arg; + struct pn533_frame *in_frame = dev->tklt_in_frame; + int rc; + + if (dev->tklt_in_error) + rc = dev->cmd_complete(dev, dev->cmd_complete_arg, NULL, + dev->tklt_in_error); + else + rc = dev->cmd_complete(dev, dev->cmd_complete_arg, + PN533_FRAME_CMD_PARAMS_PTR(in_frame), + PN533_FRAME_CMD_PARAMS_LEN(in_frame)); + + if (rc != -EINPROGRESS) + up(&dev->cmd_lock); +} + +static void pn533_recv_response(struct urb *urb) +{ + struct pn533 *dev = urb->context; + struct pn533_frame *in_frame; + + dev->tklt_in_frame = NULL; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with" + " status: %d", urb->status); + dev->tklt_in_error = urb->status; + goto sched_tasklet; + default: + nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:" + " %d", urb->status); + dev->tklt_in_error = urb->status; + goto sched_tasklet; + } + + in_frame = dev->in_urb->transfer_buffer; + + if (!pn533_rx_frame_is_valid(in_frame)) { + nfc_dev_err(&dev->interface->dev, "Received an invalid frame"); + dev->tklt_in_error = -EIO; + goto sched_tasklet; + } + + if (!pn533_rx_frame_is_cmd_response(in_frame, dev->cmd)) { + nfc_dev_err(&dev->interface->dev, "The received frame is not " + "response to the last command"); + dev->tklt_in_error = -EIO; + goto sched_tasklet; + } + + nfc_dev_dbg(&dev->interface->dev, "Received a valid frame"); + dev->tklt_in_error = 0; + dev->tklt_in_frame = in_frame; + +sched_tasklet: + tasklet_schedule(&dev->tasklet); +} + +static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) +{ + dev->in_urb->complete = pn533_recv_response; + + return usb_submit_urb(dev->in_urb, flags); +} + +static void pn533_recv_ack(struct urb *urb) +{ + struct pn533 *dev = urb->context; + struct pn533_frame *in_frame; + int rc; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with" + " status: %d", urb->status); + dev->tklt_in_error = urb->status; + goto sched_tasklet; + default: + nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:" + " %d", urb->status); + dev->tklt_in_error = urb->status; + goto sched_tasklet; + } + + in_frame = dev->in_urb->transfer_buffer; + + if (!pn533_rx_frame_is_ack(in_frame)) { + nfc_dev_err(&dev->interface->dev, "Received an invalid ack"); + dev->tklt_in_error = -EIO; + goto sched_tasklet; + } + + nfc_dev_dbg(&dev->interface->dev, "Received a valid ack"); + + rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC); + if (rc) { + nfc_dev_err(&dev->interface->dev, "usb_submit_urb failed with" + " result %d", rc); + dev->tklt_in_error = rc; + goto sched_tasklet; + } + + return; + +sched_tasklet: + dev->tklt_in_frame = NULL; + tasklet_schedule(&dev->tasklet); +} + +static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) +{ + dev->in_urb->complete = pn533_recv_ack; + + return usb_submit_urb(dev->in_urb, flags); +} + +static int pn533_send_ack(struct pn533 *dev, gfp_t flags) +{ + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + pn533_tx_frame_ack(dev->out_frame); + + dev->out_urb->transfer_buffer = dev->out_frame; + dev->out_urb->transfer_buffer_length = PN533_FRAME_ACK_SIZE; + rc = usb_submit_urb(dev->out_urb, flags); + + return rc; +} + +static int __pn533_send_cmd_frame_async(struct pn533 *dev, + struct pn533_frame *out_frame, + struct pn533_frame *in_frame, + int in_frame_len, + pn533_cmd_complete_t cmd_complete, + void *arg, gfp_t flags) +{ + int rc; + + nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", + PN533_FRAME_CMD(out_frame)); + + dev->cmd = PN533_FRAME_CMD(out_frame); + dev->cmd_complete = cmd_complete; + dev->cmd_complete_arg = arg; + + dev->out_urb->transfer_buffer = out_frame; + dev->out_urb->transfer_buffer_length = + PN533_FRAME_SIZE(out_frame); + + dev->in_urb->transfer_buffer = in_frame; + dev->in_urb->transfer_buffer_length = in_frame_len; + + rc = usb_submit_urb(dev->out_urb, flags); + if (rc) + return rc; + + rc = pn533_submit_urb_for_ack(dev, flags); + if (rc) + goto error; + + return 0; + +error: + usb_unlink_urb(dev->out_urb); + return rc; +} + +static int pn533_send_cmd_frame_async(struct pn533 *dev, + struct pn533_frame *out_frame, + struct pn533_frame *in_frame, + int in_frame_len, + pn533_cmd_complete_t cmd_complete, + void *arg, gfp_t flags) +{ + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + if (down_trylock(&dev->cmd_lock)) + return -EBUSY; + + rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, + in_frame_len, cmd_complete, arg, flags); + if (rc) + goto error; + + return 0; +error: + up(&dev->cmd_lock); + return rc; +} + +struct pn533_sync_cmd_response { + int rc; + struct completion done; +}; + +static int pn533_sync_cmd_complete(struct pn533 *dev, void *_arg, + u8 *params, int params_len) +{ + struct pn533_sync_cmd_response *arg = _arg; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + arg->rc = 0; + + if (params_len < 0) /* error */ + arg->rc = params_len; + + complete(&arg->done); + + return 0; +} + +static int pn533_send_cmd_frame_sync(struct pn533 *dev, + struct pn533_frame *out_frame, + struct pn533_frame *in_frame, + int in_frame_len) +{ + int rc; + struct pn533_sync_cmd_response arg; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + init_completion(&arg.done); + + rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, in_frame_len, + pn533_sync_cmd_complete, &arg, GFP_KERNEL); + if (rc) + return rc; + + wait_for_completion(&arg.done); + + return arg.rc; +} + +static void pn533_send_complete(struct urb *urb) +{ + struct pn533 *dev = urb->context; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with" + " status: %d", urb->status); + break; + default: + nfc_dev_dbg(&dev->interface->dev, "Nonzero urb status received:" + " %d", urb->status); + } +} + +struct pn533_target_type_a { + __be16 sens_res; + u8 sel_res; + u8 nfcid_len; + u8 nfcid_data[]; +} __packed; + + +#define PN533_TYPE_A_SENS_RES_NFCID1(x) ((u8)((be16_to_cpu(x) & 0x00C0) >> 6)) +#define PN533_TYPE_A_SENS_RES_SSD(x) ((u8)((be16_to_cpu(x) & 0x001F) >> 0)) +#define PN533_TYPE_A_SENS_RES_PLATCONF(x) ((u8)((be16_to_cpu(x) & 0x0F00) >> 8)) + +#define PN533_TYPE_A_SENS_RES_SSD_JEWEL 0x00 +#define PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL 0x0C + +#define PN533_TYPE_A_SEL_PROT(x) (((x) & 0x60) >> 5) +#define PN533_TYPE_A_SEL_CASCADE(x) (((x) & 0x04) >> 2) + +#define PN533_TYPE_A_SEL_PROT_MIFARE 0 +#define PN533_TYPE_A_SEL_PROT_ISO14443 1 +#define PN533_TYPE_A_SEL_PROT_DEP 2 +#define PN533_TYPE_A_SEL_PROT_ISO14443_DEP 3 + +static bool pn533_target_type_a_is_valid(struct pn533_target_type_a *type_a, + int target_data_len) +{ + u8 ssd; + u8 platconf; + + if (target_data_len < sizeof(struct pn533_target_type_a)) + return false; + + /* The lenght check of nfcid[] and ats[] are not being performed because + the values are not being used */ + + /* Requirement 4.6.3.3 from NFC Forum Digital Spec */ + ssd = PN533_TYPE_A_SENS_RES_SSD(type_a->sens_res); + platconf = PN533_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res); + + if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL && + platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || + (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && + platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) + return false; + + /* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */ + if (PN533_TYPE_A_SEL_CASCADE(type_a->sel_res) != 0) + return false; + + return true; +} + +static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data, + int tgt_data_len) +{ + struct pn533_target_type_a *tgt_type_a; + + tgt_type_a = (struct pn533_target_type_a *) tgt_data; + + if (!pn533_target_type_a_is_valid(tgt_type_a, tgt_data_len)) + return -EPROTO; + + switch (PN533_TYPE_A_SEL_PROT(tgt_type_a->sel_res)) { + case PN533_TYPE_A_SEL_PROT_MIFARE: + nfc_tgt->supported_protocols = NFC_PROTO_MIFARE_MASK; + break; + case PN533_TYPE_A_SEL_PROT_ISO14443: + nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK; + break; + case PN533_TYPE_A_SEL_PROT_DEP: + nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK; + break; + case PN533_TYPE_A_SEL_PROT_ISO14443_DEP: + nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK | + NFC_PROTO_NFC_DEP_MASK; + break; + } + + nfc_tgt->sens_res = be16_to_cpu(tgt_type_a->sens_res); + nfc_tgt->sel_res = tgt_type_a->sel_res; + + return 0; +} + +struct pn533_target_felica { + u8 pol_res; + u8 opcode; + u8 nfcid2[8]; + u8 pad[8]; + /* optional */ + u8 syst_code[]; +} __packed; + +#define PN533_FELICA_SENSF_NFCID2_DEP_B1 0x01 +#define PN533_FELICA_SENSF_NFCID2_DEP_B2 0xFE + +static bool pn533_target_felica_is_valid(struct pn533_target_felica *felica, + int target_data_len) +{ + if (target_data_len < sizeof(struct pn533_target_felica)) + return false; + + if (felica->opcode != PN533_FELICA_OPC_SENSF_RES) + return false; + + return true; +} + +static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data, + int tgt_data_len) +{ + struct pn533_target_felica *tgt_felica; + + tgt_felica = (struct pn533_target_felica *) tgt_data; + + if (!pn533_target_felica_is_valid(tgt_felica, tgt_data_len)) + return -EPROTO; + + if (tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1 && + tgt_felica->nfcid2[1] == + PN533_FELICA_SENSF_NFCID2_DEP_B2) + nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK; + else + nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK; + + return 0; +} + +struct pn533_target_jewel { + __be16 sens_res; + u8 jewelid[4]; +} __packed; + +static bool pn533_target_jewel_is_valid(struct pn533_target_jewel *jewel, + int target_data_len) +{ + u8 ssd; + u8 platconf; + + if (target_data_len < sizeof(struct pn533_target_jewel)) + return false; + + /* Requirement 4.6.3.3 from NFC Forum Digital Spec */ + ssd = PN533_TYPE_A_SENS_RES_SSD(jewel->sens_res); + platconf = PN533_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res); + + if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL && + platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || + (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && + platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) + return false; + + return true; +} + +static int pn533_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data, + int tgt_data_len) +{ + struct pn533_target_jewel *tgt_jewel; + + tgt_jewel = (struct pn533_target_jewel *) tgt_data; + + if (!pn533_target_jewel_is_valid(tgt_jewel, tgt_data_len)) + return -EPROTO; + + nfc_tgt->supported_protocols = NFC_PROTO_JEWEL_MASK; + nfc_tgt->sens_res = be16_to_cpu(tgt_jewel->sens_res); + + return 0; +} + +struct pn533_type_b_prot_info { + u8 bitrate; + u8 fsci_type; + u8 fwi_adc_fo; +} __packed; + +#define PN533_TYPE_B_PROT_FCSI(x) (((x) & 0xF0) >> 4) +#define PN533_TYPE_B_PROT_TYPE(x) (((x) & 0x0F) >> 0) +#define PN533_TYPE_B_PROT_TYPE_RFU_MASK 0x8 + +struct pn533_type_b_sens_res { + u8 opcode; + u8 nfcid[4]; + u8 appdata[4]; + struct pn533_type_b_prot_info prot_info; +} __packed; + +#define PN533_TYPE_B_OPC_SENSB_RES 0x50 + +struct pn533_target_type_b { + struct pn533_type_b_sens_res sensb_res; + u8 attrib_res_len; + u8 attrib_res[]; +} __packed; + +static bool pn533_target_type_b_is_valid(struct pn533_target_type_b *type_b, + int target_data_len) +{ + if (target_data_len < sizeof(struct pn533_target_type_b)) + return false; + + if (type_b->sensb_res.opcode != PN533_TYPE_B_OPC_SENSB_RES) + return false; + + if (PN533_TYPE_B_PROT_TYPE(type_b->sensb_res.prot_info.fsci_type) & + PN533_TYPE_B_PROT_TYPE_RFU_MASK) + return false; + + return true; +} + +static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data, + int tgt_data_len) +{ + struct pn533_target_type_b *tgt_type_b; + + tgt_type_b = (struct pn533_target_type_b *) tgt_data; + + if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len)) + return -EPROTO; + + nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK; + + return 0; +} + +struct pn533_poll_response { + u8 nbtg; + u8 tg; + u8 target_data[]; +} __packed; + +static int pn533_target_found(struct pn533 *dev, + struct pn533_poll_response *resp, int resp_len) +{ + int target_data_len; + struct nfc_target nfc_tgt; + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s - modulation=%d", __func__, + dev->poll_mod_curr); + + if (resp->tg != 1) + return -EPROTO; + + target_data_len = resp_len - sizeof(struct pn533_poll_response); + + switch (dev->poll_mod_curr) { + case PN533_POLL_MOD_106KBPS_A: + rc = pn533_target_found_type_a(&nfc_tgt, resp->target_data, + target_data_len); + break; + case PN533_POLL_MOD_212KBPS_FELICA: + case PN533_POLL_MOD_424KBPS_FELICA: + rc = pn533_target_found_felica(&nfc_tgt, resp->target_data, + target_data_len); + break; + case PN533_POLL_MOD_106KBPS_JEWEL: + rc = pn533_target_found_jewel(&nfc_tgt, resp->target_data, + target_data_len); + break; + case PN533_POLL_MOD_847KBPS_B: + rc = pn533_target_found_type_b(&nfc_tgt, resp->target_data, + target_data_len); + break; + default: + nfc_dev_err(&dev->interface->dev, "Unknown current poll" + " modulation"); + return -EPROTO; + } + + if (rc) + return rc; + + if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) { + nfc_dev_dbg(&dev->interface->dev, "The target found does not" + " have the desired protocol"); + return -EAGAIN; + } + + nfc_dev_dbg(&dev->interface->dev, "Target found - supported protocols: " + "0x%x", nfc_tgt.supported_protocols); + + dev->tgt_available_prots = nfc_tgt.supported_protocols; + + nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1); + + return 0; +} + +static void pn533_poll_reset_mod_list(struct pn533 *dev) +{ + dev->poll_mod_count = 0; +} + +static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index) +{ + dev->poll_mod_active[dev->poll_mod_count] = + (struct pn533_poll_modulations *) &poll_mod[mod_index]; + dev->poll_mod_count++; +} + +static void pn533_poll_create_mod_list(struct pn533 *dev, u32 protocols) +{ + pn533_poll_reset_mod_list(dev); + + if (protocols & NFC_PROTO_MIFARE_MASK + || protocols & NFC_PROTO_ISO14443_MASK + || protocols & NFC_PROTO_NFC_DEP_MASK) + pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A); + + if (protocols & NFC_PROTO_FELICA_MASK + || protocols & NFC_PROTO_NFC_DEP_MASK) { + pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA); + pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA); + } + + if (protocols & NFC_PROTO_JEWEL_MASK) + pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL); + + if (protocols & NFC_PROTO_ISO14443_MASK) + pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B); +} + +static void pn533_start_poll_frame(struct pn533_frame *frame, + struct pn533_poll_modulations *mod) +{ + + pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET); + + memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len); + frame->datalen += mod->len; + + pn533_tx_frame_finish(frame); +} + +static int pn533_start_poll_complete(struct pn533 *dev, void *arg, + u8 *params, int params_len) +{ + struct pn533_poll_response *resp; + struct pn533_poll_modulations *next_mod; + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + if (params_len == -ENOENT) { + nfc_dev_dbg(&dev->interface->dev, "Polling operation has been" + " stopped"); + goto stop_poll; + } + + if (params_len < 0) { + nfc_dev_err(&dev->interface->dev, "Error %d when running poll", + params_len); + goto stop_poll; + } + + resp = (struct pn533_poll_response *) params; + if (resp->nbtg) { + rc = pn533_target_found(dev, resp, params_len); + + /* We must stop the poll after a valid target found */ + if (rc == 0) + goto stop_poll; + + if (rc != -EAGAIN) + nfc_dev_err(&dev->interface->dev, "The target found is" + " not valid - continuing to poll"); + } + + dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count; + + next_mod = dev->poll_mod_active[dev->poll_mod_curr]; + + nfc_dev_dbg(&dev->interface->dev, "Polling next modulation (0x%x)", + dev->poll_mod_curr); + + pn533_start_poll_frame(dev->out_frame, next_mod); + + /* Don't need to down the semaphore again */ + rc = __pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame, + dev->in_maxlen, pn533_start_poll_complete, + NULL, GFP_ATOMIC); + + if (rc == -EPERM) { + nfc_dev_dbg(&dev->interface->dev, "Cannot poll next modulation" + " because poll has been stopped"); + goto stop_poll; + } + + if (rc) { + nfc_dev_err(&dev->interface->dev, "Error %d when trying to poll" + " next modulation", rc); + goto stop_poll; + } + + /* Inform caller function to do not up the semaphore */ + return -EINPROGRESS; + +stop_poll: + pn533_poll_reset_mod_list(dev); + dev->poll_protocols = 0; + return 0; +} + +static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 protocols) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + struct pn533_poll_modulations *start_mod; + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s - protocols=0x%x", __func__, + protocols); + + if (dev->poll_mod_count) { + nfc_dev_err(&dev->interface->dev, "Polling operation already" + " active"); + return -EBUSY; + } + + if (dev->tgt_active_prot) { + nfc_dev_err(&dev->interface->dev, "Cannot poll with a target" + " already activated"); + return -EBUSY; + } + + pn533_poll_create_mod_list(dev, protocols); + + if (!dev->poll_mod_count) { + nfc_dev_err(&dev->interface->dev, "No valid protocols" + " specified"); + rc = -EINVAL; + goto error; + } + + nfc_dev_dbg(&dev->interface->dev, "It will poll %d modulations types", + dev->poll_mod_count); + + dev->poll_mod_curr = 0; + start_mod = dev->poll_mod_active[dev->poll_mod_curr]; + + pn533_start_poll_frame(dev->out_frame, start_mod); + + rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame, + dev->in_maxlen, pn533_start_poll_complete, + NULL, GFP_KERNEL); + + if (rc) { + nfc_dev_err(&dev->interface->dev, "Error %d when trying to" + " start poll", rc); + goto error; + } + + dev->poll_protocols = protocols; + + return 0; + +error: + pn533_poll_reset_mod_list(dev); + return rc; +} + +static void pn533_stop_poll(struct nfc_dev *nfc_dev) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + if (!dev->poll_mod_count) { + nfc_dev_dbg(&dev->interface->dev, "Polling operation was not" + " running"); + return; + } + + /* An ack will cancel the last issued command (poll) */ + pn533_send_ack(dev, GFP_KERNEL); + + /* prevent pn533_start_poll_complete to issue a new poll meanwhile */ + usb_kill_urb(dev->in_urb); +} + +static int pn533_activate_target_nfcdep(struct pn533 *dev) +{ + struct pn533_cmd_activate_param param; + struct pn533_cmd_activate_response *resp; + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_ATR); + + param.tg = 1; + param.next = 0; + memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), ¶m, + sizeof(struct pn533_cmd_activate_param)); + dev->out_frame->datalen += sizeof(struct pn533_cmd_activate_param); + + pn533_tx_frame_finish(dev->out_frame); + + rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame, + dev->in_maxlen); + if (rc) + return rc; + + resp = (struct pn533_cmd_activate_response *) + PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame); + rc = resp->status & PN533_CMD_RET_MASK; + if (rc != PN533_CMD_RET_SUCCESS) + return -EIO; + + return 0; +} + +static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, + u32 protocol) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s - protocol=%u", __func__, + protocol); + + if (dev->poll_mod_count) { + nfc_dev_err(&dev->interface->dev, "Cannot activate while" + " polling"); + return -EBUSY; + } + + if (dev->tgt_active_prot) { + nfc_dev_err(&dev->interface->dev, "There is already an active" + " target"); + return -EBUSY; + } + + if (!dev->tgt_available_prots) { + nfc_dev_err(&dev->interface->dev, "There is no available target" + " to activate"); + return -EINVAL; + } + + if (!(dev->tgt_available_prots & (1 << protocol))) { + nfc_dev_err(&dev->interface->dev, "The target does not support" + " the requested protocol %u", protocol); + return -EINVAL; + } + + if (protocol == NFC_PROTO_NFC_DEP) { + rc = pn533_activate_target_nfcdep(dev); + if (rc) { + nfc_dev_err(&dev->interface->dev, "Error %d when" + " activating target with" + " NFC_DEP protocol", rc); + return rc; + } + } + + dev->tgt_active_prot = protocol; + dev->tgt_available_prots = 0; + + return 0; +} + +static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + u8 tg; + u8 status; + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + if (!dev->tgt_active_prot) { + nfc_dev_err(&dev->interface->dev, "There is no active target"); + return; + } + + dev->tgt_active_prot = 0; + + pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_RELEASE); + + tg = 1; + memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &tg, sizeof(u8)); + dev->out_frame->datalen += sizeof(u8); + + pn533_tx_frame_finish(dev->out_frame); + + rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame, + dev->in_maxlen); + if (rc) { + nfc_dev_err(&dev->interface->dev, "Error when sending release" + " command to the controller"); + return; + } + + status = PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame)[0]; + rc = status & PN533_CMD_RET_MASK; + if (rc != PN533_CMD_RET_SUCCESS) + nfc_dev_err(&dev->interface->dev, "Error 0x%x when releasing" + " the target", rc); + + return; +} + +#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3) +#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262 + +static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb) +{ + int payload_len = skb->len; + struct pn533_frame *out_frame; + struct sk_buff *discarded; + u8 tg; + + nfc_dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__, + payload_len); + + if (payload_len > PN533_CMD_DATAEXCH_DATA_MAXLEN) { + /* TODO: Implement support to multi-part data exchange */ + nfc_dev_err(&dev->interface->dev, "Data length greater than the" + " max allowed: %d", + PN533_CMD_DATAEXCH_DATA_MAXLEN); + return -ENOSYS; + } + + /* Reserving header space */ + if (skb_cow_head(skb, PN533_CMD_DATAEXCH_HEAD_LEN)) { + nfc_dev_err(&dev->interface->dev, "Error to add header data"); + return -ENOMEM; + } + + /* Reserving tail space, see pn533_tx_frame_finish */ + if (skb_cow_data(skb, PN533_FRAME_TAIL_SIZE, &discarded) < 0) { + nfc_dev_err(&dev->interface->dev, "Error to add tail data"); + return -ENOMEM; + } + + skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN); + out_frame = (struct pn533_frame *) skb->data; + + pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE); + + tg = 1; + memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8)); + out_frame->datalen += sizeof(u8); + + /* The data is already in the out_frame, just update the datalen */ + out_frame->datalen += payload_len; + + pn533_tx_frame_finish(out_frame); + skb_put(skb, PN533_FRAME_TAIL_SIZE); + + return 0; +} + +struct pn533_data_exchange_arg { + struct sk_buff *skb_resp; + struct sk_buff *skb_out; + data_exchange_cb_t cb; + void *cb_context; +}; + +static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, + u8 *params, int params_len) +{ + struct pn533_data_exchange_arg *arg = _arg; + struct sk_buff *skb_resp = arg->skb_resp; + struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data; + int err = 0; + u8 status; + u8 cmd_ret; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + dev_kfree_skb_irq(arg->skb_out); + + if (params_len < 0) { /* error */ + err = params_len; + goto error; + } + + skb_put(skb_resp, PN533_FRAME_SIZE(in_frame)); + + status = params[0]; + + cmd_ret = status & PN533_CMD_RET_MASK; + if (cmd_ret != PN533_CMD_RET_SUCCESS) { + nfc_dev_err(&dev->interface->dev, "PN533 reported error %d when" + " exchanging data", cmd_ret); + err = -EIO; + goto error; + } + + if (status & PN533_CMD_MI_MASK) { + /* TODO: Implement support to multi-part data exchange */ + nfc_dev_err(&dev->interface->dev, "Multi-part message not yet" + " supported"); + /* Prevent the other messages from controller */ + pn533_send_ack(dev, GFP_ATOMIC); + err = -ENOSYS; + goto error; + } + + skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN); + skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE); + + arg->cb(arg->cb_context, skb_resp, 0); + kfree(arg); + return 0; + +error: + dev_kfree_skb_irq(skb_resp); + arg->cb(arg->cb_context, NULL, err); + kfree(arg); + return 0; +} + +int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, + struct sk_buff *skb, + data_exchange_cb_t cb, + void *cb_context) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + struct pn533_frame *out_frame, *in_frame; + struct pn533_data_exchange_arg *arg; + struct sk_buff *skb_resp; + int skb_resp_len; + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + if (!dev->tgt_active_prot) { + nfc_dev_err(&dev->interface->dev, "Cannot exchange data if" + " there is no active target"); + rc = -EINVAL; + goto error; + } + + rc = pn533_data_exchange_tx_frame(dev, skb); + if (rc) + goto error; + + skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN + + PN533_CMD_DATAEXCH_DATA_MAXLEN + + PN533_FRAME_TAIL_SIZE; + + skb_resp = nfc_alloc_skb(skb_resp_len, GFP_KERNEL); + if (!skb_resp) { + rc = -ENOMEM; + goto error; + } + + in_frame = (struct pn533_frame *) skb_resp->data; + out_frame = (struct pn533_frame *) skb->data; + + arg = kmalloc(sizeof(struct pn533_data_exchange_arg), GFP_KERNEL); + if (!arg) { + rc = -ENOMEM; + goto free_skb_resp; + } + + arg->skb_resp = skb_resp; + arg->skb_out = skb; + arg->cb = cb; + arg->cb_context = cb_context; + + rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, skb_resp_len, + pn533_data_exchange_complete, arg, + GFP_KERNEL); + if (rc) { + nfc_dev_err(&dev->interface->dev, "Error %d when trying to" + " perform data_exchange", rc); + goto free_arg; + } + + return 0; + +free_arg: + kfree(arg); +free_skb_resp: + kfree_skb(skb_resp); +error: + kfree_skb(skb); + return rc; +} + +static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, + u8 cfgdata_len) +{ + int rc; + u8 *params; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + pn533_tx_frame_init(dev->out_frame, PN533_CMD_RF_CONFIGURATION); + + params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame); + params[0] = cfgitem; + memcpy(¶ms[1], cfgdata, cfgdata_len); + dev->out_frame->datalen += (1 + cfgdata_len); + + pn533_tx_frame_finish(dev->out_frame); + + rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame, + dev->in_maxlen); + + return rc; +} + +struct nfc_ops pn533_nfc_ops = { + .start_poll = pn533_start_poll, + .stop_poll = pn533_stop_poll, + .activate_target = pn533_activate_target, + .deactivate_target = pn533_deactivate_target, + .data_exchange = pn533_data_exchange, +}; + +static int pn533_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct pn533_fw_version *fw_ver; + struct pn533 *dev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct pn533_config_max_retries max_retries; + int in_endpoint = 0; + int out_endpoint = 0; + int rc = -ENOMEM; + int i; + u32 protocols; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->udev = usb_get_dev(interface_to_usbdev(interface)); + dev->interface = interface; + sema_init(&dev->cmd_lock, 1); + + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint)) { + dev->in_maxlen = le16_to_cpu(endpoint->wMaxPacketSize); + in_endpoint = endpoint->bEndpointAddress; + } + + if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint)) { + dev->out_maxlen = + le16_to_cpu(endpoint->wMaxPacketSize); + out_endpoint = endpoint->bEndpointAddress; + } + } + + if (!in_endpoint || !out_endpoint) { + nfc_dev_err(&interface->dev, "Could not find bulk-in or" + " bulk-out endpoint"); + rc = -ENODEV; + goto error; + } + + dev->in_frame = kmalloc(dev->in_maxlen, GFP_KERNEL); + dev->in_urb = usb_alloc_urb(0, GFP_KERNEL); + dev->out_frame = kmalloc(dev->out_maxlen, GFP_KERNEL); + dev->out_urb = usb_alloc_urb(0, GFP_KERNEL); + + if (!dev->in_frame || !dev->out_frame || + !dev->in_urb || !dev->out_urb) + goto error; + + usb_fill_bulk_urb(dev->in_urb, dev->udev, + usb_rcvbulkpipe(dev->udev, in_endpoint), + NULL, 0, NULL, dev); + usb_fill_bulk_urb(dev->out_urb, dev->udev, + usb_sndbulkpipe(dev->udev, out_endpoint), + NULL, 0, + pn533_send_complete, dev); + + tasklet_init(&dev->tasklet, pn533_tasklet_cmd_complete, (ulong)dev); + + usb_set_intfdata(interface, dev); + + pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION); + pn533_tx_frame_finish(dev->out_frame); + + rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame, + dev->in_maxlen); + if (rc) + goto kill_tasklet; + + fw_ver = (struct pn533_fw_version *) + PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame); + nfc_dev_info(&dev->interface->dev, "NXP PN533 firmware ver %d.%d now" + " attached", fw_ver->ver, fw_ver->rev); + + protocols = NFC_PROTO_JEWEL_MASK + | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK + | NFC_PROTO_ISO14443_MASK + | NFC_PROTO_NFC_DEP_MASK; + + dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols); + if (!dev->nfc_dev) + goto kill_tasklet; + + nfc_set_parent_dev(dev->nfc_dev, &interface->dev); + nfc_set_drvdata(dev->nfc_dev, dev); + + rc = nfc_register_device(dev->nfc_dev); + if (rc) + goto free_nfc_dev; + + max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS; + max_retries.mx_rty_psl = 2; + max_retries.mx_rty_passive_act = PN533_CONFIG_MAX_RETRIES_NO_RETRY; + + rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES, + (u8 *) &max_retries, sizeof(max_retries)); + + if (rc) { + nfc_dev_err(&dev->interface->dev, "Error on setting MAX_RETRIES" + " config"); + goto free_nfc_dev; + } + + return 0; + +free_nfc_dev: + nfc_free_device(dev->nfc_dev); +kill_tasklet: + tasklet_kill(&dev->tasklet); +error: + kfree(dev->in_frame); + usb_free_urb(dev->in_urb); + kfree(dev->out_frame); + usb_free_urb(dev->out_urb); + kfree(dev); + return rc; +} + +static void pn533_disconnect(struct usb_interface *interface) +{ + struct pn533 *dev; + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + nfc_unregister_device(dev->nfc_dev); + nfc_free_device(dev->nfc_dev); + + usb_kill_urb(dev->in_urb); + usb_kill_urb(dev->out_urb); + + tasklet_kill(&dev->tasklet); + + kfree(dev->in_frame); + usb_free_urb(dev->in_urb); + kfree(dev->out_frame); + usb_free_urb(dev->out_urb); + kfree(dev); + + nfc_dev_info(&dev->interface->dev, "NXP PN533 NFC device disconnected"); +} + +static struct usb_driver pn533_driver = { + .name = "pn533", + .probe = pn533_probe, + .disconnect = pn533_disconnect, + .id_table = pn533_table, +}; + +static int __init pn533_init(void) +{ + int rc; + + rc = usb_register(&pn533_driver); + if (rc) + err("usb_register failed. Error number %d", rc); + + return rc; +} + +static void __exit pn533_exit(void) +{ + usb_deregister(&pn533_driver); +} + +module_init(pn533_init); +module_exit(pn533_exit); + +MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>," + " Aloisio Almeida Jr <aloisio.almeida@openbossa.org>"); +MODULE_DESCRIPTION("PN533 usb driver ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 21b9465f71ad..11d85bfd774e 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -516,8 +516,17 @@ static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) { + ssb_pcicore_fix_sprom_core_index(pc); + /* Disable PCI interrupts. */ ssb_write32(pc->dev, SSB_INTVEC, 0); + + /* Additional PCIe always once-executed workarounds */ + if (pc->dev->id.coreid == SSB_DEV_PCIE) { + ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + /* TODO: Clock Request Update */ + } } void __devinit ssb_pcicore_init(struct ssb_pcicore *pc) @@ -529,8 +538,6 @@ void __devinit ssb_pcicore_init(struct ssb_pcicore *pc) if (!ssb_device_is_enabled(dev)) ssb_device_enable(dev, 0); - ssb_pcicore_fix_sprom_core_index(pc); - #ifdef CONFIG_SSB_PCICORE_HOSTMODE pc->hostmode = pcicore_is_in_hostmode(pc); if (pc->hostmode) @@ -538,13 +545,6 @@ void __devinit ssb_pcicore_init(struct ssb_pcicore *pc) #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ if (!pc->hostmode) ssb_pcicore_init_clientmode(pc); - - /* Additional PCIe always once-executed workarounds */ - if (dev->id.coreid == SSB_DEV_PCIE) { - ssb_pcicore_serdes_workaround(pc); - /* TODO: ASPM */ - /* TODO: Clock Request Update */ - } } static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index e568664f8b9c..57b7b6460896 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1002,8 +1002,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m) switch (plltype) { case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ if (m & SSB_CHIPCO_CLK_T6_MMASK) - return SSB_CHIPCO_CLK_T6_M0; - return SSB_CHIPCO_CLK_T6_M1; + return SSB_CHIPCO_CLK_T6_M1; + return SSB_CHIPCO_CLK_T6_M0; case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 7ad48585c5e6..a00b35f03084 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -734,12 +734,9 @@ out_free: static void ssb_pci_get_boardinfo(struct ssb_bus *bus, struct ssb_boardinfo *bi) { - pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID, - &bi->vendor); - pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID, - &bi->type); - pci_read_config_word(bus->host_pci, PCI_REVISION_ID, - &bi->rev); + bi->vendor = bus->host_pci->subsystem_vendor; + bi->type = bus->host_pci->subsystem_device; + bi->rev = bus->host_pci->revision; } int ssb_pci_get_invariants(struct ssb_bus *bus, diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index 45e5babd3961..8047f9aaa4b2 100644 --- a/drivers/ssb/scan.c +++ b/drivers/ssb/scan.c @@ -310,8 +310,7 @@ int ssb_bus_scan(struct ssb_bus *bus, } else { if (bus->bustype == SSB_BUSTYPE_PCI) { bus->chip_id = pcidev_to_chipid(bus->host_pci); - pci_read_config_byte(bus->host_pci, PCI_REVISION_ID, - &bus->chip_rev); + bus->chip_rev = bus->host_pci->revision; bus->chip_package = 0; } else { bus->chip_id = 0x4710; diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index bf56b6f78270..a26108e4d924 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -117,8 +117,19 @@ #define IEEE80211_MAX_MESH_ID_LEN 32 #define IEEE80211_QOS_CTL_LEN 2 -#define IEEE80211_QOS_CTL_TID_MASK 0x000F -#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 +/* 1d tag mask */ +#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 +/* TID mask */ +#define IEEE80211_QOS_CTL_TID_MASK 0x000f +/* EOSP */ +#define IEEE80211_QOS_CTL_EOSP 0x0010 +/* ACK policy */ +#define IEEE80211_QOS_CTL_ACK_POLICY_NORMAL 0x0000 +#define IEEE80211_QOS_CTL_ACK_POLICY_NOACK 0x0020 +#define IEEE80211_QOS_CTL_ACK_POLICY_NO_EXPL 0x0040 +#define IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK 0x0060 +/* A-MSDU 802.11n */ +#define IEEE80211_QOS_CTL_A_MSDU_PRESENT 0x0080 /* U-APSD queue for WMM IEs sent by AP */ #define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7) @@ -1423,9 +1434,6 @@ enum ieee80211_sa_query_action { }; -/* A-MSDU 802.11n */ -#define IEEE80211_QOS_CONTROL_A_MSDU_PRESENT 0x0080 - /* cipher suite selectors */ #define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 #define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 diff --git a/include/linux/nfc.h b/include/linux/nfc.h new file mode 100644 index 000000000000..330a4c5db588 --- /dev/null +++ b/include/linux/nfc.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * + * Authors: + * Lauro Ramos Venancio <lauro.venancio@openbossa.org> + * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LINUX_NFC_H +#define __LINUX_NFC_H + +#include <linux/types.h> +#include <linux/socket.h> + +#define NFC_GENL_NAME "nfc" +#define NFC_GENL_VERSION 1 + +#define NFC_GENL_MCAST_EVENT_NAME "events" + +/** + * enum nfc_commands - supported nfc commands + * + * @NFC_CMD_UNSPEC: unspecified command + * + * @NFC_CMD_GET_DEVICE: request information about a device (requires + * %NFC_ATTR_DEVICE_INDEX) or dump request to get a list of all nfc devices + * @NFC_CMD_START_POLL: start polling for targets using the given protocols + * (requires %NFC_ATTR_DEVICE_INDEX and %NFC_ATTR_PROTOCOLS) + * @NFC_CMD_STOP_POLL: stop polling for targets (requires + * %NFC_ATTR_DEVICE_INDEX) + * @NFC_CMD_GET_TARGET: dump all targets found by the previous poll (requires + * %NFC_ATTR_DEVICE_INDEX) + * @NFC_EVENT_TARGETS_FOUND: event emitted when a new target is found + * (it sends %NFC_ATTR_DEVICE_INDEX) + * @NFC_EVENT_DEVICE_ADDED: event emitted when a new device is registred + * (it sends %NFC_ATTR_DEVICE_NAME, %NFC_ATTR_DEVICE_INDEX and + * %NFC_ATTR_PROTOCOLS) + * @NFC_EVENT_DEVICE_REMOVED: event emitted when a device is removed + * (it sends %NFC_ATTR_DEVICE_INDEX) + */ +enum nfc_commands { + NFC_CMD_UNSPEC, + NFC_CMD_GET_DEVICE, + NFC_CMD_START_POLL, + NFC_CMD_STOP_POLL, + NFC_CMD_GET_TARGET, + NFC_EVENT_TARGETS_FOUND, + NFC_EVENT_DEVICE_ADDED, + NFC_EVENT_DEVICE_REMOVED, +/* private: internal use only */ + __NFC_CMD_AFTER_LAST +}; +#define NFC_CMD_MAX (__NFC_CMD_AFTER_LAST - 1) + +/** + * enum nfc_attrs - supported nfc attributes + * + * @NFC_ATTR_UNSPEC: unspecified attribute + * + * @NFC_ATTR_DEVICE_INDEX: index of nfc device + * @NFC_ATTR_DEVICE_NAME: device name, max 8 chars + * @NFC_ATTR_PROTOCOLS: nfc protocols - bitwise or-ed combination from + * NFC_PROTO_*_MASK constants + * @NFC_ATTR_TARGET_INDEX: index of the nfc target + * @NFC_ATTR_TARGET_SENS_RES: NFC-A targets extra information such as NFCID + * @NFC_ATTR_TARGET_SEL_RES: NFC-A targets extra information (useful if the + * target is not NFC-Forum compliant) + */ +enum nfc_attrs { + NFC_ATTR_UNSPEC, + NFC_ATTR_DEVICE_INDEX, + NFC_ATTR_DEVICE_NAME, + NFC_ATTR_PROTOCOLS, + NFC_ATTR_TARGET_INDEX, + NFC_ATTR_TARGET_SENS_RES, + NFC_ATTR_TARGET_SEL_RES, +/* private: internal use only */ + __NFC_ATTR_AFTER_LAST +}; +#define NFC_ATTR_MAX (__NFC_ATTR_AFTER_LAST - 1) + +#define NFC_DEVICE_NAME_MAXSIZE 8 + +/* NFC protocols */ +#define NFC_PROTO_JEWEL 1 +#define NFC_PROTO_MIFARE 2 +#define NFC_PROTO_FELICA 3 +#define NFC_PROTO_ISO14443 4 +#define NFC_PROTO_NFC_DEP 5 + +#define NFC_PROTO_MAX 6 + +/* NFC protocols masks used in bitsets */ +#define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL) +#define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE) +#define NFC_PROTO_FELICA_MASK (1 << NFC_PROTO_FELICA) +#define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443) +#define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP) + +struct sockaddr_nfc { + sa_family_t sa_family; + __u32 dev_idx; + __u32 target_idx; + __u32 nfc_protocol; +}; + +/* NFC socket protocols */ +#define NFC_SOCKPROTO_RAW 0 +#define NFC_SOCKPROTO_MAX 1 + +#endif /*__LINUX_NFC_H */ diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c7ccaae15af6..8cb025a00094 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -247,7 +247,8 @@ * passed, all channels allowed for the current regulatory domain * are used. Extra IEs can also be passed from the userspace by * using the %NL80211_ATTR_IE attribute. - * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan + * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT + * if scheduled scan is not running. * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan * results available. * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has @@ -483,6 +484,14 @@ * more background information, see * http://wireless.kernel.org/en/users/Documentation/WoWLAN. * + * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver + * the necessary information for supporting GTK rekey offload. This + * feature is typically used during WoWLAN. The configuration data + * is contained in %NL80211_ATTR_REKEY_DATA (which is nested and + * contains the data in sub-attributes). After rekeying happened, + * this command may also be sent by the driver as an MLME event to + * inform userspace of the new replay counter. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -605,6 +614,8 @@ enum nl80211_commands { NL80211_CMD_SCHED_SCAN_RESULTS, NL80211_CMD_SCHED_SCAN_STOPPED, + NL80211_CMD_SET_REKEY_OFFLOAD, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -996,6 +1007,9 @@ enum nl80211_commands { * are managed in software: interfaces of these types aren't subject to * any restrictions in their number or combinations. * + * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information + * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1194,6 +1208,8 @@ enum nl80211_attrs { NL80211_ATTR_INTERFACE_COMBINATIONS, NL80211_ATTR_SOFTWARE_IFTYPES, + NL80211_ATTR_REKEY_DATA, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2361,4 +2377,28 @@ enum nl80211_plink_state { MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1 }; +#define NL80211_KCK_LEN 16 +#define NL80211_KEK_LEN 16 +#define NL80211_REPLAY_CTR_LEN 8 + +/** + * enum nl80211_rekey_data - attributes for GTK rekey offload + * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes + * @NL80211_REKEY_DATA_KEK: key encryption key (binary) + * @NL80211_REKEY_DATA_KCK: key confirmation key (binary) + * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary) + * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal) + * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal) + */ +enum nl80211_rekey_data { + __NL80211_REKEY_DATA_INVALID, + NL80211_REKEY_DATA_KEK, + NL80211_REKEY_DATA_KCK, + NL80211_REKEY_DATA_REPLAY_CTR, + + /* keep last */ + NUM_NL80211_REKEY_DATA, + MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/linux/socket.h b/include/linux/socket.h index 4ef98e422fde..e17f82266639 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -192,7 +192,8 @@ struct ucred { #define AF_IEEE802154 36 /* IEEE802154 sockets */ #define AF_CAIF 37 /* CAIF sockets */ #define AF_ALG 38 /* Algorithm sockets */ -#define AF_MAX 39 /* For now.. */ +#define AF_NFC 39 /* NFC sockets */ +#define AF_MAX 40 /* For now.. */ /* Protocol families, same as address families. */ #define PF_UNSPEC AF_UNSPEC @@ -234,6 +235,7 @@ struct ucred { #define PF_IEEE802154 AF_IEEE802154 #define PF_CAIF AF_CAIF #define PF_ALG AF_ALG +#define PF_NFC AF_NFC #define PF_MAX AF_MAX /* Maximum queue length specifiable by listen. */ diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 252e44821787..b0928c10111b 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -99,7 +99,7 @@ struct ssb_sprom { struct ssb_boardinfo { u16 vendor; u16 type; - u16 rev; + u8 rev; }; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6cb2543a2ee1..4bf101bada4e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1154,6 +1154,18 @@ struct cfg80211_wowlan { }; /** + * struct cfg80211_gtk_rekey_data - rekey data + * @kek: key encryption key + * @kck: key confirmation key + * @replay_ctr: replay counter + */ +struct cfg80211_gtk_rekey_data { + u8 kek[NL80211_KEK_LEN]; + u8 kck[NL80211_KCK_LEN]; + u8 replay_ctr[NL80211_REPLAY_CTR_LEN]; +}; + +/** * struct cfg80211_ops - backend description for wireless configuration * * This struct is registered by fullmac card drivers and/or wireless stacks @@ -1197,6 +1209,8 @@ struct cfg80211_wowlan { * * @set_default_mgmt_key: set the default management frame key on an interface * + * @set_rekey_data: give the data necessary for GTK rekeying to the driver + * * @add_beacon: Add a beacon with given parameters, @head, @interval * and @dtim_period will be valid, @tail is optional. * @set_beacon: Change the beacon parameters for an access point mode @@ -1499,6 +1513,9 @@ struct cfg80211_ops { struct net_device *dev, struct cfg80211_sched_scan_request *request); int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev); + + int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_gtk_rekey_data *data); }; /* @@ -2697,7 +2714,7 @@ void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, * @dev: network device * @addr: The source MAC address of the frame * @key_type: The key type that the received frame used - * @key_id: Key identifier (0..3) + * @key_id: Key identifier (0..3). Can be -1 if missing. * @tsc: The TSC value of the frame that generated the MIC failure (6 octets) * @gfp: allocation flags * @@ -3033,6 +3050,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, void cfg80211_cqm_pktloss_notify(struct net_device *dev, const u8 *peer, u32 num_packets, gfp_t gfp); +/** + * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying + * @dev: network device + * @bssid: BSSID of AP (to avoid races) + * @replay_ctr: new replay counter + */ +void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp); + /* Logging, debugging and troubleshooting/diagnostic helpers. */ /* wiphy_printk helpers, similar to dev_printk */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 120f102814b6..b29456a945c2 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -20,6 +20,7 @@ #include <linux/device.h> #include <linux/ieee80211.h> #include <net/cfg80211.h> +#include <asm/unaligned.h> /** * DOC: Introduction @@ -933,6 +934,7 @@ enum set_key_cmd { * @aid: AID we assigned to the station if we're an AP * @supp_rates: Bitmap of supported rates (per band) * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities + * @wme: indicates whether the STA supports WME. Only valid during AP-mode. * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *), size is determined in hw information. */ @@ -941,6 +943,7 @@ struct ieee80211_sta { u8 addr[ETH_ALEN]; u16 aid; struct ieee80211_sta_ht_cap ht_cap; + bool wme; /* must be last */ u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); @@ -960,21 +963,6 @@ enum sta_notify_cmd { }; /** - * enum ieee80211_tkip_key_type - get tkip key - * - * Used by drivers which need to get a tkip key for skb. Some drivers need a - * phase 1 key, others need a phase 2 key. A single function allows the driver - * to get the key, this enum indicates what type of key is required. - * - * @IEEE80211_TKIP_P1_KEY: the driver needs a phase 1 key - * @IEEE80211_TKIP_P2_KEY: the driver needs a phase 2 key - */ -enum ieee80211_tkip_key_type { - IEEE80211_TKIP_P1_KEY, - IEEE80211_TKIP_P2_KEY, -}; - -/** * enum ieee80211_hw_flags - hardware flags * * These flags are used to indicate hardware capabilities to @@ -1626,6 +1614,10 @@ enum ieee80211_ampdu_mlme_action { * ask the device to suspend. This is only invoked when WoWLAN is * configured, otherwise the device is deconfigured completely and * reconfigured at resume time. + * The driver may also impose special conditions under which it + * wants to use the "normal" suspend (deconfigure), say if it only + * supports WoWLAN when the device is associated. In this case, it + * must return 1 from this function. * * @resume: If WoWLAN was configured, this indicates that mac80211 is * now resuming its operation, after this the device must be fully @@ -1694,6 +1686,12 @@ enum ieee80211_ampdu_mlme_action { * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. * The callback must be atomic. * + * @set_rekey_data: If the device supports GTK rekeying, for example while the + * host is suspended, it can assign this callback to retrieve the data + * necessary to do GTK rekeying, this is the KEK, KCK and replay counter. + * After rekeying was done it should (for example during resume) notify + * userspace of the new replay counter using ieee80211_gtk_rekey_notify(). + * * @hw_scan: Ask the hardware to service the scan request, no need to start * the scan state machine in stack. The scan must honour the channel * configuration done by the regulatory agent in the wiphy's @@ -1906,6 +1904,9 @@ struct ieee80211_ops { struct ieee80211_key_conf *conf, struct ieee80211_sta *sta, u32 iv32, u16 *phase1key); + void (*set_rekey_data)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data); int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req); void (*cancel_hw_scan)(struct ieee80211_hw *hw, @@ -2564,21 +2565,122 @@ struct sk_buff * ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /** - * ieee80211_get_tkip_key - get a TKIP rc4 for skb + * ieee80211_get_tkip_p1k_iv - get a TKIP phase 1 key for IV32 + * + * This function returns the TKIP phase 1 key for the given IV32. + * + * @keyconf: the parameter passed with the set key + * @iv32: IV32 to get the P1K for + * @p1k: a buffer to which the key will be written, as 5 u16 values + */ +void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, + u32 iv32, u16 *p1k); + +/** + * ieee80211_get_tkip_p1k - get a TKIP phase 1 key + * + * This function returns the TKIP phase 1 key for the IV32 taken + * from the given packet. + * + * @keyconf: the parameter passed with the set key + * @skb: the packet to take the IV32 value from that will be encrypted + * with this P1K + * @p1k: a buffer to which the key will be written, as 5 u16 values + */ +static inline void ieee80211_get_tkip_p1k(struct ieee80211_key_conf *keyconf, + struct sk_buff *skb, u16 *p1k) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); + u32 iv32 = get_unaligned_le32(&data[4]); + + ieee80211_get_tkip_p1k_iv(keyconf, iv32, p1k); +} + +/** + * ieee80211_get_tkip_p2k - get a TKIP phase 2 key + * + * This function computes the TKIP RC4 key for the IV values + * in the packet. + * + * @keyconf: the parameter passed with the set key + * @skb: the packet to take the IV32/IV16 values from that will be + * encrypted with this key + * @p2k: a buffer to which the key will be written, 16 bytes + */ +void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, + struct sk_buff *skb, u8 *p2k); + +/** + * struct ieee80211_key_seq - key sequence counter + * + * @tkip: TKIP data, containing IV32 and IV16 in host byte order + * @ccmp: PN data, most significant byte first (big endian, + * reverse order than in packet) + * @aes_cmac: PN data, most significant byte first (big endian, + * reverse order than in packet) + */ +struct ieee80211_key_seq { + union { + struct { + u32 iv32; + u16 iv16; + } tkip; + struct { + u8 pn[6]; + } ccmp; + struct { + u8 pn[6]; + } aes_cmac; + }; +}; + +/** + * ieee80211_get_key_tx_seq - get key TX sequence counter + * + * @keyconf: the parameter passed with the set key + * @seq: buffer to receive the sequence data * - * This function computes a TKIP rc4 key for an skb. It computes - * a phase 1 key if needed (iv16 wraps around). This function is to - * be used by drivers which can do HW encryption but need to compute - * to phase 1/2 key in SW. + * This function allows a driver to retrieve the current TX IV/PN + * for the given key. It must not be called if IV generation is + * offloaded to the device. + * + * Note that this function may only be called when no TX processing + * can be done concurrently, for example when queues are stopped + * and the stop has been synchronized. + */ +void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, + struct ieee80211_key_seq *seq); + +/** + * ieee80211_get_key_rx_seq - get key RX sequence counter * * @keyconf: the parameter passed with the set key - * @skb: the skb for which the key is needed - * @type: TBD - * @key: a buffer to which the key will be written + * @tid: The TID, or -1 for the management frame value (CCMP only); + * the value on TID 0 is also used for non-QoS frames. For + * CMAC, only TID 0 is valid. + * @seq: buffer to receive the sequence data + * + * This function allows a driver to retrieve the current RX IV/PNs + * for the given key. It must not be called if IV checking is done + * by the device and not by mac80211. + * + * Note that this function may only be called when no RX processing + * can be done concurrently. */ -void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, - struct sk_buff *skb, - enum ieee80211_tkip_key_type type, u8 *key); +void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, + int tid, struct ieee80211_key_seq *seq); + +/** + * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying + * @vif: virtual interface the rekeying was done on + * @bssid: The BSSID of the AP, for checking association + * @replay_ctr: the new replay counter after GTK rekeying + * @gfp: allocation flags + */ +void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp); + /** * ieee80211_wake_queue - wake specific queue * @hw: pointer as obtained from ieee80211_alloc_hw(). @@ -2844,6 +2946,29 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, bool block); /** + * ieee80211_iter_keys - iterate keys programmed into the device + * @hw: pointer obtained from ieee80211_alloc_hw() + * @vif: virtual interface to iterate, may be %NULL for all + * @iter: iterator function that will be called for each key + * @iter_data: custom data to pass to the iterator function + * + * This function can be used to iterate all the keys known to + * mac80211, even those that weren't previously programmed into + * the device. This is intended for use in WoWLAN if the device + * needs reprogramming of the keys during suspend. Note that due + * to locking reasons, it is also only safe to call this at few + * spots since it must hold the RTNL and be able to sleep. + */ +void ieee80211_iter_keys(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + void (*iter)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *data), + void *iter_data); + +/** * ieee80211_ap_probereq_get - retrieve a Probe Request template * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from the add_interface callback. diff --git a/include/net/nfc.h b/include/net/nfc.h new file mode 100644 index 000000000000..cc0130312f70 --- /dev/null +++ b/include/net/nfc.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * + * Authors: + * Lauro Ramos Venancio <lauro.venancio@openbossa.org> + * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __NET_NFC_H +#define __NET_NFC_H + +#include <linux/device.h> +#include <linux/skbuff.h> + +#define nfc_dev_info(dev, fmt, arg...) dev_info((dev), "NFC: " fmt "\n", ## arg) +#define nfc_dev_err(dev, fmt, arg...) dev_err((dev), "NFC: " fmt "\n", ## arg) +#define nfc_dev_dbg(dev, fmt, arg...) dev_dbg((dev), fmt "\n", ## arg) + +struct nfc_dev; + +/** + * data_exchange_cb_t - Definition of nfc_data_exchange callback + * + * @context: nfc_data_exchange cb_context parameter + * @skb: response data + * @err: If an error has occurred during data exchange, it is the + * error number. Zero means no error. + * + * When a rx or tx package is lost or corrupted or the target gets out + * of the operating field, err is -EIO. + */ +typedef void (*data_exchange_cb_t)(void *context, struct sk_buff *skb, + int err); + +struct nfc_ops { + int (*start_poll)(struct nfc_dev *dev, u32 protocols); + void (*stop_poll)(struct nfc_dev *dev); + int (*activate_target)(struct nfc_dev *dev, u32 target_idx, + u32 protocol); + void (*deactivate_target)(struct nfc_dev *dev, u32 target_idx); + int (*data_exchange)(struct nfc_dev *dev, u32 target_idx, + struct sk_buff *skb, data_exchange_cb_t cb, + void *cb_context); +}; + +struct nfc_target { + u32 idx; + u32 supported_protocols; + u16 sens_res; + u8 sel_res; +}; + +struct nfc_genl_data { + u32 poll_req_pid; + struct mutex genl_data_mutex; +}; + +struct nfc_dev { + unsigned idx; + unsigned target_idx; + struct nfc_target *targets; + int n_targets; + int targets_generation; + spinlock_t targets_lock; + struct device dev; + bool polling; + struct nfc_genl_data genl_data; + u32 supported_protocols; + + struct nfc_ops *ops; +}; +#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev) + +extern struct class nfc_class; + +struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, + u32 supported_protocols); + +/** + * nfc_free_device - free nfc device + * + * @dev: The nfc device to free + */ +static inline void nfc_free_device(struct nfc_dev *dev) +{ + put_device(&dev->dev); +} + +int nfc_register_device(struct nfc_dev *dev); + +void nfc_unregister_device(struct nfc_dev *dev); + +/** + * nfc_set_parent_dev - set the parent device + * + * @nfc_dev: The nfc device whose parent is being set + * @dev: The parent device + */ +static inline void nfc_set_parent_dev(struct nfc_dev *nfc_dev, + struct device *dev) +{ + nfc_dev->dev.parent = dev; +} + +/** + * nfc_set_drvdata - set driver specifc data + * + * @dev: The nfc device + * @data: Pointer to driver specifc data + */ +static inline void nfc_set_drvdata(struct nfc_dev *dev, void *data) +{ + dev_set_drvdata(&dev->dev, data); +} + +/** + * nfc_get_drvdata - get driver specifc data + * + * @dev: The nfc device + */ +static inline void *nfc_get_drvdata(struct nfc_dev *dev) +{ + return dev_get_drvdata(&dev->dev); +} + +/** + * nfc_device_name - get the nfc device name + * + * @dev: The nfc device whose name to return + */ +static inline const char *nfc_device_name(struct nfc_dev *dev) +{ + return dev_name(&dev->dev); +} + +struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp); + +int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, + int ntargets); + +#endif /* __NET_NFC_H */ diff --git a/net/Kconfig b/net/Kconfig index 878151c772c9..a07314844238 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -322,6 +322,7 @@ source "net/rfkill/Kconfig" source "net/9p/Kconfig" source "net/caif/Kconfig" source "net/ceph/Kconfig" +source "net/nfc/Kconfig" endif # if NET diff --git a/net/Makefile b/net/Makefile index a51d9465e628..acdde4950de4 100644 --- a/net/Makefile +++ b/net/Makefile @@ -68,3 +68,4 @@ obj-$(CONFIG_WIMAX) += wimax/ obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ obj-$(CONFIG_CEPH_LIB) += ceph/ obj-$(CONFIG_BATMAN_ADV) += batman-adv/ +obj-$(CONFIG_NFC) += nfc/ diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index fa48c0b3d93c..ea7f031f3b04 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -444,6 +444,9 @@ int hci_conn_del(struct hci_conn *conn) hci_dev_put(hdev); + if (conn->handle == 0) + kfree(conn); + return 0; } diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index c405a954a603..43b4c2deb7cc 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -464,7 +464,8 @@ static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } static void hidp_set_timer(struct hidp_session *session) @@ -535,7 +536,8 @@ static void hidp_process_hid_control(struct hidp_session *session, skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(current); } } @@ -706,9 +708,8 @@ static int hidp_session(void *arg) add_wait_queue(sk_sleep(intr_sk), &intr_wait); session->waiting_for_startup = 0; wake_up_interruptible(&session->startup_queue); - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - + set_current_state(TASK_INTERRUPTIBLE); + while (!atomic_read(&session->terminate)) { if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) break; @@ -726,6 +727,7 @@ static int hidp_session(void *arg) hidp_process_transmit(session); schedule(); + set_current_state(TASK_INTERRUPTIBLE); } set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(intr_sk), &intr_wait); @@ -1060,7 +1062,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, err_add_device: hid_destroy_device(session->hid); session->hid = NULL; - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); unlink: hidp_del_timer(session); @@ -1111,7 +1114,8 @@ int hidp_del_connection(struct hidp_conndel_req *req) skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - kthread_stop(session->task); + atomic_inc(&session->terminate); + wake_up_process(session->task); } } else err = -ENOENT; diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 19e95004b286..af1bcc823f26 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -142,6 +142,7 @@ struct hidp_session { uint ctrl_mtu; uint intr_mtu; + atomic_t terminate; struct task_struct *task; unsigned char keys[8]; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 52c791ed038d..f7f8e2cd3f70 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2523,7 +2523,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk = chan->sk; - if (chan->state != BT_CONFIG) { + if ((bt_sk(sk)->defer_setup && chan->state != BT_CONNECT2) || + (!bt_sk(sk)->defer_setup && chan->state != BT_CONFIG)) { struct l2cap_cmd_rej_cid rej; rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID); @@ -2537,7 +2538,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Reject if config buffer is too small. */ len = cmd_len - sizeof(*req); - if (chan->conf_len + len > sizeof(chan->conf_req)) { + if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_REJECT, flags), rsp); diff --git a/net/core/sock.c b/net/core/sock.c index 6e819780c232..84d6de809352 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -158,7 +158,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = { "sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" , "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" , "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" , - "sk_lock-AF_MAX" + "sk_lock-AF_NFC" , "sk_lock-AF_MAX" }; static const char *const af_family_slock_key_strings[AF_MAX+1] = { "slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" , @@ -174,7 +174,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = { "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" , "slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" , "slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" , - "slock-AF_MAX" + "slock-AF_NFC" , "slock-AF_MAX" }; static const char *const af_family_clock_key_strings[AF_MAX+1] = { "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" , @@ -190,7 +190,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = { "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" , "clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" , "clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" , - "clock-AF_MAX" + "clock-AF_NFC" , "clock-AF_MAX" }; /* diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index b9b595c08112..0785e95c9924 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -11,6 +11,7 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/aes.h> #include <net/mac80211.h> #include "key.h" @@ -21,21 +22,21 @@ static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a) int i; u8 *b_0, *aad, *b, *s_0; - b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; + b_0 = scratch + 3 * AES_BLOCK_SIZE; + aad = scratch + 4 * AES_BLOCK_SIZE; b = scratch; - s_0 = scratch + AES_BLOCK_LEN; + s_0 = scratch + AES_BLOCK_SIZE; crypto_cipher_encrypt_one(tfm, b, b_0); /* Extra Authenticate-only data (always two AES blocks) */ - for (i = 0; i < AES_BLOCK_LEN; i++) + for (i = 0; i < AES_BLOCK_SIZE; i++) aad[i] ^= b[i]; crypto_cipher_encrypt_one(tfm, b, aad); - aad += AES_BLOCK_LEN; + aad += AES_BLOCK_SIZE; - for (i = 0; i < AES_BLOCK_LEN; i++) + for (i = 0; i < AES_BLOCK_SIZE; i++) aad[i] ^= b[i]; crypto_cipher_encrypt_one(tfm, a, aad); @@ -57,12 +58,12 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *pos, *cpos, *b, *s_0, *e, *b_0; b = scratch; - s_0 = scratch + AES_BLOCK_LEN; - e = scratch + 2 * AES_BLOCK_LEN; - b_0 = scratch + 3 * AES_BLOCK_LEN; + s_0 = scratch + AES_BLOCK_SIZE; + e = scratch + 2 * AES_BLOCK_SIZE; + b_0 = scratch + 3 * AES_BLOCK_SIZE; - num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); - last_len = data_len % AES_BLOCK_LEN; + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); + last_len = data_len % AES_BLOCK_SIZE; aes_ccm_prepare(tfm, scratch, b); /* Process payload blocks */ @@ -70,7 +71,7 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, cpos = cdata; for (j = 1; j <= num_blocks; j++) { int blen = (j == num_blocks && last_len) ? - last_len : AES_BLOCK_LEN; + last_len : AES_BLOCK_SIZE; /* Authentication followed by encryption */ for (i = 0; i < blen; i++) @@ -96,12 +97,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *pos, *cpos, *b, *s_0, *a, *b_0; b = scratch; - s_0 = scratch + AES_BLOCK_LEN; - a = scratch + 2 * AES_BLOCK_LEN; - b_0 = scratch + 3 * AES_BLOCK_LEN; + s_0 = scratch + AES_BLOCK_SIZE; + a = scratch + 2 * AES_BLOCK_SIZE; + b_0 = scratch + 3 * AES_BLOCK_SIZE; - num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); - last_len = data_len % AES_BLOCK_LEN; + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); + last_len = data_len % AES_BLOCK_SIZE; aes_ccm_prepare(tfm, scratch, a); /* Process payload blocks */ @@ -109,7 +110,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, pos = data; for (j = 1; j <= num_blocks; j++) { int blen = (j == num_blocks && last_len) ? - last_len : AES_BLOCK_LEN; + last_len : AES_BLOCK_SIZE; /* Decryption followed by authentication */ b_0[14] = (j >> 8) & 0xff; diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h index 6e7820ef3448..5b7d744e2370 100644 --- a/net/mac80211/aes_ccm.h +++ b/net/mac80211/aes_ccm.h @@ -12,8 +12,6 @@ #include <linux/crypto.h> -#define AES_BLOCK_LEN 16 - struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]); void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *data, size_t data_len, diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index d502b2684a66..8dfd70d8fcfb 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c @@ -11,12 +11,12 @@ #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> +#include <crypto/aes.h> #include <net/mac80211.h> #include "key.h" #include "aes_cmac.h" -#define AES_BLOCK_SIZE 16 #define AES_CMAC_KEY_LEN 16 #define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ #define AAD_LEN 20 @@ -35,10 +35,10 @@ static void gf_mulx(u8 *pad) } -static void aes_128_cmac_vector(struct crypto_cipher *tfm, u8 *scratch, - size_t num_elem, +static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { + u8 scratch[2 * AES_BLOCK_SIZE]; u8 *cbc, *pad; const u8 *pos, *end; size_t i, e, left, total_len; @@ -95,7 +95,7 @@ static void aes_128_cmac_vector(struct crypto_cipher *tfm, u8 *scratch, } -void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad, +void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, const u8 *data, size_t data_len, u8 *mic) { const u8 *addr[3]; @@ -110,7 +110,7 @@ void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad, addr[2] = zero; len[2] = CMAC_TLEN; - aes_128_cmac_vector(tfm, scratch, 3, addr, len, mic); + aes_128_cmac_vector(tfm, 3, addr, len, mic); } diff --git a/net/mac80211/aes_cmac.h b/net/mac80211/aes_cmac.h index 0eb9a4831508..20785a647254 100644 --- a/net/mac80211/aes_cmac.h +++ b/net/mac80211/aes_cmac.h @@ -12,7 +12,7 @@ #include <linux/crypto.h> struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]); -void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad, +void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, const u8 *data, size_t data_len, u8 *mic); void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 89b0b2ca6db6..ebadb9ac9a7e 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -262,7 +262,11 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, "%pM on tid %u\n", mgmt->sa, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - goto end; + + /* delete existing Rx BA session on the same tid */ + ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, + WLAN_STATUS_UNSPECIFIED_QOS, + false); } /* prepare A-MPDU MLME for Rx aggregation */ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6e56c6ee7ccd..bfc36e904764 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -209,6 +209,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, u8 seq[6] = {0}; struct key_params params; struct ieee80211_key *key = NULL; + u64 pn64; u32 iv32; u16 iv16; int err = -ENOENT; @@ -256,22 +257,24 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, params.seq_len = 6; break; case WLAN_CIPHER_SUITE_CCMP: - seq[0] = key->u.ccmp.tx_pn[5]; - seq[1] = key->u.ccmp.tx_pn[4]; - seq[2] = key->u.ccmp.tx_pn[3]; - seq[3] = key->u.ccmp.tx_pn[2]; - seq[4] = key->u.ccmp.tx_pn[1]; - seq[5] = key->u.ccmp.tx_pn[0]; + pn64 = atomic64_read(&key->u.ccmp.tx_pn); + seq[0] = pn64; + seq[1] = pn64 >> 8; + seq[2] = pn64 >> 16; + seq[3] = pn64 >> 24; + seq[4] = pn64 >> 32; + seq[5] = pn64 >> 40; params.seq = seq; params.seq_len = 6; break; case WLAN_CIPHER_SUITE_AES_CMAC: - seq[0] = key->u.aes_cmac.tx_pn[5]; - seq[1] = key->u.aes_cmac.tx_pn[4]; - seq[2] = key->u.aes_cmac.tx_pn[3]; - seq[3] = key->u.aes_cmac.tx_pn[2]; - seq[4] = key->u.aes_cmac.tx_pn[1]; - seq[5] = key->u.aes_cmac.tx_pn[0]; + pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); + seq[0] = pn64; + seq[1] = pn64 >> 8; + seq[2] = pn64 >> 16; + seq[3] = pn64 >> 24; + seq[4] = pn64 >> 32; + seq[5] = pn64 >> 40; params.seq = seq; params.seq_len = 6; break; @@ -674,8 +677,11 @@ static void sta_apply_parameters(struct ieee80211_local *local, if (mask & BIT(NL80211_STA_FLAG_WME)) { sta->flags &= ~WLAN_STA_WME; - if (set & BIT(NL80211_STA_FLAG_WME)) + sta->sta.wme = false; + if (set & BIT(NL80211_STA_FLAG_WME)) { sta->flags |= WLAN_STA_WME; + sta->sta.wme = true; + } } if (mask & BIT(NL80211_STA_FLAG_MFP)) { @@ -2098,6 +2104,21 @@ static void ieee80211_get_ringparam(struct wiphy *wiphy, drv_get_ringparam(local, tx, tx_max, rx, rx_max); } +static int ieee80211_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (!local->ops->set_rekey_data) + return -EOPNOTSUPP; + + drv_set_rekey_data(local, sdata, data); + + return 0; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -2160,4 +2181,5 @@ struct cfg80211_ops mac80211_config_ops = { .get_antenna = ieee80211_get_antenna, .set_ringparam = ieee80211_set_ringparam, .get_ringparam = ieee80211_get_ringparam, + .set_rekey_data = ieee80211_set_rekey_data, }; diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 33c58b85c911..38e6101190d9 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -78,7 +78,7 @@ KEY_OPS(algorithm); static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - const u8 *tpn; + u64 pn; char buf[20]; int len; struct ieee80211_key *key = file->private_data; @@ -94,15 +94,16 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, key->u.tkip.tx.iv16); break; case WLAN_CIPHER_SUITE_CCMP: - tpn = key->u.ccmp.tx_pn; + pn = atomic64_read(&key->u.ccmp.tx_pn); len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", - tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); + (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), + (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); break; case WLAN_CIPHER_SUITE_AES_CMAC: - tpn = key->u.aes_cmac.tx_pn; + pn = atomic64_read(&key->u.aes_cmac.tx_pn); len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", - tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], - tpn[5]); + (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), + (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); break; default: return 0; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 0e7e4268ddf6..edd2dd79c9be 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -647,4 +647,14 @@ static inline int drv_set_bitrate_mask(struct ieee80211_local *local, return ret; } +static inline void drv_set_rekey_data(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct cfg80211_gtk_rekey_data *data) +{ + trace_drv_set_rekey_data(local, sdata, data); + if (local->ops->set_rekey_data) + local->ops->set_rekey_data(&local->hw, &sdata->vif, data); + trace_drv_return_void(local); +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 3cb6795e926d..31a9dfa81f65 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -1024,6 +1024,34 @@ TRACE_EVENT(drv_set_bitrate_mask, ) ); +TRACE_EVENT(drv_set_rekey_data, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct cfg80211_gtk_rekey_data *data), + + TP_ARGS(local, sdata, data), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __array(u8, kek, NL80211_KEK_LEN) + __array(u8, kck, NL80211_KCK_LEN) + __array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + memcpy(__entry->kek, data->kek, NL80211_KEK_LEN); + memcpy(__entry->kck, data->kck, NL80211_KCK_LEN); + memcpy(__entry->replay_ctr, data->replay_ctr, + NL80211_REPLAY_CTR_LEN); + ), + + TP_printk(LOCAL_PR_FMT VIF_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG) +); + /* * Tracing for API calls that drivers call. */ @@ -1293,6 +1321,27 @@ DEFINE_EVENT(local_only_evt, api_remain_on_channel_expired, TP_ARGS(local) ); +TRACE_EVENT(api_gtk_rekey_notify, + TP_PROTO(struct ieee80211_sub_if_data *sdata, + const u8 *bssid, const u8 *replay_ctr), + + TP_ARGS(sdata, bssid, replay_ctr), + + TP_STRUCT__entry( + VIF_ENTRY + __array(u8, bssid, ETH_ALEN) + __array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN) + ), + + TP_fast_assign( + VIF_ASSIGN; + memcpy(__entry->bssid, bssid, ETH_ALEN); + memcpy(__entry->replay_ctr, replay_ctr, NL80211_REPLAY_CTR_LEN); + ), + + TP_printk(VIF_PR_FMT, VIF_PR_ARG) +); + /* * Tracing for internal functions * (which may also be called in response to driver calls) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 090b0ec1e056..4c7a831e7d1e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -202,7 +202,22 @@ struct ieee80211_rx_data { struct ieee80211_key *key; unsigned int flags; - int queue; + + /* + * Index into sequence numbers array, 0..16 + * since the last (16) is used for non-QoS, + * will be 16 on non-QoS frames. + */ + int seqno_idx; + + /* + * Index into the security IV/PN arrays, 0..16 + * since the last (16) is used for CCMP-encrypted + * management frames, will be set to 16 on mgmt + * frames and 0 on non-QoS frames. + */ + int security_idx; + u32 tkip_iv32; u16 tkip_iv16; }; @@ -544,6 +559,9 @@ struct ieee80211_sub_if_data { /* keys */ struct list_head key_list; + /* count for keys needing tailroom space allocation */ + int crypto_tx_tailroom_needed_cnt; + struct net_device *dev; struct ieee80211_local *local; @@ -1350,10 +1368,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len); + const u8 *ie, size_t ie_len, + bool directed); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len); + const u8 *ie, size_t ie_len, + bool directed); void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, const size_t supp_rates_len, diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f825e2f0a57e..739bee13e813 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -61,6 +61,36 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) return NULL; } +static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) +{ + /* + * When this count is zero, SKB resizing for allocating tailroom + * for IV or MMIC is skipped. But, this check has created two race + * cases in xmit path while transiting from zero count to one: + * + * 1. SKB resize was skipped because no key was added but just before + * the xmit key is added and SW encryption kicks off. + * + * 2. SKB resize was skipped because all the keys were hw planted but + * just before xmit one of the key is deleted and SW encryption kicks + * off. + * + * In both the above case SW encryption will find not enough space for + * tailroom and exits with WARN_ON. (See WARN_ONs at wpa.c) + * + * Solution has been explained at + * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net + */ + + if (!sdata->crypto_tx_tailroom_needed_cnt++) { + /* + * Flush all XMIT packets currently using HW encryption or no + * encryption at all if the count transition is from 0 -> 1. + */ + synchronize_net(); + } +} + static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) { struct ieee80211_sub_if_data *sdata; @@ -101,6 +131,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (!ret) { key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + + if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || + (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) + sdata->crypto_tx_tailroom_needed_cnt--; + return 0; } @@ -142,6 +177,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) sta = get_sta_for_key(key); sdata = key->sdata; + if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || + (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) + increment_tailroom_need_count(sdata); + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, @@ -330,6 +369,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, get_unaligned_le16(seq); } } + spin_lock_init(&key->u.tkip.txlock); break; case WLAN_CIPHER_SUITE_CCMP: key->conf.iv_len = CCMP_HDR_LEN; @@ -394,8 +434,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) ieee80211_aes_key_free(key->u.ccmp.tfm); if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); - if (key->local) + if (key->local) { ieee80211_debugfs_key_remove(key); + key->sdata->crypto_tx_tailroom_needed_cnt--; + } kfree(key); } @@ -452,6 +494,8 @@ int ieee80211_key_link(struct ieee80211_key *key, else old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); + increment_tailroom_need_count(sdata); + __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); __ieee80211_key_destroy(old_key); @@ -498,12 +542,49 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) mutex_lock(&sdata->local->key_mtx); - list_for_each_entry(key, &sdata->key_list, list) + sdata->crypto_tx_tailroom_needed_cnt = 0; + + list_for_each_entry(key, &sdata->key_list, list) { + increment_tailroom_need_count(sdata); ieee80211_key_enable_hw_accel(key); + } mutex_unlock(&sdata->local->key_mtx); } +void ieee80211_iter_keys(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + void (*iter)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *data), + void *iter_data) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_key *key; + struct ieee80211_sub_if_data *sdata; + + ASSERT_RTNL(); + + mutex_lock(&local->key_mtx); + if (vif) { + sdata = vif_to_sdata(vif); + list_for_each_entry(key, &sdata->key_list, list) + iter(hw, &sdata->vif, + key->sta ? &key->sta->sta : NULL, + &key->conf, iter_data); + } else { + list_for_each_entry(sdata, &local->interfaces, list) + list_for_each_entry(key, &sdata->key_list, list) + iter(hw, &sdata->vif, + key->sta ? &key->sta->sta : NULL, + &key->conf, iter_data); + } + mutex_unlock(&local->key_mtx); +} +EXPORT_SYMBOL(ieee80211_iter_keys); + void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) { struct ieee80211_key *key; @@ -533,3 +614,89 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) mutex_unlock(&sdata->local->key_mtx); } + + +void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + + trace_api_gtk_rekey_notify(sdata, bssid, replay_ctr); + + cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp); +} +EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify); + +void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, + struct ieee80211_key_seq *seq) +{ + struct ieee80211_key *key; + u64 pn64; + + if (WARN_ON(!(keyconf->flags & IEEE80211_KEY_FLAG_GENERATE_IV))) + return; + + key = container_of(keyconf, struct ieee80211_key, conf); + + switch (key->conf.cipher) { + case WLAN_CIPHER_SUITE_TKIP: + seq->tkip.iv32 = key->u.tkip.tx.iv32; + seq->tkip.iv16 = key->u.tkip.tx.iv16; + break; + case WLAN_CIPHER_SUITE_CCMP: + pn64 = atomic64_read(&key->u.ccmp.tx_pn); + seq->ccmp.pn[5] = pn64; + seq->ccmp.pn[4] = pn64 >> 8; + seq->ccmp.pn[3] = pn64 >> 16; + seq->ccmp.pn[2] = pn64 >> 24; + seq->ccmp.pn[1] = pn64 >> 32; + seq->ccmp.pn[0] = pn64 >> 40; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); + seq->ccmp.pn[5] = pn64; + seq->ccmp.pn[4] = pn64 >> 8; + seq->ccmp.pn[3] = pn64 >> 16; + seq->ccmp.pn[2] = pn64 >> 24; + seq->ccmp.pn[1] = pn64 >> 32; + seq->ccmp.pn[0] = pn64 >> 40; + break; + default: + WARN_ON(1); + } +} +EXPORT_SYMBOL(ieee80211_get_key_tx_seq); + +void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, + int tid, struct ieee80211_key_seq *seq) +{ + struct ieee80211_key *key; + const u8 *pn; + + key = container_of(keyconf, struct ieee80211_key, conf); + + switch (key->conf.cipher) { + case WLAN_CIPHER_SUITE_TKIP: + if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES)) + return; + seq->tkip.iv32 = key->u.tkip.rx[tid].iv32; + seq->tkip.iv16 = key->u.tkip.rx[tid].iv16; + break; + case WLAN_CIPHER_SUITE_CCMP: + if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES)) + return; + if (tid < 0) + pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES]; + else + pn = key->u.ccmp.rx_pn[tid]; + memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + if (WARN_ON(tid != 0)) + return; + pn = key->u.aes_cmac.rx_pn; + memcpy(seq->aes_cmac.pn, pn, CMAC_PN_LEN); + break; + } +} +EXPORT_SYMBOL(ieee80211_get_key_rx_seq); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index d801d5351336..86b216b01415 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -28,8 +28,9 @@ #define CCMP_PN_LEN 6 #define TKIP_IV_LEN 8 #define TKIP_ICV_LEN 4 +#define CMAC_PN_LEN 6 -#define NUM_RX_DATA_QUEUES 17 +#define NUM_RX_DATA_QUEUES 16 struct ieee80211_local; struct ieee80211_sub_if_data; @@ -52,9 +53,10 @@ enum ieee80211_internal_tkip_state { }; struct tkip_ctx { - u32 iv32; - u16 iv16; - u16 p1k[5]; + u32 iv32; /* current iv32 */ + u16 iv16; /* current iv16 */ + u16 p1k[5]; /* p1k cache */ + u32 p1k_iv32; /* iv32 for which p1k computed */ enum ieee80211_internal_tkip_state state; }; @@ -71,6 +73,9 @@ struct ieee80211_key { union { struct { + /* protects tx context */ + spinlock_t txlock; + /* last used TSC */ struct tkip_ctx tx; @@ -78,32 +83,23 @@ struct ieee80211_key { struct tkip_ctx rx[NUM_RX_DATA_QUEUES]; } tkip; struct { - u8 tx_pn[6]; + atomic64_t tx_pn; /* * Last received packet number. The first * NUM_RX_DATA_QUEUES counters are used with Data * frames and the last counter is used with Robust * Management frames. */ - u8 rx_pn[NUM_RX_DATA_QUEUES + 1][6]; + u8 rx_pn[NUM_RX_DATA_QUEUES + 1][CCMP_PN_LEN]; struct crypto_cipher *tfm; u32 replays; /* dot11RSNAStatsCCMPReplays */ - /* scratch buffers for virt_to_page() (crypto API) */ -#ifndef AES_BLOCK_LEN -#define AES_BLOCK_LEN 16 -#endif - u8 tx_crypto_buf[6 * AES_BLOCK_LEN]; - u8 rx_crypto_buf[6 * AES_BLOCK_LEN]; } ccmp; struct { - u8 tx_pn[6]; - u8 rx_pn[6]; + atomic64_t tx_pn; + u8 rx_pn[CMAC_PN_LEN]; struct crypto_cipher *tfm; u32 replays; /* dot11RSNAStatsCMACReplays */ u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ - /* scratch buffers for virt_to_page() (crypto API) */ - u8 tx_crypto_buf[2 * AES_BLOCK_LEN]; - u8 rx_crypto_buf[2 * AES_BLOCK_LEN]; } aes_cmac; } u; diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 0d2faacc3e87..068ee6518254 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -647,12 +647,12 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) mpath = node->mpath; if (mpath->sdata == sdata && memcmp(addr, mpath->dst, ETH_ALEN) == 0) { - spin_lock_bh(&mpath->state_lock); + spin_lock(&mpath->state_lock); mpath->flags |= MESH_PATH_RESOLVING; hlist_del_rcu(&node->list); call_rcu(&node->rcu, mesh_path_node_reclaim); atomic_dec(&tbl->entries); - spin_unlock_bh(&mpath->state_lock); + spin_unlock(&mpath->state_lock); goto enddel; } } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index faca5033f061..b6d9bd5f4d3c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -749,7 +749,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) container_of(work, struct ieee80211_local, dynamic_ps_enable_work); struct ieee80211_sub_if_data *sdata = local->ps_sdata; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_if_managed *ifmgd; unsigned long flags; int q; @@ -757,26 +757,39 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) if (!sdata) return; + ifmgd = &sdata->u.mgd; + if (local->hw.conf.flags & IEEE80211_CONF_PS) return; - /* - * transmission can be stopped by others which leads to - * dynamic_ps_timer expiry. Postpond the ps timer if it - * is not the actual idle state. - */ - spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - for (q = 0; q < local->hw.queues; q++) { - if (local->queue_stop_reasons[q]) { - spin_unlock_irqrestore(&local->queue_stop_reason_lock, - flags); + if (!local->disable_dynamic_ps && + local->hw.conf.dynamic_ps_timeout > 0) { + /* don't enter PS if TX frames are pending */ + if (drv_tx_frames_pending(local)) { mod_timer(&local->dynamic_ps_timer, jiffies + msecs_to_jiffies( local->hw.conf.dynamic_ps_timeout)); return; } + + /* + * transmission can be stopped by others which leads to + * dynamic_ps_timer expiry. Postpone the ps timer if it + * is not the actual idle state. + */ + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (q = 0; q < local->hw.queues; q++) { + if (local->queue_stop_reasons[q]) { + spin_unlock_irqrestore(&local->queue_stop_reason_lock, + flags); + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies( + local->hw.conf.dynamic_ps_timeout)); + return; + } + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { @@ -801,7 +814,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } - netif_tx_wake_all_queues(sdata->dev); + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + netif_tx_wake_all_queues(sdata->dev); } void ieee80211_dynamic_ps_timer(unsigned long data) @@ -1204,7 +1218,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) ieee80211_send_nullfunc(sdata->local, sdata, 0); } else { ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); - ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); + ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0, + true); } ifmgd->probe_send_count++; @@ -1289,7 +1304,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, - ssid + 2, ssid[1], NULL, 0); + ssid + 2, ssid[1], NULL, 0, true); return skb; } @@ -2200,6 +2215,9 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + if (!ifmgd->associated) + return; + if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) add_timer(&ifmgd->timer); if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 67839eb90cc1..f87e993e713b 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -72,15 +72,19 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) local->wowlan = wowlan && local->open_count; if (local->wowlan) { int err = drv_suspend(local, wowlan); - if (err) { + if (err < 0) { local->quiescing = false; return err; + } else if (err > 0) { + WARN_ON(err != 1); + local->wowlan = false; + } else { + list_for_each_entry(sdata, &local->interfaces, list) { + cancel_work_sync(&sdata->work); + ieee80211_quiesce(sdata); + } + goto suspend; } - list_for_each_entry(sdata, &local->interfaces, list) { - cancel_work_sync(&sdata->work); - ieee80211_quiesce(sdata); - } - goto suspend; } /* disable keys */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7fa8c6be7bf0..e6dccc70931d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -331,15 +331,18 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - int tid; + int tid, seqno_idx, security_idx; /* does the frame have a qos control field? */ if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *qc = ieee80211_get_qos_ctl(hdr); /* frame has qos control */ tid = *qc & IEEE80211_QOS_CTL_TID_MASK; - if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) status->rx_flags |= IEEE80211_RX_AMSDU; + + seqno_idx = tid; + security_idx = tid; } else { /* * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"): @@ -352,10 +355,15 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) * * We also use that counter for non-QoS STAs. */ - tid = NUM_RX_DATA_QUEUES - 1; + seqno_idx = NUM_RX_DATA_QUEUES; + security_idx = 0; + if (ieee80211_is_mgmt(hdr->frame_control)) + security_idx = NUM_RX_DATA_QUEUES; + tid = 0; } - rx->queue = tid; + rx->seqno_idx = seqno_idx; + rx->security_idx = security_idx; /* Set skb->priority to 1d tag if highest order bit of TID is not set. * For now, set skb->priority to 0 for other cases. */ rx->skb->priority = (tid > 7) ? 0 : tid; @@ -810,7 +818,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { if (unlikely(ieee80211_has_retry(hdr->frame_control) && - rx->sta->last_seq_ctrl[rx->queue] == + rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) { if (status->rx_flags & IEEE80211_RX_RA_MATCH) { rx->local->dot11FrameDuplicateCount++; @@ -818,7 +826,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) } return RX_DROP_UNUSABLE; } else - rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl; + rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl; } if (unlikely(rx->skb->len < 16)) { @@ -1374,11 +1382,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) if (frag == 0) { /* This is the first fragment of a new frame. */ entry = ieee80211_reassemble_add(rx->sdata, frag, seq, - rx->queue, &(rx->skb)); + rx->seqno_idx, &(rx->skb)); if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP && ieee80211_has_protected(fc)) { - int queue = ieee80211_is_mgmt(fc) ? - NUM_RX_DATA_QUEUES : rx->queue; + int queue = rx->security_idx; /* Store CCMP PN so that we can verify that the next * fragment has a sequential PN value. */ entry->ccmp = 1; @@ -1392,7 +1399,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) /* This is a fragment for a frame that should already be pending in * fragment cache. Add this fragment to the end of the pending entry. */ - entry = ieee80211_reassemble_find(rx->sdata, frag, seq, rx->queue, hdr); + entry = ieee80211_reassemble_find(rx->sdata, frag, seq, + rx->seqno_idx, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); return RX_DROP_MONITOR; @@ -1412,8 +1420,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) if (pn[i]) break; } - queue = ieee80211_is_mgmt(fc) ? - NUM_RX_DATA_QUEUES : rx->queue; + queue = rx->security_idx; rpn = rx->key->u.ccmp.rx_pn[queue]; if (memcmp(pn, rpn, CCMP_PN_LEN)) return RX_DROP_UNUSABLE; @@ -2590,7 +2597,9 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) .sta = sta, .sdata = sta->sdata, .local = sta->local, - .queue = tid, + /* This is OK -- must be QoS data frame */ + .security_idx = tid, + .seqno_idx = tid, .flags = 0, }; struct tid_ampdu_rx *tid_agg_rx; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1758b463c583..08a45ac3d6f8 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -228,6 +228,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) { struct cfg80211_scan_request *req = local->scan_req; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; enum ieee80211_band band; int i, ielen, n_chans; @@ -251,8 +252,8 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) local->hw_scan_req->n_channels = n_chans; ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, - req->ie, req->ie_len, band, (u32) -1, - 0); + req->ie, req->ie_len, band, + sdata->rc_rateidx_mask[band], 0); local->hw_scan_req->ie_len = ielen; return true; @@ -658,7 +659,8 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, sdata, NULL, local->scan_req->ssids[i].ssid, local->scan_req->ssids[i].ssid_len, - local->scan_req->ie, local->scan_req->ie_len); + local->scan_req->ie, local->scan_req->ie_len, + false); /* * After sending probe requests, wait for probe responses @@ -882,7 +884,8 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, for (i = 0; i < IEEE80211_NUM_BANDS; i++) { local->sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len, + local->scan_ies_len + + req->ie_len, GFP_KERNEL); if (!local->sched_scan_ies.ie[i]) { ret = -ENOMEM; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index a06d64ebc177..28beb78e601e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -287,7 +287,8 @@ struct sta_info { unsigned long rx_dropped; int last_signal; struct ewma avg_signal; - __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; + /* Plus 1 for non-QoS frames */ + __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1]; /* Updated from TX status path only, no locking requirements */ unsigned long tx_filtered_count; diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 757e4eb2baf7..cc79e697cdb2 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -101,6 +101,7 @@ static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx, p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i; } ctx->state = TKIP_STATE_PHASE1_DONE; + ctx->p1k_iv32 = tsc_IV32; } static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, @@ -140,60 +141,69 @@ static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets * of the IV. Returns pointer to the octet following IVs (i.e., beginning of * the packet payload). */ -u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16) +u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key) { - pos = write_tkip_iv(pos, iv16); + lockdep_assert_held(&key->u.tkip.txlock); + + pos = write_tkip_iv(pos, key->u.tkip.tx.iv16); *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */; put_unaligned_le32(key->u.tkip.tx.iv32, pos); return pos + 4; } -void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, - struct sk_buff *skb, enum ieee80211_tkip_key_type type, - u8 *outkey) +static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32) { - struct ieee80211_key *key = (struct ieee80211_key *) - container_of(keyconf, struct ieee80211_key, conf); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u8 *data; - const u8 *tk; - struct tkip_ctx *ctx; - u16 iv16; - u32 iv32; - - data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); - iv16 = data[2] | (data[0] << 8); - iv32 = get_unaligned_le32(&data[4]); - - tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; - ctx = &key->u.tkip.tx; + struct ieee80211_sub_if_data *sdata = key->sdata; + struct tkip_ctx *ctx = &key->u.tkip.tx; + const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; -#ifdef CONFIG_MAC80211_TKIP_DEBUG - printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", - iv16, iv32); - - if (iv32 != ctx->iv32) { - printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n", - iv32, ctx->iv32); - printk(KERN_DEBUG "Wrap around of iv16 in the middle of a " - "fragmented packet\n"); - } -#endif + lockdep_assert_held(&key->u.tkip.txlock); + + /* + * Update the P1K when the IV32 is different from the value it + * had when we last computed it (or when not initialised yet). + * This might flip-flop back and forth if packets are processed + * out-of-order due to the different ACs, but then we have to + * just compute the P1K more often. + */ + if (ctx->p1k_iv32 != iv32 || ctx->state == TKIP_STATE_NOT_INIT) + tkip_mixing_phase1(tk, ctx, sdata->vif.addr, iv32); +} - /* Update the p1k only when the iv16 in the packet wraps around, this - * might occur after the wrap around of iv16 in the key in case of - * fragmented packets. */ - if (iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) - tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32); +void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, + u32 iv32, u16 *p1k) +{ + struct ieee80211_key *key = (struct ieee80211_key *) + container_of(keyconf, struct ieee80211_key, conf); + struct tkip_ctx *ctx = &key->u.tkip.tx; + unsigned long flags; - if (type == IEEE80211_TKIP_P1_KEY) { - memcpy(outkey, ctx->p1k, sizeof(u16) * 5); - return; - } + spin_lock_irqsave(&key->u.tkip.txlock, flags); + ieee80211_compute_tkip_p1k(key, iv32); + memcpy(p1k, ctx->p1k, sizeof(ctx->p1k)); + spin_unlock_irqrestore(&key->u.tkip.txlock, flags); +} +EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); - tkip_mixing_phase2(tk, ctx, iv16, outkey); +void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, + struct sk_buff *skb, u8 *p2k) +{ + struct ieee80211_key *key = (struct ieee80211_key *) + container_of(keyconf, struct ieee80211_key, conf); + const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; + struct tkip_ctx *ctx = &key->u.tkip.tx; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); + u32 iv32 = get_unaligned_le32(&data[4]); + u16 iv16 = data[2] | (data[0] << 8); + unsigned long flags; + + spin_lock_irqsave(&key->u.tkip.txlock, flags); + ieee80211_compute_tkip_p1k(key, iv32); + tkip_mixing_phase2(tk, ctx, iv16, p2k); + spin_unlock_irqrestore(&key->u.tkip.txlock, flags); } -EXPORT_SYMBOL(ieee80211_get_tkip_key); +EXPORT_SYMBOL(ieee80211_get_tkip_p2k); /* * Encrypt packet payload with TKIP using @key. @pos is a pointer to the @@ -204,19 +214,15 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key); */ int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, struct ieee80211_key *key, - u8 *pos, size_t payload_len, u8 *ta) + struct sk_buff *skb, + u8 *payload, size_t payload_len) { u8 rc4key[16]; - struct tkip_ctx *ctx = &key->u.tkip.tx; - const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; - - /* Calculate per-packet key */ - if (ctx->iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) - tkip_mixing_phase1(tk, ctx, ta, ctx->iv32); - tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); + ieee80211_get_tkip_p2k(&key->conf, skb, rc4key); - return ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); + return ieee80211_wep_encrypt_data(tfm, rc4key, 16, + payload, payload_len); } /* Decrypt packet payload with TKIP using @key. @pos is a pointer to the diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index 1cab9c86978f..e3ecb659b90a 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -13,11 +13,13 @@ #include <linux/crypto.h> #include "key.h" -u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16); +u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key); int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, - struct ieee80211_key *key, - u8 *pos, size_t payload_len, u8 *ta); + struct ieee80211_key *key, + struct sk_buff *skb, + u8 *payload, size_t payload_len); + enum { TKIP_DECRYPT_OK = 0, TKIP_DECRYPT_NO_EXT_IV = -1, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3104c844b544..e8d0d2d22665 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1474,18 +1474,14 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, /* device xmit handlers */ -static int ieee80211_skb_resize(struct ieee80211_local *local, +static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int head_need, bool may_encrypt) { + struct ieee80211_local *local = sdata->local; int tail_need = 0; - /* - * This could be optimised, devices that do full hardware - * crypto (including TKIP MMIC) need no tailroom... But we - * have no drivers for such devices currently. - */ - if (may_encrypt) { + if (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt) { tail_need = IEEE80211_ENCRYPT_TAILROOM; tail_need -= skb_tailroom(skb); tail_need = max_t(int, tail_need, 0); @@ -1578,7 +1574,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, headroom -= skb_headroom(skb); headroom = max_t(int, 0, headroom); - if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) { + if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) { dev_kfree_skb(skb); rcu_read_unlock(); return; @@ -1945,7 +1941,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, head_need += IEEE80211_ENCRYPT_HEADROOM; head_need += local->tx_headroom; head_need = max_t(int, 0, head_need); - if (ieee80211_skb_resize(local, skb, head_need, true)) + if (ieee80211_skb_resize(sdata, skb, head_need, true)) goto fail; } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 05e3fb889d77..652e5695225a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1018,7 +1018,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len) + const u8 *ie, size_t ie_len, + bool directed) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; @@ -1035,8 +1036,16 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, return NULL; } - chan = ieee80211_frequency_to_channel( - local->hw.conf.channel->center_freq); + /* + * Do not send DS Channel parameter for directed probe requests + * in order to maximize the chance that we get a response. Some + * badly-behaved APs don't respond when this parameter is included. + */ + if (directed) + chan = 0; + else + chan = ieee80211_frequency_to_channel( + local->hw.conf.channel->center_freq); buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, local->hw.conf.channel->band, @@ -1062,11 +1071,13 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len) + const u8 *ie, size_t ie_len, + bool directed) { struct sk_buff *skb; - skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len); + skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len, + directed); if (skb) ieee80211_tx_skb(sdata, skb); } diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 28bc084dbfb9..7a49532f14cb 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -151,8 +151,7 @@ void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb) tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; if (unlikely(local->wifi_wme_noack_test)) - ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << - QOS_CONTROL_ACK_POLICY_SHIFT; + ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; /* qos header is 2 bytes, second reserved */ *p++ = ack_policy | tid; *p = 0; diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 6053b1c9feee..faead6d02026 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -13,11 +13,6 @@ #include <linux/netdevice.h> #include "ieee80211_i.h" -#define QOS_CONTROL_ACK_POLICY_NORMAL 0 -#define QOS_CONTROL_ACK_POLICY_NOACK 1 - -#define QOS_CONTROL_ACK_POLICY_SHIFT 5 - extern const int ieee802_1d_to_ac[8]; u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/work.c b/net/mac80211/work.c index d2e7f0e86677..edf8583280c9 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -450,7 +450,7 @@ ieee80211_direct_probe(struct ieee80211_work *wk) * will not answer to direct packet in unassociated state. */ ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid, - wk->probe_auth.ssid_len, NULL, 0); + wk->probe_auth.ssid_len, NULL, 0, true); wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; run_again(local, wk->timeout); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 9dc3b5f26e80..7bc8702808fa 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -15,6 +15,7 @@ #include <linux/gfp.h> #include <asm/unaligned.h> #include <net/mac80211.h> +#include <crypto/aes.h> #include "ieee80211_i.h" #include "michael.h" @@ -148,13 +149,19 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) update_iv: /* update IV in key information to be able to detect replays */ - rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; - rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; + rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32; + rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16; return RX_CONTINUE; mic_fail: - mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, + /* + * In some cases the key can be unset - e.g. a multicast packet, in + * a driver that supports HW encryption. Send up the key idx only if + * the key is set. + */ + mac80211_ev_michael_mic_failure(rx->sdata, + rx->key ? rx->key->conf.keyidx : -1, (void *) skb->data, NULL, GFP_ATOMIC); return RX_DROP_UNUSABLE; } @@ -165,6 +172,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_key *key = tx->key; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + unsigned long flags; unsigned int hdrlen; int len, tail; u8 *pos; @@ -192,11 +200,12 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) pos += hdrlen; /* Increase IV for the frame */ + spin_lock_irqsave(&key->u.tkip.txlock, flags); key->u.tkip.tx.iv16++; if (key->u.tkip.tx.iv16 == 0) key->u.tkip.tx.iv32++; - - pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); + pos = ieee80211_tkip_add_iv(pos, key); + spin_unlock_irqrestore(&key->u.tkip.txlock, flags); /* hwaccel - with software IV */ if (info->control.hw_key) @@ -205,9 +214,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) /* Add room for ICV */ skb_put(skb, TKIP_ICV_LEN); - hdr = (struct ieee80211_hdr *) skb->data; return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm, - key, pos, len, hdr->addr2); + key, skb, pos, len); } @@ -255,7 +263,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, key, skb->data + hdrlen, skb->len - hdrlen, rx->sta->sta.addr, - hdr->addr1, hwaccel, rx->queue, + hdr->addr1, hwaccel, rx->security_idx, &rx->tkip_iv32, &rx->tkip_iv16); if (res != TKIP_DECRYPT_OK) @@ -283,8 +291,10 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, unsigned int hdrlen; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; + memset(scratch, 0, 6 * AES_BLOCK_SIZE); + + b_0 = scratch + 3 * AES_BLOCK_SIZE; + aad = scratch + 4 * AES_BLOCK_SIZE; /* * Mask FC: zero subtype b4 b5 b6 (if not mgmt) @@ -373,8 +383,10 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) struct ieee80211_key *key = tx->key; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen, len, tail; - u8 *pos, *pn; - int i; + u8 *pos; + u8 pn[6]; + u64 pn64; + u8 scratch[6 * AES_BLOCK_SIZE]; if (info->control.hw_key && !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { @@ -402,14 +414,14 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) hdr = (struct ieee80211_hdr *) pos; pos += hdrlen; - /* PN = PN + 1 */ - pn = key->u.ccmp.tx_pn; + pn64 = atomic64_inc_return(&key->u.ccmp.tx_pn); - for (i = CCMP_PN_LEN - 1; i >= 0; i--) { - pn[i]++; - if (pn[i]) - break; - } + pn[5] = pn64; + pn[4] = pn64 >> 8; + pn[3] = pn64 >> 16; + pn[2] = pn64 >> 24; + pn[1] = pn64 >> 32; + pn[0] = pn64 >> 40; ccmp_pn2hdr(pos, pn, key->conf.keyidx); @@ -418,8 +430,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) return 0; pos += CCMP_HDR_LEN; - ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0); - ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, key->u.ccmp.tx_crypto_buf, pos, len, + ccmp_special_blocks(skb, pn, scratch, 0); + ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, pos, len, pos, skb_put(skb, CCMP_MIC_LEN)); return 0; @@ -466,8 +478,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) ccmp_hdr2pn(pn, skb->data + hdrlen); - queue = ieee80211_is_mgmt(hdr->frame_control) ? - NUM_RX_DATA_QUEUES : rx->queue; + queue = rx->security_idx; if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) { key->u.ccmp.replays++; @@ -475,11 +486,12 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) } if (!(status->flag & RX_FLAG_DECRYPTED)) { + u8 scratch[6 * AES_BLOCK_SIZE]; /* hardware didn't decrypt/verify MIC */ - ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1); + ccmp_special_blocks(skb, pn, scratch, 1); if (ieee80211_aes_ccm_decrypt( - key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf, + key->u.ccmp.tfm, scratch, skb->data + hdrlen + CCMP_HDR_LEN, data_len, skb->data + skb->len - CCMP_MIC_LEN, skb->data + hdrlen + CCMP_HDR_LEN)) @@ -510,6 +522,16 @@ static void bip_aad(struct sk_buff *skb, u8 *aad) } +static inline void bip_ipn_set64(u8 *d, u64 pn) +{ + *d++ = pn; + *d++ = pn >> 8; + *d++ = pn >> 16; + *d++ = pn >> 24; + *d++ = pn >> 32; + *d = pn >> 40; +} + static inline void bip_ipn_swap(u8 *d, const u8 *s) { *d++ = s[5]; @@ -528,8 +550,8 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_key *key = tx->key; struct ieee80211_mmie *mmie; - u8 *pn, aad[20]; - int i; + u8 aad[20]; + u64 pn64; if (info->control.hw_key) return 0; @@ -543,22 +565,17 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) mmie->key_id = cpu_to_le16(key->conf.keyidx); /* PN = PN + 1 */ - pn = key->u.aes_cmac.tx_pn; + pn64 = atomic64_inc_return(&key->u.aes_cmac.tx_pn); - for (i = sizeof(key->u.aes_cmac.tx_pn) - 1; i >= 0; i--) { - pn[i]++; - if (pn[i]) - break; - } - bip_ipn_swap(mmie->sequence_number, pn); + bip_ipn_set64(mmie->sequence_number, pn64); bip_aad(skb, aad); /* * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */ - ieee80211_aes_cmac(key->u.aes_cmac.tfm, key->u.aes_cmac.tx_crypto_buf, - aad, skb->data + 24, skb->len - 24, mmie->mic); + ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, + skb->data + 24, skb->len - 24, mmie->mic); return TX_CONTINUE; } @@ -596,8 +613,7 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) if (!(status->flag & RX_FLAG_DECRYPTED)) { /* hardware didn't decrypt/verify MIC */ bip_aad(skb, aad); - ieee80211_aes_cmac(key->u.aes_cmac.tfm, - key->u.aes_cmac.rx_crypto_buf, aad, + ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, skb->data + 24, skb->len - 24, mic); if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) { key->u.aes_cmac.icverrors++; diff --git a/net/nfc/Kconfig b/net/nfc/Kconfig new file mode 100644 index 000000000000..33e095b124b3 --- /dev/null +++ b/net/nfc/Kconfig @@ -0,0 +1,16 @@ +# +# NFC sybsystem configuration +# + +menuconfig NFC + depends on NET && EXPERIMENTAL + tristate "NFC subsystem support (EXPERIMENTAL)" + default n + help + Say Y here if you want to build support for NFC (Near field + communication) devices. + + To compile this support as a module, choose M here: the module will + be called nfc. + +source "drivers/nfc/Kconfig" diff --git a/net/nfc/Makefile b/net/nfc/Makefile new file mode 100644 index 000000000000..16250c353851 --- /dev/null +++ b/net/nfc/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Linux NFC subsystem. +# + +obj-$(CONFIG_NFC) += nfc.o + +nfc-objs := core.o netlink.o af_nfc.o rawsock.o diff --git a/net/nfc/af_nfc.c b/net/nfc/af_nfc.c new file mode 100644 index 000000000000..e982cef8f49d --- /dev/null +++ b/net/nfc/af_nfc.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * + * Authors: + * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> + * Lauro Ramos Venancio <lauro.venancio@openbossa.org> + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/nfc.h> + +#include "nfc.h" + +static DEFINE_RWLOCK(proto_tab_lock); +static const struct nfc_protocol *proto_tab[NFC_SOCKPROTO_MAX]; + +static int nfc_sock_create(struct net *net, struct socket *sock, int proto, + int kern) +{ + int rc = -EPROTONOSUPPORT; + + if (net != &init_net) + return -EAFNOSUPPORT; + + if (proto < 0 || proto >= NFC_SOCKPROTO_MAX) + return -EINVAL; + + read_lock(&proto_tab_lock); + if (proto_tab[proto] && try_module_get(proto_tab[proto]->owner)) { + rc = proto_tab[proto]->create(net, sock, proto_tab[proto]); + module_put(proto_tab[proto]->owner); + } + read_unlock(&proto_tab_lock); + + return rc; +} + +static struct net_proto_family nfc_sock_family_ops = { + .owner = THIS_MODULE, + .family = PF_NFC, + .create = nfc_sock_create, +}; + +int nfc_proto_register(const struct nfc_protocol *nfc_proto) +{ + int rc; + + if (nfc_proto->id < 0 || nfc_proto->id >= NFC_SOCKPROTO_MAX) + return -EINVAL; + + rc = proto_register(nfc_proto->proto, 0); + if (rc) + return rc; + + write_lock(&proto_tab_lock); + if (proto_tab[nfc_proto->id]) + rc = -EBUSY; + else + proto_tab[nfc_proto->id] = nfc_proto; + write_unlock(&proto_tab_lock); + + return rc; +} +EXPORT_SYMBOL(nfc_proto_register); + +void nfc_proto_unregister(const struct nfc_protocol *nfc_proto) +{ + write_lock(&proto_tab_lock); + proto_tab[nfc_proto->id] = NULL; + write_unlock(&proto_tab_lock); + + proto_unregister(nfc_proto->proto); +} +EXPORT_SYMBOL(nfc_proto_unregister); + +int __init af_nfc_init(void) +{ + return sock_register(&nfc_sock_family_ops); +} + +void af_nfc_exit(void) +{ + sock_unregister(PF_NFC); +} diff --git a/net/nfc/core.c b/net/nfc/core.c new file mode 100644 index 000000000000..b6fd4e1f2057 --- /dev/null +++ b/net/nfc/core.c @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * + * Authors: + * Lauro Ramos Venancio <lauro.venancio@openbossa.org> + * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "nfc.h" + +#define VERSION "0.1" + +int nfc_devlist_generation; +DEFINE_MUTEX(nfc_devlist_mutex); + +int nfc_printk(const char *level, const char *format, ...) +{ + struct va_format vaf; + va_list args; + int r; + + va_start(args, format); + + vaf.fmt = format; + vaf.va = &args; + + r = printk("%sNFC: %pV\n", level, &vaf); + + va_end(args); + + return r; +} +EXPORT_SYMBOL(nfc_printk); + +/** + * nfc_start_poll - start polling for nfc targets + * + * @dev: The nfc device that must start polling + * @protocols: bitset of nfc protocols that must be used for polling + * + * The device remains polling for targets until a target is found or + * the nfc_stop_poll function is called. + */ +int nfc_start_poll(struct nfc_dev *dev, u32 protocols) +{ + int rc; + + nfc_dbg("dev_name=%s protocols=0x%x", dev_name(&dev->dev), protocols); + + if (!protocols) + return -EINVAL; + + device_lock(&dev->dev); + + if (!device_is_registered(&dev->dev)) { + rc = -ENODEV; + goto error; + } + + if (dev->polling) { + rc = -EBUSY; + goto error; + } + + rc = dev->ops->start_poll(dev, protocols); + if (!rc) + dev->polling = true; + +error: + device_unlock(&dev->dev); + return rc; +} + +/** + * nfc_stop_poll - stop polling for nfc targets + * + * @dev: The nfc device that must stop polling + */ +int nfc_stop_poll(struct nfc_dev *dev) +{ + int rc = 0; + + nfc_dbg("dev_name=%s", dev_name(&dev->dev)); + + device_lock(&dev->dev); + + if (!device_is_registered(&dev->dev)) { + rc = -ENODEV; + goto error; + } + + if (!dev->polling) { + rc = -EINVAL; + goto error; + } + + dev->ops->stop_poll(dev); + dev->polling = false; + +error: + device_unlock(&dev->dev); + return rc; +} + +/** + * nfc_activate_target - prepare the target for data exchange + * + * @dev: The nfc device that found the target + * @target_idx: index of the target that must be activated + * @protocol: nfc protocol that will be used for data exchange + */ +int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) +{ + int rc; + + nfc_dbg("dev_name=%s target_idx=%u protocol=%u", dev_name(&dev->dev), + target_idx, protocol); + + device_lock(&dev->dev); + + if (!device_is_registered(&dev->dev)) { + rc = -ENODEV; + goto error; + } + + rc = dev->ops->activate_target(dev, target_idx, protocol); + +error: + device_unlock(&dev->dev); + return rc; +} + +/** + * nfc_deactivate_target - deactivate a nfc target + * + * @dev: The nfc device that found the target + * @target_idx: index of the target that must be deactivated + */ +int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx) +{ + int rc = 0; + + nfc_dbg("dev_name=%s target_idx=%u", dev_name(&dev->dev), target_idx); + + device_lock(&dev->dev); + + if (!device_is_registered(&dev->dev)) { + rc = -ENODEV; + goto error; + } + + dev->ops->deactivate_target(dev, target_idx); + +error: + device_unlock(&dev->dev); + return rc; +} + +/** + * nfc_data_exchange - transceive data + * + * @dev: The nfc device that found the target + * @target_idx: index of the target + * @skb: data to be sent + * @cb: callback called when the response is received + * @cb_context: parameter for the callback function + * + * The user must wait for the callback before calling this function again. + */ +int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, + struct sk_buff *skb, + data_exchange_cb_t cb, + void *cb_context) +{ + int rc; + + nfc_dbg("dev_name=%s target_idx=%u skb->len=%u", dev_name(&dev->dev), + target_idx, skb->len); + + device_lock(&dev->dev); + + if (!device_is_registered(&dev->dev)) { + rc = -ENODEV; + kfree_skb(skb); + goto error; + } + + rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context); + +error: + device_unlock(&dev->dev); + return rc; +} + +/** + * nfc_alloc_skb - allocate a skb for data exchange responses + * + * @size: size to allocate + * @gfp: gfp flags + */ +struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp) +{ + struct sk_buff *skb; + unsigned int total_size; + + total_size = size + 1; + skb = alloc_skb(total_size, gfp); + + if (skb) + skb_reserve(skb, 1); + + return skb; +} +EXPORT_SYMBOL(nfc_alloc_skb); + +/** + * nfc_targets_found - inform that targets were found + * + * @dev: The nfc device that found the targets + * @targets: array of nfc targets found + * @ntargets: targets array size + * + * The device driver must call this function when one or many nfc targets + * are found. After calling this function, the device driver must stop + * polling for targets. + */ +int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, + int n_targets) +{ + int i; + + nfc_dbg("dev_name=%s n_targets=%d", dev_name(&dev->dev), n_targets); + + dev->polling = false; + + for (i = 0; i < n_targets; i++) + targets[i].idx = dev->target_idx++; + + spin_lock_bh(&dev->targets_lock); + + dev->targets_generation++; + + kfree(dev->targets); + dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target), + GFP_ATOMIC); + + if (!dev->targets) { + dev->n_targets = 0; + spin_unlock_bh(&dev->targets_lock); + return -ENOMEM; + } + + dev->n_targets = n_targets; + spin_unlock_bh(&dev->targets_lock); + + nfc_genl_targets_found(dev); + + return 0; +} +EXPORT_SYMBOL(nfc_targets_found); + +static void nfc_release(struct device *d) +{ + struct nfc_dev *dev = to_nfc_dev(d); + + nfc_dbg("dev_name=%s", dev_name(&dev->dev)); + + nfc_genl_data_exit(&dev->genl_data); + kfree(dev->targets); + kfree(dev); +} + +struct class nfc_class = { + .name = "nfc", + .dev_release = nfc_release, +}; +EXPORT_SYMBOL(nfc_class); + +static int match_idx(struct device *d, void *data) +{ + struct nfc_dev *dev = to_nfc_dev(d); + unsigned *idx = data; + + return dev->idx == *idx; +} + +struct nfc_dev *nfc_get_device(unsigned idx) +{ + struct device *d; + + d = class_find_device(&nfc_class, NULL, &idx, match_idx); + if (!d) + return NULL; + + return to_nfc_dev(d); +} + +/** + * nfc_allocate_device - allocate a new nfc device + * + * @ops: device operations + * @supported_protocols: NFC protocols supported by the device + */ +struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, + u32 supported_protocols) +{ + static atomic_t dev_no = ATOMIC_INIT(0); + struct nfc_dev *dev; + + if (!ops->start_poll || !ops->stop_poll || !ops->activate_target || + !ops->deactivate_target || !ops->data_exchange) + return NULL; + + if (!supported_protocols) + return NULL; + + dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->dev.class = &nfc_class; + dev->idx = atomic_inc_return(&dev_no) - 1; + dev_set_name(&dev->dev, "nfc%d", dev->idx); + device_initialize(&dev->dev); + + dev->ops = ops; + dev->supported_protocols = supported_protocols; + + spin_lock_init(&dev->targets_lock); + nfc_genl_data_init(&dev->genl_data); + + /* first generation must not be 0 */ + dev->targets_generation = 1; + + return dev; +} +EXPORT_SYMBOL(nfc_allocate_device); + +/** + * nfc_register_device - register a nfc device in the nfc subsystem + * + * @dev: The nfc device to register + */ +int nfc_register_device(struct nfc_dev *dev) +{ + int rc; + + nfc_dbg("dev_name=%s", dev_name(&dev->dev)); + + mutex_lock(&nfc_devlist_mutex); + nfc_devlist_generation++; + rc = device_add(&dev->dev); + mutex_unlock(&nfc_devlist_mutex); + + if (rc < 0) + return rc; + + rc = nfc_genl_device_added(dev); + if (rc) + nfc_dbg("The userspace won't be notified that the device %s was" + " added", dev_name(&dev->dev)); + + + return 0; +} +EXPORT_SYMBOL(nfc_register_device); + +/** + * nfc_unregister_device - unregister a nfc device in the nfc subsystem + * + * @dev: The nfc device to unregister + */ +void nfc_unregister_device(struct nfc_dev *dev) +{ + int rc; + + nfc_dbg("dev_name=%s", dev_name(&dev->dev)); + + mutex_lock(&nfc_devlist_mutex); + nfc_devlist_generation++; + + /* lock to avoid unregistering a device while an operation + is in progress */ + device_lock(&dev->dev); + device_del(&dev->dev); + device_unlock(&dev->dev); + + mutex_unlock(&nfc_devlist_mutex); + + rc = nfc_genl_device_removed(dev); + if (rc) + nfc_dbg("The userspace won't be notified that the device %s" + " was removed", dev_name(&dev->dev)); + +} +EXPORT_SYMBOL(nfc_unregister_device); + +static int __init nfc_init(void) +{ + int rc; + + nfc_info("NFC Core ver %s", VERSION); + + rc = class_register(&nfc_class); + if (rc) + return rc; + + rc = nfc_genl_init(); + if (rc) + goto err_genl; + + /* the first generation must not be 0 */ + nfc_devlist_generation = 1; + + rc = rawsock_init(); + if (rc) + goto err_rawsock; + + rc = af_nfc_init(); + if (rc) + goto err_af_nfc; + + return 0; + +err_af_nfc: + rawsock_exit(); +err_rawsock: + nfc_genl_exit(); +err_genl: + class_unregister(&nfc_class); + return rc; +} + +static void __exit nfc_exit(void) +{ + af_nfc_exit(); + rawsock_exit(); + nfc_genl_exit(); + class_unregister(&nfc_class); +} + +subsys_initcall(nfc_init); +module_exit(nfc_exit); + +MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>"); +MODULE_DESCRIPTION("NFC Core ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c new file mode 100644 index 000000000000..ccdff7953f7d --- /dev/null +++ b/net/nfc/netlink.c @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * + * Authors: + * Lauro Ramos Venancio <lauro.venancio@openbossa.org> + * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <net/genetlink.h> +#include <linux/nfc.h> +#include <linux/slab.h> + +#include "nfc.h" + +static struct genl_multicast_group nfc_genl_event_mcgrp = { + .name = NFC_GENL_MCAST_EVENT_NAME, +}; + +struct genl_family nfc_genl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = NFC_GENL_NAME, + .version = NFC_GENL_VERSION, + .maxattr = NFC_ATTR_MAX, +}; + +static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { + [NFC_ATTR_DEVICE_INDEX] = { .type = NLA_U32 }, + [NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING, + .len = NFC_DEVICE_NAME_MAXSIZE }, + [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 }, +}; + +static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, + struct netlink_callback *cb, int flags) +{ + void *hdr; + + nfc_dbg("entry"); + + hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, + &nfc_genl_family, flags, NFC_CMD_GET_TARGET); + if (!hdr) + return -EMSGSIZE; + + genl_dump_check_consistent(cb, hdr, &nfc_genl_family); + + NLA_PUT_U32(msg, NFC_ATTR_TARGET_INDEX, target->idx); + NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, + target->supported_protocols); + NLA_PUT_U16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res); + NLA_PUT_U8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res); + + return genlmsg_end(msg, hdr); + +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb) +{ + struct nfc_dev *dev; + int rc; + u32 idx; + + rc = nlmsg_parse(cb->nlh, GENL_HDRLEN + nfc_genl_family.hdrsize, + nfc_genl_family.attrbuf, + nfc_genl_family.maxattr, + nfc_genl_policy); + if (rc < 0) + return ERR_PTR(rc); + + if (!nfc_genl_family.attrbuf[NFC_ATTR_DEVICE_INDEX]) + return ERR_PTR(-EINVAL); + + idx = nla_get_u32(nfc_genl_family.attrbuf[NFC_ATTR_DEVICE_INDEX]); + + dev = nfc_get_device(idx); + if (!dev) + return ERR_PTR(-ENODEV); + + return dev; +} + +static int nfc_genl_dump_targets(struct sk_buff *skb, + struct netlink_callback *cb) +{ + int i = cb->args[0]; + struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; + int rc; + + nfc_dbg("entry"); + + if (!dev) { + dev = __get_device_from_cb(cb); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + cb->args[1] = (long) dev; + } + + spin_lock_bh(&dev->targets_lock); + + cb->seq = dev->targets_generation; + + while (i < dev->n_targets) { + rc = nfc_genl_send_target(skb, &dev->targets[i], cb, + NLM_F_MULTI); + if (rc < 0) + break; + + i++; + } + + spin_unlock_bh(&dev->targets_lock); + + cb->args[0] = i; + + return skb->len; +} + +static int nfc_genl_dump_targets_done(struct netlink_callback *cb) +{ + struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; + + nfc_dbg("entry"); + + if (dev) + nfc_put_device(dev); + + return 0; +} + +int nfc_genl_targets_found(struct nfc_dev *dev) +{ + struct sk_buff *msg; + void *hdr; + + nfc_dbg("entry"); + + dev->genl_data.poll_req_pid = 0; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + if (!msg) + return -ENOMEM; + + hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, + NFC_EVENT_TARGETS_FOUND); + if (!hdr) + goto free_msg; + + NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx); + + genlmsg_end(msg, hdr); + + return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); + +nla_put_failure: + genlmsg_cancel(msg, hdr); +free_msg: + nlmsg_free(msg); + return -EMSGSIZE; +} + +int nfc_genl_device_added(struct nfc_dev *dev) +{ + struct sk_buff *msg; + void *hdr; + + nfc_dbg("entry"); + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, + NFC_EVENT_DEVICE_ADDED); + if (!hdr) + goto free_msg; + + NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)); + NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx); + NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols); + + genlmsg_end(msg, hdr); + + genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + + return 0; + +nla_put_failure: + genlmsg_cancel(msg, hdr); +free_msg: + nlmsg_free(msg); + return -EMSGSIZE; +} + +int nfc_genl_device_removed(struct nfc_dev *dev) +{ + struct sk_buff *msg; + void *hdr; + + nfc_dbg("entry"); + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, + NFC_EVENT_DEVICE_REMOVED); + if (!hdr) + goto free_msg; + + NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx); + + genlmsg_end(msg, hdr); + + genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + + return 0; + +nla_put_failure: + genlmsg_cancel(msg, hdr); +free_msg: + nlmsg_free(msg); + return -EMSGSIZE; +} + +static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, + u32 pid, u32 seq, + struct netlink_callback *cb, + int flags) +{ + void *hdr; + + nfc_dbg("entry"); + + hdr = genlmsg_put(msg, pid, seq, &nfc_genl_family, flags, + NFC_CMD_GET_DEVICE); + if (!hdr) + return -EMSGSIZE; + + if (cb) + genl_dump_check_consistent(cb, hdr, &nfc_genl_family); + + NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)); + NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx); + NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols); + + return genlmsg_end(msg, hdr); + +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int nfc_genl_dump_devices(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0]; + struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; + bool first_call = false; + + nfc_dbg("entry"); + + if (!iter) { + first_call = true; + iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL); + if (!iter) + return -ENOMEM; + cb->args[0] = (long) iter; + } + + mutex_lock(&nfc_devlist_mutex); + + cb->seq = nfc_devlist_generation; + + if (first_call) { + nfc_device_iter_init(iter); + dev = nfc_device_iter_next(iter); + } + + while (dev) { + int rc; + + rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + cb, NLM_F_MULTI); + if (rc < 0) + break; + + dev = nfc_device_iter_next(iter); + } + + mutex_unlock(&nfc_devlist_mutex); + + cb->args[1] = (long) dev; + + return skb->len; +} + +static int nfc_genl_dump_devices_done(struct netlink_callback *cb) +{ + struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0]; + + nfc_dbg("entry"); + + nfc_device_iter_exit(iter); + kfree(iter); + + return 0; +} + +static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + struct nfc_dev *dev; + u32 idx; + int rc = -ENOBUFS; + + nfc_dbg("entry"); + + if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) + return -EINVAL; + + idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); + + dev = nfc_get_device(idx); + if (!dev) + return -ENODEV; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) { + rc = -ENOMEM; + goto out_putdev; + } + + rc = nfc_genl_send_device(msg, dev, info->snd_pid, info->snd_seq, + NULL, 0); + if (rc < 0) + goto out_free; + + nfc_put_device(dev); + + return genlmsg_reply(msg, info); + +out_free: + nlmsg_free(msg); +out_putdev: + nfc_put_device(dev); + return rc; +} + +static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info) +{ + struct nfc_dev *dev; + int rc; + u32 idx; + u32 protocols; + + nfc_dbg("entry"); + + if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || + !info->attrs[NFC_ATTR_PROTOCOLS]) + return -EINVAL; + + idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); + protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]); + + dev = nfc_get_device(idx); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->genl_data.genl_data_mutex); + + rc = nfc_start_poll(dev, protocols); + if (!rc) + dev->genl_data.poll_req_pid = info->snd_pid; + + mutex_unlock(&dev->genl_data.genl_data_mutex); + + nfc_put_device(dev); + return rc; +} + +static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info) +{ + struct nfc_dev *dev; + int rc; + u32 idx; + + nfc_dbg("entry"); + + if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) + return -EINVAL; + + idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); + + dev = nfc_get_device(idx); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->genl_data.genl_data_mutex); + + if (dev->genl_data.poll_req_pid != info->snd_pid) { + rc = -EBUSY; + goto out; + } + + rc = nfc_stop_poll(dev); + dev->genl_data.poll_req_pid = 0; + +out: + mutex_unlock(&dev->genl_data.genl_data_mutex); + nfc_put_device(dev); + return rc; +} + +static struct genl_ops nfc_genl_ops[] = { + { + .cmd = NFC_CMD_GET_DEVICE, + .doit = nfc_genl_get_device, + .dumpit = nfc_genl_dump_devices, + .done = nfc_genl_dump_devices_done, + .policy = nfc_genl_policy, + }, + { + .cmd = NFC_CMD_START_POLL, + .doit = nfc_genl_start_poll, + .policy = nfc_genl_policy, + }, + { + .cmd = NFC_CMD_STOP_POLL, + .doit = nfc_genl_stop_poll, + .policy = nfc_genl_policy, + }, + { + .cmd = NFC_CMD_GET_TARGET, + .dumpit = nfc_genl_dump_targets, + .done = nfc_genl_dump_targets_done, + .policy = nfc_genl_policy, + }, +}; + +static int nfc_genl_rcv_nl_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct netlink_notify *n = ptr; + struct class_dev_iter iter; + struct nfc_dev *dev; + + if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC) + goto out; + + nfc_dbg("NETLINK_URELEASE event from id %d", n->pid); + + nfc_device_iter_init(&iter); + dev = nfc_device_iter_next(&iter); + + while (dev) { + mutex_lock(&dev->genl_data.genl_data_mutex); + if (dev->genl_data.poll_req_pid == n->pid) { + nfc_stop_poll(dev); + dev->genl_data.poll_req_pid = 0; + } + mutex_unlock(&dev->genl_data.genl_data_mutex); + dev = nfc_device_iter_next(&iter); + } + + nfc_device_iter_exit(&iter); + +out: + return NOTIFY_DONE; +} + +void nfc_genl_data_init(struct nfc_genl_data *genl_data) +{ + genl_data->poll_req_pid = 0; + mutex_init(&genl_data->genl_data_mutex); +} + +void nfc_genl_data_exit(struct nfc_genl_data *genl_data) +{ + mutex_destroy(&genl_data->genl_data_mutex); +} + +static struct notifier_block nl_notifier = { + .notifier_call = nfc_genl_rcv_nl_event, +}; + +/** + * nfc_genl_init() - Initialize netlink interface + * + * This initialization function registers the nfc netlink family. + */ +int __init nfc_genl_init(void) +{ + int rc; + + rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops, + ARRAY_SIZE(nfc_genl_ops)); + if (rc) + return rc; + + rc = genl_register_mc_group(&nfc_genl_family, &nfc_genl_event_mcgrp); + + netlink_register_notifier(&nl_notifier); + + return rc; +} + +/** + * nfc_genl_exit() - Deinitialize netlink interface + * + * This exit function unregisters the nfc netlink family. + */ +void nfc_genl_exit(void) +{ + netlink_unregister_notifier(&nl_notifier); + genl_unregister_family(&nfc_genl_family); +} diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h new file mode 100644 index 000000000000..aaf9832298f3 --- /dev/null +++ b/net/nfc/nfc.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * + * Authors: + * Lauro Ramos Venancio <lauro.venancio@openbossa.org> + * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LOCAL_NFC_H +#define __LOCAL_NFC_H + +#include <net/nfc.h> +#include <net/sock.h> + +__attribute__((format (printf, 2, 3))) +int nfc_printk(const char *level, const char *fmt, ...); + +#define nfc_info(fmt, arg...) nfc_printk(KERN_INFO, fmt, ##arg) +#define nfc_err(fmt, arg...) nfc_printk(KERN_ERR, fmt, ##arg) +#define nfc_dbg(fmt, arg...) pr_debug(fmt "\n", ##arg) + +struct nfc_protocol { + int id; + struct proto *proto; + struct module *owner; + int (*create)(struct net *net, struct socket *sock, + const struct nfc_protocol *nfc_proto); +}; + +struct nfc_rawsock { + struct sock sk; + struct nfc_dev *dev; + u32 target_idx; + struct work_struct tx_work; + bool tx_work_scheduled; +}; +#define nfc_rawsock(sk) ((struct nfc_rawsock *) sk) +#define to_rawsock_sk(_tx_work) \ + ((struct sock *) container_of(_tx_work, struct nfc_rawsock, tx_work)) + +int __init rawsock_init(void); +void rawsock_exit(void); + +int __init af_nfc_init(void); +void af_nfc_exit(void); +int nfc_proto_register(const struct nfc_protocol *nfc_proto); +void nfc_proto_unregister(const struct nfc_protocol *nfc_proto); + +extern int nfc_devlist_generation; +extern struct mutex nfc_devlist_mutex; + +int __init nfc_genl_init(void); +void nfc_genl_exit(void); + +void nfc_genl_data_init(struct nfc_genl_data *genl_data); +void nfc_genl_data_exit(struct nfc_genl_data *genl_data); + +int nfc_genl_targets_found(struct nfc_dev *dev); + +int nfc_genl_device_added(struct nfc_dev *dev); +int nfc_genl_device_removed(struct nfc_dev *dev); + +struct nfc_dev *nfc_get_device(unsigned idx); + +static inline void nfc_put_device(struct nfc_dev *dev) +{ + put_device(&dev->dev); +} + +static inline void nfc_device_iter_init(struct class_dev_iter *iter) +{ + class_dev_iter_init(iter, &nfc_class, NULL, NULL); +} + +static inline struct nfc_dev *nfc_device_iter_next(struct class_dev_iter *iter) +{ + struct device *d = class_dev_iter_next(iter); + if (!d) + return NULL; + + return to_nfc_dev(d); +} + +static inline void nfc_device_iter_exit(struct class_dev_iter *iter) +{ + class_dev_iter_exit(iter); +} + +int nfc_start_poll(struct nfc_dev *dev, u32 protocols); + +int nfc_stop_poll(struct nfc_dev *dev); + +int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol); + +int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx); + +int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, + struct sk_buff *skb, + data_exchange_cb_t cb, + void *cb_context); + +#endif /* __LOCAL_NFC_H */ diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c new file mode 100644 index 000000000000..52de84a55115 --- /dev/null +++ b/net/nfc/rawsock.c @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * + * Authors: + * Aloisio Almeida Jr <aloisio.almeida@openbossa.org> + * Lauro Ramos Venancio <lauro.venancio@openbossa.org> + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <net/tcp_states.h> +#include <linux/nfc.h> + +#include "nfc.h" + +static void rawsock_write_queue_purge(struct sock *sk) +{ + nfc_dbg("sk=%p", sk); + + spin_lock_bh(&sk->sk_write_queue.lock); + __skb_queue_purge(&sk->sk_write_queue); + nfc_rawsock(sk)->tx_work_scheduled = false; + spin_unlock_bh(&sk->sk_write_queue.lock); +} + +static void rawsock_report_error(struct sock *sk, int err) +{ + nfc_dbg("sk=%p err=%d", sk, err); + + sk->sk_shutdown = SHUTDOWN_MASK; + sk->sk_err = -err; + sk->sk_error_report(sk); + + rawsock_write_queue_purge(sk); +} + +static int rawsock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + + nfc_dbg("sock=%p", sock); + + sock_orphan(sk); + sock_put(sk); + + return 0; +} + +static int rawsock_connect(struct socket *sock, struct sockaddr *_addr, + int len, int flags) +{ + struct sock *sk = sock->sk; + struct sockaddr_nfc *addr = (struct sockaddr_nfc *)_addr; + struct nfc_dev *dev; + int rc = 0; + + nfc_dbg("sock=%p sk=%p flags=%d", sock, sk, flags); + + if (!addr || len < sizeof(struct sockaddr_nfc) || + addr->sa_family != AF_NFC) + return -EINVAL; + + nfc_dbg("addr dev_idx=%u target_idx=%u protocol=%u", addr->dev_idx, + addr->target_idx, addr->nfc_protocol); + + lock_sock(sk); + + if (sock->state == SS_CONNECTED) { + rc = -EISCONN; + goto error; + } + + dev = nfc_get_device(addr->dev_idx); + if (!dev) { + rc = -ENODEV; + goto error; + } + + if (addr->target_idx > dev->target_idx - 1 || + addr->target_idx < dev->target_idx - dev->n_targets) { + rc = -EINVAL; + goto error; + } + + if (addr->target_idx > dev->target_idx - 1 || + addr->target_idx < dev->target_idx - dev->n_targets) { + rc = -EINVAL; + goto error; + } + + rc = nfc_activate_target(dev, addr->target_idx, addr->nfc_protocol); + if (rc) + goto put_dev; + + nfc_rawsock(sk)->dev = dev; + nfc_rawsock(sk)->target_idx = addr->target_idx; + sock->state = SS_CONNECTED; + sk->sk_state = TCP_ESTABLISHED; + sk->sk_state_change(sk); + + release_sock(sk); + return 0; + +put_dev: + nfc_put_device(dev); +error: + release_sock(sk); + return rc; +} + +static int rawsock_add_header(struct sk_buff *skb) +{ + + if (skb_cow_head(skb, 1)) + return -ENOMEM; + + *skb_push(skb, 1) = 0; + + return 0; +} + +static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb, + int err) +{ + struct sock *sk = (struct sock *) context; + + BUG_ON(in_irq()); + + nfc_dbg("sk=%p err=%d", sk, err); + + if (err) + goto error; + + err = rawsock_add_header(skb); + if (err) + goto error; + + err = sock_queue_rcv_skb(sk, skb); + if (err) + goto error; + + spin_lock_bh(&sk->sk_write_queue.lock); + if (!skb_queue_empty(&sk->sk_write_queue)) + schedule_work(&nfc_rawsock(sk)->tx_work); + else + nfc_rawsock(sk)->tx_work_scheduled = false; + spin_unlock_bh(&sk->sk_write_queue.lock); + + sock_put(sk); + return; + +error: + rawsock_report_error(sk, err); + sock_put(sk); +} + +static void rawsock_tx_work(struct work_struct *work) +{ + struct sock *sk = to_rawsock_sk(work); + struct nfc_dev *dev = nfc_rawsock(sk)->dev; + u32 target_idx = nfc_rawsock(sk)->target_idx; + struct sk_buff *skb; + int rc; + + nfc_dbg("sk=%p target_idx=%u", sk, target_idx); + + if (sk->sk_shutdown & SEND_SHUTDOWN) { + rawsock_write_queue_purge(sk); + return; + } + + skb = skb_dequeue(&sk->sk_write_queue); + + sock_hold(sk); + rc = nfc_data_exchange(dev, target_idx, skb, + rawsock_data_exchange_complete, sk); + if (rc) { + rawsock_report_error(sk, rc); + sock_put(sk); + } +} + +static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len) +{ + struct sock *sk = sock->sk; + struct sk_buff *skb; + int rc; + + nfc_dbg("sock=%p sk=%p len=%zu", sock, sk, len); + + if (msg->msg_namelen) + return -EOPNOTSUPP; + + if (sock->state != SS_CONNECTED) + return -ENOTCONN; + + skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT, + &rc); + if (!skb) + return rc; + + rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); + if (rc < 0) { + kfree_skb(skb); + return rc; + } + + spin_lock_bh(&sk->sk_write_queue.lock); + __skb_queue_tail(&sk->sk_write_queue, skb); + if (!nfc_rawsock(sk)->tx_work_scheduled) { + schedule_work(&nfc_rawsock(sk)->tx_work); + nfc_rawsock(sk)->tx_work_scheduled = true; + } + spin_unlock_bh(&sk->sk_write_queue.lock); + + return len; +} + +static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len, int flags) +{ + int noblock = flags & MSG_DONTWAIT; + struct sock *sk = sock->sk; + struct sk_buff *skb; + int copied; + int rc; + + nfc_dbg("sock=%p sk=%p len=%zu flags=%d", sock, sk, len, flags); + + skb = skb_recv_datagram(sk, flags, noblock, &rc); + if (!skb) + return rc; + + msg->msg_namelen = 0; + + copied = skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + + rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + + skb_free_datagram(sk, skb); + + return rc ? : copied; +} + + +static const struct proto_ops rawsock_ops = { + .family = PF_NFC, + .owner = THIS_MODULE, + .release = rawsock_release, + .bind = sock_no_bind, + .connect = rawsock_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = sock_no_getname, + .poll = datagram_poll, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .sendmsg = rawsock_sendmsg, + .recvmsg = rawsock_recvmsg, + .mmap = sock_no_mmap, +}; + +static void rawsock_destruct(struct sock *sk) +{ + nfc_dbg("sk=%p", sk); + + if (sk->sk_state == TCP_ESTABLISHED) { + nfc_deactivate_target(nfc_rawsock(sk)->dev, + nfc_rawsock(sk)->target_idx); + nfc_put_device(nfc_rawsock(sk)->dev); + } + + skb_queue_purge(&sk->sk_receive_queue); + + if (!sock_flag(sk, SOCK_DEAD)) { + nfc_err("Freeing alive NFC raw socket %p", sk); + return; + } +} + +static int rawsock_create(struct net *net, struct socket *sock, + const struct nfc_protocol *nfc_proto) +{ + struct sock *sk; + + nfc_dbg("sock=%p", sock); + + if (sock->type != SOCK_SEQPACKET) + return -ESOCKTNOSUPPORT; + + sock->ops = &rawsock_ops; + + sk = sk_alloc(net, PF_NFC, GFP_KERNEL, nfc_proto->proto); + if (!sk) + return -ENOMEM; + + sock_init_data(sock, sk); + sk->sk_protocol = nfc_proto->id; + sk->sk_destruct = rawsock_destruct; + sock->state = SS_UNCONNECTED; + + INIT_WORK(&nfc_rawsock(sk)->tx_work, rawsock_tx_work); + nfc_rawsock(sk)->tx_work_scheduled = false; + + return 0; +} + +static struct proto rawsock_proto = { + .name = "NFC_RAW", + .owner = THIS_MODULE, + .obj_size = sizeof(struct nfc_rawsock), +}; + +static const struct nfc_protocol rawsock_nfc_proto = { + .id = NFC_SOCKPROTO_RAW, + .proto = &rawsock_proto, + .owner = THIS_MODULE, + .create = rawsock_create +}; + +int __init rawsock_init(void) +{ + int rc; + + rc = nfc_proto_register(&rawsock_nfc_proto); + + return rc; +} + +void rawsock_exit(void) +{ + nfc_proto_unregister(&rawsock_nfc_proto); +} diff --git a/net/wireless/core.c b/net/wireless/core.c index c22ef3492ee6..880dbe2e6f94 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -366,6 +366,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); + mutex_init(&rdev->sched_scan_mtx); INIT_LIST_HEAD(&rdev->netdev_list); spin_lock_init(&rdev->bss_lock); INIT_LIST_HEAD(&rdev->bss_list); @@ -701,6 +702,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) rfkill_destroy(rdev->rfkill); mutex_destroy(&rdev->mtx); mutex_destroy(&rdev->devlist_mtx); + mutex_destroy(&rdev->sched_scan_mtx); list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) cfg80211_put_bss(&scan->pub); cfg80211_rdev_free_wowlan(rdev); @@ -737,12 +739,16 @@ static void wdev_cleanup_work(struct work_struct *work) ___cfg80211_scan_done(rdev, true); } + cfg80211_unlock_rdev(rdev); + + mutex_lock(&rdev->sched_scan_mtx); + if (WARN_ON(rdev->sched_scan_req && rdev->sched_scan_req->dev == wdev->netdev)) { __cfg80211_stop_sched_scan(rdev, false); } - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); mutex_lock(&rdev->devlist_mtx); rdev->opencount--; @@ -830,9 +836,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); __cfg80211_stop_sched_scan(rdev, false); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); wdev_lock(wdev); #ifdef CONFIG_CFG80211_WEXT diff --git a/net/wireless/core.h b/net/wireless/core.h index 3dce1f167eba..a570ff9214ec 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -65,6 +65,8 @@ struct cfg80211_registered_device { struct work_struct scan_done_wk; struct work_struct sched_scan_results_wk; + struct mutex sched_scan_mtx; + #ifdef CONFIG_NL80211_TESTMODE struct genl_info *testmode_info; #endif diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 3633ab6af184..832f6574e4ed 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -1084,3 +1084,14 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp); } EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); + +void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp); +} +EXPORT_SYMBOL(cfg80211_gtk_rekey_notify); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index aed6d2ad4c90..6a82c898f831 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -176,6 +176,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, + [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, }; /* policy for the key attributes */ @@ -206,6 +207,14 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, }; +/* policy for GTK rekey offload attributes */ +static const struct nla_policy +nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { + [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN }, + [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN }, + [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN }, +}; + /* ifidx get helper */ static int nl80211_get_ifidx(struct netlink_callback *cb) { @@ -3461,9 +3470,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; - if (rdev->sched_scan_req) - return -EINPROGRESS; - if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) return -EINVAL; @@ -3502,12 +3508,21 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (ie_len > wiphy->max_scan_ie_len) return -EINVAL; + mutex_lock(&rdev->sched_scan_mtx); + + if (rdev->sched_scan_req) { + err = -EINPROGRESS; + goto out; + } + request = kzalloc(sizeof(*request) + sizeof(*request->ssids) * n_ssids + sizeof(*request->channels) * n_channels + ie_len, GFP_KERNEL); - if (!request) - return -ENOMEM; + if (!request) { + err = -ENOMEM; + goto out; + } if (n_ssids) request->ssids = (void *)&request->channels[n_channels]; @@ -3605,6 +3620,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, out_free: kfree(request); out: + mutex_unlock(&rdev->sched_scan_mtx); return err; } @@ -3612,12 +3628,17 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int err; if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || !rdev->ops->sched_scan_stop) return -EOPNOTSUPP; - return __cfg80211_stop_sched_scan(rdev, false); + mutex_lock(&rdev->sched_scan_mtx); + err = __cfg80211_stop_sched_scan(rdev, false); + mutex_unlock(&rdev->sched_scan_mtx); + + return err; } static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, @@ -5408,6 +5429,57 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) return err; } +static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct nlattr *tb[NUM_NL80211_REKEY_DATA]; + struct cfg80211_gtk_rekey_data rekey_data; + int err; + + if (!info->attrs[NL80211_ATTR_REKEY_DATA]) + return -EINVAL; + + err = nla_parse(tb, MAX_NL80211_REKEY_DATA, + nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]), + nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]), + nl80211_rekey_policy); + if (err) + return err; + + if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN) + return -ERANGE; + if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN) + return -ERANGE; + if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN) + return -ERANGE; + + memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]), + NL80211_KEK_LEN); + memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]), + NL80211_KCK_LEN); + memcpy(rekey_data.replay_ctr, + nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]), + NL80211_REPLAY_CTR_LEN); + + wdev_lock(wdev); + if (!wdev->current_bss) { + err = -ENOTCONN; + goto out; + } + + if (!rdev->ops->set_rekey_data) { + err = -EOPNOTSUPP; + goto out; + } + + err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data); + out: + wdev_unlock(wdev); + return err; +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -5939,6 +6011,14 @@ static struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_WIPHY | NL80211_FLAG_NEED_RTNL, }, + { + .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, + .doit = nl80211_set_rekey_data, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { @@ -6566,7 +6646,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, if (addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); + if (key_id != -1) + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); if (tsc) NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); @@ -6882,6 +6963,51 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, nlmsg_free(msg); } +void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp) +{ + struct sk_buff *msg; + struct nlattr *rekey_attr; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + + rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA); + if (!rekey_attr) + goto nla_put_failure; + + NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, + NL80211_REPLAY_CTR_LEN, replay_ctr); + + nla_nest_end(msg, rekey_attr); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + void nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *peer, diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2f1bfb87a651..5d69c56400ae 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -109,4 +109,8 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *peer, u32 num_packets, gfp_t gfp); +void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + const u8 *replay_ctr, gfp_t gfp); + #endif /* __NET_WIRELESS_NL80211_H */ diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 7a6c67667d70..1c4672e35144 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -100,14 +100,14 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) rdev = container_of(wk, struct cfg80211_registered_device, sched_scan_results_wk); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); /* we don't have sched_scan_req anymore if the scan is stopping */ if (rdev->sched_scan_req) nl80211_send_sched_scan_results(rdev, rdev->sched_scan_req->dev); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); } void cfg80211_sched_scan_results(struct wiphy *wiphy) @@ -123,27 +123,26 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - cfg80211_lock_rdev(rdev); + mutex_lock(&rdev->sched_scan_mtx); __cfg80211_stop_sched_scan(rdev, true); - cfg80211_unlock_rdev(rdev); + mutex_unlock(&rdev->sched_scan_mtx); } EXPORT_SYMBOL(cfg80211_sched_scan_stopped); int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, bool driver_initiated) { - int err; struct net_device *dev; - ASSERT_RDEV_LOCK(rdev); + lockdep_assert_held(&rdev->sched_scan_mtx); if (!rdev->sched_scan_req) - return 0; + return -ENOENT; dev = rdev->sched_scan_req->dev; if (!driver_initiated) { - err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev); + int err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev); if (err) return err; } @@ -153,7 +152,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, kfree(rdev->sched_scan_req); rdev->sched_scan_req = NULL; - return err; + return 0; } static void bss_release(struct kref *ref) |