Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,17 @@
# SPDX-License-Identifier: GPL-2.0-only
config WLAN_VENDOR_RALINK
bool "Ralink devices"
default y
help
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_RALINK
source "drivers/net/wireless/ralink/rt2x00/Kconfig"
endif # WLAN_VENDOR_RALINK
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_RT2X00) += rt2x00/
@@ -0,0 +1,265 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig RT2X00
tristate "Ralink driver support"
depends on MAC80211 && HAS_DMA
help
This will enable the support for the Ralink drivers,
developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
These drivers make use of the mac80211 stack.
When building one of the individual drivers, the rt2x00 library
will also be created. That library (when the driver is built as
a module) will be called rt2x00lib.
Additionally PCI and USB libraries will also be build depending
on the types of drivers being selected, these libraries will be
called rt2x00pci and rt2x00usb.
if RT2X00
config RT2400PCI
tristate "Ralink rt2400 (PCI/PCMCIA) support"
depends on PCI
select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI
select EEPROM_93CX6
help
This adds support for rt2400 wireless chipset family.
Supported chips: RT2460.
When compiled as a module, this driver will be called rt2400pci.
config RT2500PCI
tristate "Ralink rt2500 (PCI/PCMCIA) support"
depends on PCI
select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI
select EEPROM_93CX6
help
This adds support for rt2500 wireless chipset family.
Supported chips: RT2560.
When compiled as a module, this driver will be called rt2500pci.
config RT61PCI
tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"
depends on PCI
select RT2X00_LIB_PCI
select RT2X00_LIB_MMIO
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_ITU_T
select EEPROM_93CX6
help
This adds support for rt2501 wireless chipset family.
Supported chips: RT2561, RT2561S & RT2661.
When compiled as a module, this driver will be called rt61pci.
config RT2800PCI
tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support"
depends on PCI
select RT2800_LIB
select RT2800_LIB_MMIO
select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select EEPROM_93CX6
help
This adds support for rt27xx/rt28xx/rt30xx wireless chipset family.
Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890, RT3052,
RT3090, RT3091 & RT3092
When compiled as a module, this driver will be called "rt2800pci.ko".
if RT2800PCI
config RT2800PCI_RT33XX
bool "rt2800pci - Include support for rt33xx devices"
default y
help
This adds support for rt33xx wireless chipset family to the
rt2800pci driver.
Supported chips: RT3390
config RT2800PCI_RT35XX
bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)"
default y
help
This adds support for rt35xx wireless chipset family to the
rt2800pci driver.
Supported chips: RT3060, RT3062, RT3562, RT3592
config RT2800PCI_RT53XX
bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)"
default y
help
This adds support for rt53xx wireless chipset family to the
rt2800pci driver.
Supported chips: RT5390
config RT2800PCI_RT3290
bool "rt2800pci - Include support for rt3290 devices (EXPERIMENTAL)"
default y
help
This adds support for rt3290 wireless chipset family to the
rt2800pci driver.
Supported chips: RT3290
endif
config RT2500USB
tristate "Ralink rt2500 (USB) support"
depends on USB
select RT2X00_LIB_USB
select RT2X00_LIB_CRYPTO
help
This adds support for rt2500 wireless chipset family.
Supported chips: RT2571 & RT2572.
When compiled as a module, this driver will be called rt2500usb.
config RT73USB
tristate "Ralink rt2501/rt73 (USB) support"
depends on USB
select RT2X00_LIB_USB
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_ITU_T
help
This adds support for rt2501 wireless chipset family.
Supported chips: RT2571W, RT2573 & RT2671.
When compiled as a module, this driver will be called rt73usb.
config RT2800USB
tristate "Ralink rt27xx/rt28xx/rt30xx (USB) support"
depends on USB
select RT2800_LIB
select RT2X00_LIB_USB
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
help
This adds support for rt27xx/rt28xx/rt30xx wireless chipset family.
Supported chips: RT2770, RT2870 & RT3070, RT3071 & RT3072
When compiled as a module, this driver will be called "rt2800usb.ko".
if RT2800USB
config RT2800USB_RT33XX
bool "rt2800usb - Include support for rt33xx devices"
default y
help
This adds support for rt33xx wireless chipset family to the
rt2800usb driver.
Supported chips: RT3370
config RT2800USB_RT35XX
bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)"
default y
help
This adds support for rt35xx wireless chipset family to the
rt2800usb driver.
Supported chips: RT3572
config RT2800USB_RT3573
bool "rt2800usb - Include support for rt3573 devices (EXPERIMENTAL)"
help
This enables support for RT3573 chipset based USB wireless devices
in the rt2800usb driver.
config RT2800USB_RT53XX
bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)"
help
This adds support for rt53xx wireless chipset family to the
rt2800usb driver.
Supported chips: RT5370
config RT2800USB_RT55XX
bool "rt2800usb - Include support for rt55xx devices (EXPERIMENTAL)"
help
This adds support for rt55xx wireless chipset family to the
rt2800usb driver.
Supported chips: RT5572
config RT2800USB_UNKNOWN
bool "rt2800usb - Include support for unknown (USB) devices"
default n
help
This adds support for rt2800usb devices that are known to
have a rt28xx family compatible chipset, but for which the exact
chipset is unknown.
Support status for these devices is unknown, and enabling these
devices may or may not work.
endif
config RT2800SOC
tristate "Ralink WiSoC support"
depends on OF && (SOC_RT288X || SOC_RT305X || SOC_MT7620 || COMPILE_TEST)
select RT2X00_LIB_MMIO
select RT2X00_LIB_CRYPTO
select RT2X00_LIB_FIRMWARE
select RT2800_LIB
select RT2800_LIB_MMIO
help
This adds support for Ralink WiSoC devices.
Supported chips: RT2880, RT3050, RT3052, RT3350, RT3352.
When compiled as a module, this driver will be called rt2800soc.
config RT2800_LIB
tristate
select CRC_CCITT
config RT2800_LIB_MMIO
tristate
select RT2X00_LIB_MMIO
select RT2800_LIB
config RT2X00_LIB_MMIO
tristate
select RT2X00_LIB
config RT2X00_LIB_PCI
tristate
select RT2X00_LIB
config RT2X00_LIB_USB
tristate
select RT2X00_LIB
config RT2X00_LIB
tristate
config RT2X00_LIB_FIRMWARE
bool
select FW_LOADER
config RT2X00_LIB_CRYPTO
bool
config RT2X00_LIB_LEDS
bool
default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
config RT2X00_LIB_DEBUGFS
bool "Ralink debugfs support"
depends on RT2X00_LIB && MAC80211_DEBUGFS
help
Enable creation of debugfs files for the rt2x00 drivers.
These debugfs files support both reading and writing of the
most important register types of the rt2x00 hardware.
config RT2X00_DEBUG
bool "Ralink debug output"
depends on RT2X00_LIB
help
Enable debugging output for all rt2x00 modules
endif
@@ -0,0 +1,25 @@
# SPDX-License-Identifier: GPL-2.0
rt2x00lib-y += rt2x00dev.o
rt2x00lib-y += rt2x00mac.o
rt2x00lib-y += rt2x00config.o
rt2x00lib-y += rt2x00queue.o
rt2x00lib-y += rt2x00link.o
rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
obj-$(CONFIG_RT2X00_LIB_MMIO) += rt2x00mmio.o
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
obj-$(CONFIG_RT2800_LIB) += rt2800lib.o
obj-$(CONFIG_RT2800_LIB_MMIO) += rt2800mmio.o
obj-$(CONFIG_RT2400PCI) += rt2400pci.o
obj-$(CONFIG_RT2500PCI) += rt2500pci.o
obj-$(CONFIG_RT61PCI) += rt61pci.o
obj-$(CONFIG_RT2800PCI) += rt2800pci.o
obj-$(CONFIG_RT2500USB) += rt2500usb.o
obj-$(CONFIG_RT73USB) += rt73usb.o
obj-$(CONFIG_RT2800USB) += rt2800usb.o
obj-$(CONFIG_RT2800SOC) += rt2800soc.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,950 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2400pci
Abstract: Data structures and registers for the rt2400pci module.
Supported chipsets: RT2460.
*/
#ifndef RT2400PCI_H
#define RT2400PCI_H
/*
* RF chip defines.
*/
#define RF2420 0x0000
#define RF2421 0x0001
/*
* Signal information.
* Default offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 100
/*
* Register layout information.
*/
#define CSR_REG_BASE 0x0000
#define CSR_REG_SIZE 0x014c
#define EEPROM_BASE 0x0000
#define EEPROM_SIZE 0x0100
#define BBP_BASE 0x0000
#define BBP_SIZE 0x0020
#define RF_BASE 0x0004
#define RF_SIZE 0x000c
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/*
* Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* CSR0: ASIC revision number.
*/
#define CSR0 0x0000
#define CSR0_REVISION FIELD32(0x0000ffff)
/*
* CSR1: System control register.
* SOFT_RESET: Software reset, 1: reset, 0: normal.
* BBP_RESET: Hardware reset, 1: reset, 0, release.
* HOST_READY: Host ready after initialization.
*/
#define CSR1 0x0004
#define CSR1_SOFT_RESET FIELD32(0x00000001)
#define CSR1_BBP_RESET FIELD32(0x00000002)
#define CSR1_HOST_READY FIELD32(0x00000004)
/*
* CSR2: System admin status register (invalid).
*/
#define CSR2 0x0008
/*
* CSR3: STA MAC address register 0.
*/
#define CSR3 0x000c
#define CSR3_BYTE0 FIELD32(0x000000ff)
#define CSR3_BYTE1 FIELD32(0x0000ff00)
#define CSR3_BYTE2 FIELD32(0x00ff0000)
#define CSR3_BYTE3 FIELD32(0xff000000)
/*
* CSR4: STA MAC address register 1.
*/
#define CSR4 0x0010
#define CSR4_BYTE4 FIELD32(0x000000ff)
#define CSR4_BYTE5 FIELD32(0x0000ff00)
/*
* CSR5: BSSID register 0.
*/
#define CSR5 0x0014
#define CSR5_BYTE0 FIELD32(0x000000ff)
#define CSR5_BYTE1 FIELD32(0x0000ff00)
#define CSR5_BYTE2 FIELD32(0x00ff0000)
#define CSR5_BYTE3 FIELD32(0xff000000)
/*
* CSR6: BSSID register 1.
*/
#define CSR6 0x0018
#define CSR6_BYTE4 FIELD32(0x000000ff)
#define CSR6_BYTE5 FIELD32(0x0000ff00)
/*
* CSR7: Interrupt source register.
* Write 1 to clear interrupt.
* TBCN_EXPIRE: Beacon timer expired interrupt.
* TWAKE_EXPIRE: Wakeup timer expired interrupt.
* TATIMW_EXPIRE: Timer of atim window expired interrupt.
* TXDONE_TXRING: Tx ring transmit done interrupt.
* TXDONE_ATIMRING: Atim ring transmit done interrupt.
* TXDONE_PRIORING: Priority ring transmit done interrupt.
* RXDONE: Receive done interrupt.
*/
#define CSR7 0x001c
#define CSR7_TBCN_EXPIRE FIELD32(0x00000001)
#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002)
#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004)
#define CSR7_TXDONE_TXRING FIELD32(0x00000008)
#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010)
#define CSR7_TXDONE_PRIORING FIELD32(0x00000020)
#define CSR7_RXDONE FIELD32(0x00000040)
/*
* CSR8: Interrupt mask register.
* Write 1 to mask interrupt.
* TBCN_EXPIRE: Beacon timer expired interrupt.
* TWAKE_EXPIRE: Wakeup timer expired interrupt.
* TATIMW_EXPIRE: Timer of atim window expired interrupt.
* TXDONE_TXRING: Tx ring transmit done interrupt.
* TXDONE_ATIMRING: Atim ring transmit done interrupt.
* TXDONE_PRIORING: Priority ring transmit done interrupt.
* RXDONE: Receive done interrupt.
*/
#define CSR8 0x0020
#define CSR8_TBCN_EXPIRE FIELD32(0x00000001)
#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002)
#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004)
#define CSR8_TXDONE_TXRING FIELD32(0x00000008)
#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010)
#define CSR8_TXDONE_PRIORING FIELD32(0x00000020)
#define CSR8_RXDONE FIELD32(0x00000040)
/*
* CSR9: Maximum frame length register.
* MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12.
*/
#define CSR9 0x0024
#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80)
/*
* CSR11: Back-off control register.
* CWMIN: CWmin. Default cwmin is 31 (2^5 - 1).
* CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1).
* SLOT_TIME: Slot time, default is 20us for 802.11b.
* LONG_RETRY: Long retry count.
* SHORT_RETRY: Short retry count.
*/
#define CSR11 0x002c
#define CSR11_CWMIN FIELD32(0x0000000f)
#define CSR11_CWMAX FIELD32(0x000000f0)
#define CSR11_SLOT_TIME FIELD32(0x00001f00)
#define CSR11_LONG_RETRY FIELD32(0x00ff0000)
#define CSR11_SHORT_RETRY FIELD32(0xff000000)
/*
* CSR12: Synchronization configuration register 0.
* All units in 1/16 TU.
* BEACON_INTERVAL: Beacon interval, default is 100 TU.
* CFPMAX_DURATION: Cfp maximum duration, default is 100 TU.
*/
#define CSR12 0x0030
#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff)
#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000)
/*
* CSR13: Synchronization configuration register 1.
* All units in 1/16 TU.
* ATIMW_DURATION: Atim window duration.
* CFP_PERIOD: Cfp period, default is 0 TU.
*/
#define CSR13 0x0034
#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff)
#define CSR13_CFP_PERIOD FIELD32(0x00ff0000)
/*
* CSR14: Synchronization control register.
* TSF_COUNT: Enable tsf auto counting.
* TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
* TBCN: Enable tbcn with reload value.
* TCFP: Enable tcfp & cfp / cp switching.
* TATIMW: Enable tatimw & atim window switching.
* BEACON_GEN: Enable beacon generator.
* CFP_COUNT_PRELOAD: Cfp count preload value.
* TBCM_PRELOAD: Tbcn preload value in units of 64us.
*/
#define CSR14 0x0038
#define CSR14_TSF_COUNT FIELD32(0x00000001)
#define CSR14_TSF_SYNC FIELD32(0x00000006)
#define CSR14_TBCN FIELD32(0x00000008)
#define CSR14_TCFP FIELD32(0x00000010)
#define CSR14_TATIMW FIELD32(0x00000020)
#define CSR14_BEACON_GEN FIELD32(0x00000040)
#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00)
#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000)
/*
* CSR15: Synchronization status register.
* CFP: ASIC is in contention-free period.
* ATIMW: ASIC is in ATIM window.
* BEACON_SENT: Beacon is send.
*/
#define CSR15 0x003c
#define CSR15_CFP FIELD32(0x00000001)
#define CSR15_ATIMW FIELD32(0x00000002)
#define CSR15_BEACON_SENT FIELD32(0x00000004)
/*
* CSR16: TSF timer register 0.
*/
#define CSR16 0x0040
#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff)
/*
* CSR17: TSF timer register 1.
*/
#define CSR17 0x0044
#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff)
/*
* CSR18: IFS timer register 0.
* SIFS: Sifs, default is 10 us.
* PIFS: Pifs, default is 30 us.
*/
#define CSR18 0x0048
#define CSR18_SIFS FIELD32(0x0000ffff)
#define CSR18_PIFS FIELD32(0xffff0000)
/*
* CSR19: IFS timer register 1.
* DIFS: Difs, default is 50 us.
* EIFS: Eifs, default is 364 us.
*/
#define CSR19 0x004c
#define CSR19_DIFS FIELD32(0x0000ffff)
#define CSR19_EIFS FIELD32(0xffff0000)
/*
* CSR20: Wakeup timer register.
* DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU.
* TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
* AUTOWAKE: Enable auto wakeup / sleep mechanism.
*/
#define CSR20 0x0050
#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff)
#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000)
#define CSR20_AUTOWAKE FIELD32(0x01000000)
/*
* CSR21: EEPROM control register.
* RELOAD: Write 1 to reload eeprom content.
* TYPE_93C46: 1: 93c46, 0:93c66.
*/
#define CSR21 0x0054
#define CSR21_RELOAD FIELD32(0x00000001)
#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002)
#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004)
#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008)
#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010)
#define CSR21_TYPE_93C46 FIELD32(0x00000020)
/*
* CSR22: CFP control register.
* CFP_DURATION_REMAIN: Cfp duration remain, in units of TU.
* RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain.
*/
#define CSR22 0x0058
#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff)
#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000)
/*
* Transmit related CSRs.
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* TXCSR0: TX Control Register.
* KICK_TX: Kick tx ring.
* KICK_ATIM: Kick atim ring.
* KICK_PRIO: Kick priority ring.
* ABORT: Abort all transmit related ring operation.
*/
#define TXCSR0 0x0060
#define TXCSR0_KICK_TX FIELD32(0x00000001)
#define TXCSR0_KICK_ATIM FIELD32(0x00000002)
#define TXCSR0_KICK_PRIO FIELD32(0x00000004)
#define TXCSR0_ABORT FIELD32(0x00000008)
/*
* TXCSR1: TX Configuration Register.
* ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps.
* ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps.
* TSF_OFFSET: Insert tsf offset.
* AUTORESPONDER: Enable auto responder which include ack & cts.
*/
#define TXCSR1 0x0064
#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff)
#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00)
#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000)
#define TXCSR1_AUTORESPONDER FIELD32(0x01000000)
/*
* TXCSR2: Tx descriptor configuration register.
* TXD_SIZE: Tx descriptor size, default is 48.
* NUM_TXD: Number of tx entries in ring.
* NUM_ATIM: Number of atim entries in ring.
* NUM_PRIO: Number of priority entries in ring.
*/
#define TXCSR2 0x0068
#define TXCSR2_TXD_SIZE FIELD32(0x000000ff)
#define TXCSR2_NUM_TXD FIELD32(0x0000ff00)
#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000)
#define TXCSR2_NUM_PRIO FIELD32(0xff000000)
/*
* TXCSR3: TX Ring Base address register.
*/
#define TXCSR3 0x006c
#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff)
/*
* TXCSR4: TX Atim Ring Base address register.
*/
#define TXCSR4 0x0070
#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff)
/*
* TXCSR5: TX Prio Ring Base address register.
*/
#define TXCSR5 0x0074
#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff)
/*
* TXCSR6: Beacon Base address register.
*/
#define TXCSR6 0x0078
#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff)
/*
* TXCSR7: Auto responder control register.
* AR_POWERMANAGEMENT: Auto responder power management bit.
*/
#define TXCSR7 0x007c
#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001)
/*
* Receive related CSRs.
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* RXCSR0: RX Control Register.
* DISABLE_RX: Disable rx engine.
* DROP_CRC: Drop crc error.
* DROP_PHYSICAL: Drop physical error.
* DROP_CONTROL: Drop control frame.
* DROP_NOT_TO_ME: Drop not to me unicast frame.
* DROP_TODS: Drop frame tods bit is true.
* DROP_VERSION_ERROR: Drop version error frame.
* PASS_CRC: Pass all packets with crc attached.
*/
#define RXCSR0 0x0080
#define RXCSR0_DISABLE_RX FIELD32(0x00000001)
#define RXCSR0_DROP_CRC FIELD32(0x00000002)
#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004)
#define RXCSR0_DROP_CONTROL FIELD32(0x00000008)
#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010)
#define RXCSR0_DROP_TODS FIELD32(0x00000020)
#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040)
#define RXCSR0_PASS_CRC FIELD32(0x00000080)
/*
* RXCSR1: RX descriptor configuration register.
* RXD_SIZE: Rx descriptor size, default is 32b.
* NUM_RXD: Number of rx entries in ring.
*/
#define RXCSR1 0x0084
#define RXCSR1_RXD_SIZE FIELD32(0x000000ff)
#define RXCSR1_NUM_RXD FIELD32(0x0000ff00)
/*
* RXCSR2: RX Ring base address register.
*/
#define RXCSR2 0x0088
#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff)
/*
* RXCSR3: BBP ID register for Rx operation.
* BBP_ID#: BBP register # id.
* BBP_ID#_VALID: BBP register # id is valid or not.
*/
#define RXCSR3 0x0090
#define RXCSR3_BBP_ID0 FIELD32(0x0000007f)
#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080)
#define RXCSR3_BBP_ID1 FIELD32(0x00007f00)
#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000)
#define RXCSR3_BBP_ID2 FIELD32(0x007f0000)
#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000)
#define RXCSR3_BBP_ID3 FIELD32(0x7f000000)
#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000)
/*
* RXCSR4: BBP ID register for Rx operation.
* BBP_ID#: BBP register # id.
* BBP_ID#_VALID: BBP register # id is valid or not.
*/
#define RXCSR4 0x0094
#define RXCSR4_BBP_ID4 FIELD32(0x0000007f)
#define RXCSR4_BBP_ID4_VALID FIELD32(0x00000080)
#define RXCSR4_BBP_ID5 FIELD32(0x00007f00)
#define RXCSR4_BBP_ID5_VALID FIELD32(0x00008000)
/*
* ARCSR0: Auto Responder PLCP config register 0.
* ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
* ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
*/
#define ARCSR0 0x0098
#define ARCSR0_AR_BBP_DATA0 FIELD32(0x000000ff)
#define ARCSR0_AR_BBP_ID0 FIELD32(0x0000ff00)
#define ARCSR0_AR_BBP_DATA1 FIELD32(0x00ff0000)
#define ARCSR0_AR_BBP_ID1 FIELD32(0xff000000)
/*
* ARCSR1: Auto Responder PLCP config register 1.
* ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
* ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
*/
#define ARCSR1 0x009c
#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff)
#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00)
#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000)
#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000)
/*
* Miscellaneous Registers.
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* PCICSR: PCI control register.
* BIG_ENDIAN: 1: big endian, 0: little endian.
* RX_TRESHOLD: Rx threshold in dw to start pci access
* 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw.
* TX_TRESHOLD: Tx threshold in dw to start pci access
* 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward.
* BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw.
* ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational.
*/
#define PCICSR 0x008c
#define PCICSR_BIG_ENDIAN FIELD32(0x00000001)
#define PCICSR_RX_TRESHOLD FIELD32(0x00000006)
#define PCICSR_TX_TRESHOLD FIELD32(0x00000018)
#define PCICSR_BURST_LENTH FIELD32(0x00000060)
#define PCICSR_ENABLE_CLK FIELD32(0x00000080)
/*
* CNT0: FCS error count.
* FCS_ERROR: FCS error count, cleared when read.
*/
#define CNT0 0x00a0
#define CNT0_FCS_ERROR FIELD32(0x0000ffff)
/*
* Statistic Register.
* CNT1: PLCP error count.
* CNT2: Long error count.
* CNT3: CCA false alarm count.
* CNT4: Rx FIFO overflow count.
* CNT5: Tx FIFO underrun count.
*/
#define TIMECSR2 0x00a8
#define CNT1 0x00ac
#define CNT2 0x00b0
#define TIMECSR3 0x00b4
#define CNT3 0x00b8
#define CNT4 0x00bc
#define CNT5 0x00c0
/*
* Baseband Control Register.
*/
/*
* PWRCSR0: Power mode configuration register.
*/
#define PWRCSR0 0x00c4
/*
* Power state transition time registers.
*/
#define PSCSR0 0x00c8
#define PSCSR1 0x00cc
#define PSCSR2 0x00d0
#define PSCSR3 0x00d4
/*
* PWRCSR1: Manual power control / status register.
* Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
* SET_STATE: Set state. Write 1 to trigger, self cleared.
* BBP_DESIRE_STATE: BBP desired state.
* RF_DESIRE_STATE: RF desired state.
* BBP_CURR_STATE: BBP current state.
* RF_CURR_STATE: RF current state.
* PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
*/
#define PWRCSR1 0x00d8
#define PWRCSR1_SET_STATE FIELD32(0x00000001)
#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006)
#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018)
#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060)
#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180)
#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200)
/*
* TIMECSR: Timer control register.
* US_COUNT: 1 us timer count in units of clock cycles.
* US_64_COUNT: 64 us timer count in units of 1 us timer.
* BEACON_EXPECT: Beacon expect window.
*/
#define TIMECSR 0x00dc
#define TIMECSR_US_COUNT FIELD32(0x000000ff)
#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00)
#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000)
/*
* MACCSR0: MAC configuration register 0.
*/
#define MACCSR0 0x00e0
/*
* MACCSR1: MAC configuration register 1.
* KICK_RX: Kick one-shot rx in one-shot rx mode.
* ONESHOT_RXMODE: Enable one-shot rx mode for debugging.
* BBPRX_RESET_MODE: Ralink bbp rx reset mode.
* AUTO_TXBBP: Auto tx logic access bbp control register.
* AUTO_RXBBP: Auto rx logic access bbp control register.
* LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd.
* INTERSIL_IF: Intersil if calibration pin.
*/
#define MACCSR1 0x00e4
#define MACCSR1_KICK_RX FIELD32(0x00000001)
#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002)
#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004)
#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008)
#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010)
#define MACCSR1_LOOPBACK FIELD32(0x00000060)
#define MACCSR1_INTERSIL_IF FIELD32(0x00000080)
/*
* RALINKCSR: Ralink Rx auto-reset BBCR.
* AR_BBP_DATA#: Auto reset BBP register # data.
* AR_BBP_ID#: Auto reset BBP register # id.
*/
#define RALINKCSR 0x00e8
#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff)
#define RALINKCSR_AR_BBP_ID0 FIELD32(0x0000ff00)
#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000)
#define RALINKCSR_AR_BBP_ID1 FIELD32(0xff000000)
/*
* BCNCSR: Beacon interval control register.
* CHANGE: Write one to change beacon interval.
* DELTATIME: The delta time value.
* NUM_BEACON: Number of beacon according to mode.
* MODE: Please refer to asic specs.
* PLUS: Plus or minus delta time value.
*/
#define BCNCSR 0x00ec
#define BCNCSR_CHANGE FIELD32(0x00000001)
#define BCNCSR_DELTATIME FIELD32(0x0000001e)
#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0)
#define BCNCSR_MODE FIELD32(0x00006000)
#define BCNCSR_PLUS FIELD32(0x00008000)
/*
* BBP / RF / IF Control Register.
*/
/*
* BBPCSR: BBP serial control register.
* VALUE: Register value to program into BBP.
* REGNUM: Selected BBP register.
* BUSY: 1: asic is busy execute BBP programming.
* WRITE_CONTROL: 1: write BBP, 0: read BBP.
*/
#define BBPCSR 0x00f0
#define BBPCSR_VALUE FIELD32(0x000000ff)
#define BBPCSR_REGNUM FIELD32(0x00007f00)
#define BBPCSR_BUSY FIELD32(0x00008000)
#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000)
/*
* RFCSR: RF serial control register.
* VALUE: Register value + id to program into rf/if.
* NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
* IF_SELECT: Chip to program: 0: rf, 1: if.
* PLL_LD: Rf pll_ld status.
* BUSY: 1: asic is busy execute rf programming.
*/
#define RFCSR 0x00f4
#define RFCSR_VALUE FIELD32(0x00ffffff)
#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000)
#define RFCSR_IF_SELECT FIELD32(0x20000000)
#define RFCSR_PLL_LD FIELD32(0x40000000)
#define RFCSR_BUSY FIELD32(0x80000000)
/*
* LEDCSR: LED control register.
* ON_PERIOD: On period, default 70ms.
* OFF_PERIOD: Off period, default 30ms.
* LINK: 0: linkoff, 1: linkup.
* ACTIVITY: 0: idle, 1: active.
*/
#define LEDCSR 0x00f8
#define LEDCSR_ON_PERIOD FIELD32(0x000000ff)
#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00)
#define LEDCSR_LINK FIELD32(0x00010000)
#define LEDCSR_ACTIVITY FIELD32(0x00020000)
/*
* ASIC pointer information.
* RXPTR: Current RX ring address.
* TXPTR: Current Tx ring address.
* PRIPTR: Current Priority ring address.
* ATIMPTR: Current ATIM ring address.
*/
#define RXPTR 0x0100
#define TXPTR 0x0104
#define PRIPTR 0x0108
#define ATIMPTR 0x010c
/*
* GPIO and others.
*/
/*
* GPIOCSR: GPIO control register.
* GPIOCSR_VALx: Actual GPIO pin x value
* GPIOCSR_DIRx: GPIO direction: 0 = output; 1 = input
*/
#define GPIOCSR 0x0120
#define GPIOCSR_VAL0 FIELD32(0x00000001)
#define GPIOCSR_VAL1 FIELD32(0x00000002)
#define GPIOCSR_VAL2 FIELD32(0x00000004)
#define GPIOCSR_VAL3 FIELD32(0x00000008)
#define GPIOCSR_VAL4 FIELD32(0x00000010)
#define GPIOCSR_VAL5 FIELD32(0x00000020)
#define GPIOCSR_VAL6 FIELD32(0x00000040)
#define GPIOCSR_VAL7 FIELD32(0x00000080)
#define GPIOCSR_DIR0 FIELD32(0x00000100)
#define GPIOCSR_DIR1 FIELD32(0x00000200)
#define GPIOCSR_DIR2 FIELD32(0x00000400)
#define GPIOCSR_DIR3 FIELD32(0x00000800)
#define GPIOCSR_DIR4 FIELD32(0x00001000)
#define GPIOCSR_DIR5 FIELD32(0x00002000)
#define GPIOCSR_DIR6 FIELD32(0x00004000)
#define GPIOCSR_DIR7 FIELD32(0x00008000)
/*
* BBPPCSR: BBP Pin control register.
*/
#define BBPPCSR 0x0124
/*
* BCNCSR1: Tx BEACON offset time control register.
* PRELOAD: Beacon timer offset in units of usec.
*/
#define BCNCSR1 0x0130
#define BCNCSR1_PRELOAD FIELD32(0x0000ffff)
/*
* MACCSR2: TX_PE to RX_PE turn-around time control register
* DELAY: RX_PE low width, in units of pci clock cycle.
*/
#define MACCSR2 0x0134
#define MACCSR2_DELAY FIELD32(0x000000ff)
/*
* ARCSR2: 1 Mbps ACK/CTS PLCP.
*/
#define ARCSR2 0x013c
#define ARCSR2_SIGNAL FIELD32(0x000000ff)
#define ARCSR2_SERVICE FIELD32(0x0000ff00)
#define ARCSR2_LENGTH_LOW FIELD32(0x00ff0000)
#define ARCSR2_LENGTH FIELD32(0xffff0000)
/*
* ARCSR3: 2 Mbps ACK/CTS PLCP.
*/
#define ARCSR3 0x0140
#define ARCSR3_SIGNAL FIELD32(0x000000ff)
#define ARCSR3_SERVICE FIELD32(0x0000ff00)
#define ARCSR3_LENGTH FIELD32(0xffff0000)
/*
* ARCSR4: 5.5 Mbps ACK/CTS PLCP.
*/
#define ARCSR4 0x0144
#define ARCSR4_SIGNAL FIELD32(0x000000ff)
#define ARCSR4_SERVICE FIELD32(0x0000ff00)
#define ARCSR4_LENGTH FIELD32(0xffff0000)
/*
* ARCSR5: 11 Mbps ACK/CTS PLCP.
*/
#define ARCSR5 0x0148
#define ARCSR5_SIGNAL FIELD32(0x000000ff)
#define ARCSR5_SERVICE FIELD32(0x0000ff00)
#define ARCSR5_LENGTH FIELD32(0xffff0000)
/*
* BBP registers.
* The wordsize of the BBP is 8 bits.
*/
/*
* R1: TX antenna control
*/
#define BBP_R1_TX_ANTENNA FIELD8(0x03)
/*
* R4: RX antenna control
*/
#define BBP_R4_RX_ANTENNA FIELD8(0x06)
/*
* RF registers
*/
/*
* RF 1
*/
#define RF1_TUNER FIELD32(0x00020000)
/*
* RF 3
*/
#define RF3_TUNER FIELD32(0x00000100)
#define RF3_TXPOWER FIELD32(0x00003e00)
/*
* EEPROM content.
* The wordsize of the EEPROM is 16 bits.
*/
/*
* HW MAC address.
*/
#define EEPROM_MAC_ADDR_0 0x0002
#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
#define EEPROM_MAC_ADDR1 0x0003
#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
#define EEPROM_MAC_ADDR_2 0x0004
#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
/*
* EEPROM antenna.
* ANTENNA_NUM: Number of antenna's.
* TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RF_TYPE: Rf_type of this adapter.
* LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd.
* RX_AGCVGC: 0: disable, 1:enable BBP R13 tuning.
* HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
*/
#define EEPROM_ANTENNA 0x0b
#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0040)
#define EEPROM_ANTENNA_LED_MODE FIELD16(0x0180)
#define EEPROM_ANTENNA_RX_AGCVGC_TUNING FIELD16(0x0200)
#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
/*
* EEPROM BBP.
*/
#define EEPROM_BBP_START 0x0c
#define EEPROM_BBP_SIZE 7
#define EEPROM_BBP_VALUE FIELD16(0x00ff)
#define EEPROM_BBP_REG_ID FIELD16(0xff00)
/*
* EEPROM TXPOWER
*/
#define EEPROM_TXPOWER_START 0x13
#define EEPROM_TXPOWER_SIZE 7
#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
#define EEPROM_TXPOWER_2 FIELD16(0xff00)
/*
* DMA descriptor defines.
*/
#define TXD_DESC_SIZE (8 * sizeof(__le32))
#define RXD_DESC_SIZE (8 * sizeof(__le32))
/*
* TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
*/
/*
* Word0
*/
#define TXD_W0_OWNER_NIC FIELD32(0x00000001)
#define TXD_W0_VALID FIELD32(0x00000002)
#define TXD_W0_RESULT FIELD32(0x0000001c)
#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0)
#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
#define TXD_W0_ACK FIELD32(0x00000200)
#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
#define TXD_W0_RTS FIELD32(0x00000800)
#define TXD_W0_IFS FIELD32(0x00006000)
#define TXD_W0_RETRY_MODE FIELD32(0x00008000)
#define TXD_W0_AGC FIELD32(0x00ff0000)
#define TXD_W0_R2 FIELD32(0xff000000)
/*
* Word1
*/
#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
/*
* Word2
*/
#define TXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff)
#define TXD_W2_DATABYTE_COUNT FIELD32(0xffff0000)
/*
* Word3 & 4: PLCP information
* The PLCP values should be treated as if they were BBP values.
*/
#define TXD_W3_PLCP_SIGNAL FIELD32(0x000000ff)
#define TXD_W3_PLCP_SIGNAL_REGNUM FIELD32(0x00007f00)
#define TXD_W3_PLCP_SIGNAL_BUSY FIELD32(0x00008000)
#define TXD_W3_PLCP_SERVICE FIELD32(0x00ff0000)
#define TXD_W3_PLCP_SERVICE_REGNUM FIELD32(0x7f000000)
#define TXD_W3_PLCP_SERVICE_BUSY FIELD32(0x80000000)
#define TXD_W4_PLCP_LENGTH_LOW FIELD32(0x000000ff)
#define TXD_W3_PLCP_LENGTH_LOW_REGNUM FIELD32(0x00007f00)
#define TXD_W3_PLCP_LENGTH_LOW_BUSY FIELD32(0x00008000)
#define TXD_W4_PLCP_LENGTH_HIGH FIELD32(0x00ff0000)
#define TXD_W3_PLCP_LENGTH_HIGH_REGNUM FIELD32(0x7f000000)
#define TXD_W3_PLCP_LENGTH_HIGH_BUSY FIELD32(0x80000000)
/*
* Word5
*/
#define TXD_W5_BBCR4 FIELD32(0x0000ffff)
#define TXD_W5_AGC_REG FIELD32(0x007f0000)
#define TXD_W5_AGC_REG_VALID FIELD32(0x00800000)
#define TXD_W5_XXX_REG FIELD32(0x7f000000)
#define TXD_W5_XXX_REG_VALID FIELD32(0x80000000)
/*
* Word6
*/
#define TXD_W6_SK_BUFF FIELD32(0xffffffff)
/*
* Word7
*/
#define TXD_W7_RESERVED FIELD32(0xffffffff)
/*
* RX descriptor format for RX Ring.
*/
/*
* Word0
*/
#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
#define RXD_W0_MULTICAST FIELD32(0x00000004)
#define RXD_W0_BROADCAST FIELD32(0x00000008)
#define RXD_W0_MY_BSS FIELD32(0x00000010)
#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
#define RXD_W0_DATABYTE_COUNT FIELD32(0xffff0000)
/*
* Word1
*/
#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
/*
* Word2
*/
#define RXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff)
#define RXD_W2_BBR0 FIELD32(0x00ff0000)
#define RXD_W2_SIGNAL FIELD32(0xff000000)
/*
* Word3
*/
#define RXD_W3_RSSI FIELD32(0x000000ff)
#define RXD_W3_BBR3 FIELD32(0x0000ff00)
#define RXD_W3_BBR4 FIELD32(0x00ff0000)
#define RXD_W3_BBR5 FIELD32(0xff000000)
/*
* Word4
*/
#define RXD_W4_RX_END_TIME FIELD32(0xffffffff)
/*
* Word5 & 6 & 7: Reserved
*/
#define RXD_W5_RESERVED FIELD32(0xffffffff)
#define RXD_W6_RESERVED FIELD32(0xffffffff)
#define RXD_W7_RESERVED FIELD32(0xffffffff)
/*
* Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
* NOTE: Logics in rt2400pci for txpower are reversed
* compared to the other rt2x00 drivers. A higher txpower
* value means that the txpower must be lowered. This is
* important when converting the value coming from the
* mac80211 stack to the rt2400 acceptable value.
*/
#define MIN_TXPOWER 31
#define MAX_TXPOWER 62
#define DEFAULT_TXPOWER 39
#define __CLAMP_TX(__txpower) \
clamp_t(u8, (__txpower), MIN_TXPOWER, MAX_TXPOWER)
#define TXPOWER_FROM_DEV(__txpower) \
((__CLAMP_TX(__txpower) - MAX_TXPOWER) + MIN_TXPOWER)
#define TXPOWER_TO_DEV(__txpower) \
(MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER))
#endif /* RT2400PCI_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,844 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2500usb
Abstract: Data structures and registers for the rt2500usb module.
Supported chipsets: RT2570.
*/
#ifndef RT2500USB_H
#define RT2500USB_H
/*
* RF chip defines.
*/
#define RF2522 0x0000
#define RF2523 0x0001
#define RF2524 0x0002
#define RF2525 0x0003
#define RF2525E 0x0005
#define RF5222 0x0010
/*
* RT2570 version
*/
#define RT2570_VERSION_B 2
#define RT2570_VERSION_C 3
#define RT2570_VERSION_D 4
/*
* Signal information.
* Default offset is required for RSSI <-> dBm conversion.
*/
#define DEFAULT_RSSI_OFFSET 120
/*
* Register layout information.
*/
#define CSR_REG_BASE 0x0400
#define CSR_REG_SIZE 0x0100
#define EEPROM_BASE 0x0000
#define EEPROM_SIZE 0x006e
#define BBP_BASE 0x0000
#define BBP_SIZE 0x0060
#define RF_BASE 0x0004
#define RF_SIZE 0x0010
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/*
* Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* MAC_CSR0: ASIC revision number.
*/
#define MAC_CSR0 0x0400
/*
* MAC_CSR1: System control.
* SOFT_RESET: Software reset, 1: reset, 0: normal.
* BBP_RESET: Hardware reset, 1: reset, 0, release.
* HOST_READY: Host ready after initialization.
*/
#define MAC_CSR1 0x0402
#define MAC_CSR1_SOFT_RESET FIELD16(0x00000001)
#define MAC_CSR1_BBP_RESET FIELD16(0x00000002)
#define MAC_CSR1_HOST_READY FIELD16(0x00000004)
/*
* MAC_CSR2: STA MAC register 0.
*/
#define MAC_CSR2 0x0404
#define MAC_CSR2_BYTE0 FIELD16(0x00ff)
#define MAC_CSR2_BYTE1 FIELD16(0xff00)
/*
* MAC_CSR3: STA MAC register 1.
*/
#define MAC_CSR3 0x0406
#define MAC_CSR3_BYTE2 FIELD16(0x00ff)
#define MAC_CSR3_BYTE3 FIELD16(0xff00)
/*
* MAC_CSR4: STA MAC register 2.
*/
#define MAC_CSR4 0X0408
#define MAC_CSR4_BYTE4 FIELD16(0x00ff)
#define MAC_CSR4_BYTE5 FIELD16(0xff00)
/*
* MAC_CSR5: BSSID register 0.
*/
#define MAC_CSR5 0x040a
#define MAC_CSR5_BYTE0 FIELD16(0x00ff)
#define MAC_CSR5_BYTE1 FIELD16(0xff00)
/*
* MAC_CSR6: BSSID register 1.
*/
#define MAC_CSR6 0x040c
#define MAC_CSR6_BYTE2 FIELD16(0x00ff)
#define MAC_CSR6_BYTE3 FIELD16(0xff00)
/*
* MAC_CSR7: BSSID register 2.
*/
#define MAC_CSR7 0x040e
#define MAC_CSR7_BYTE4 FIELD16(0x00ff)
#define MAC_CSR7_BYTE5 FIELD16(0xff00)
/*
* MAC_CSR8: Max frame length.
*/
#define MAC_CSR8 0x0410
#define MAC_CSR8_MAX_FRAME_UNIT FIELD16(0x0fff)
/*
* Misc MAC_CSR registers.
* MAC_CSR9: Timer control.
* MAC_CSR10: Slot time.
* MAC_CSR11: SIFS.
* MAC_CSR12: EIFS.
* MAC_CSR13: Power mode0.
* MAC_CSR14: Power mode1.
* MAC_CSR15: Power saving transition0
* MAC_CSR16: Power saving transition1
*/
#define MAC_CSR9 0x0412
#define MAC_CSR10 0x0414
#define MAC_CSR11 0x0416
#define MAC_CSR12 0x0418
#define MAC_CSR13 0x041a
#define MAC_CSR14 0x041c
#define MAC_CSR15 0x041e
#define MAC_CSR16 0x0420
/*
* MAC_CSR17: Manual power control / status register.
* Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
* SET_STATE: Set state. Write 1 to trigger, self cleared.
* BBP_DESIRE_STATE: BBP desired state.
* RF_DESIRE_STATE: RF desired state.
* BBP_CURRENT_STATE: BBP current state.
* RF_CURRENT_STATE: RF current state.
* PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
*/
#define MAC_CSR17 0x0422
#define MAC_CSR17_SET_STATE FIELD16(0x0001)
#define MAC_CSR17_BBP_DESIRE_STATE FIELD16(0x0006)
#define MAC_CSR17_RF_DESIRE_STATE FIELD16(0x0018)
#define MAC_CSR17_BBP_CURR_STATE FIELD16(0x0060)
#define MAC_CSR17_RF_CURR_STATE FIELD16(0x0180)
#define MAC_CSR17_PUT_TO_SLEEP FIELD16(0x0200)
/*
* MAC_CSR18: Wakeup timer register.
* DELAY_AFTER_BEACON: Delay after Tbcn expired in units of 1/16 TU.
* BEACONS_BEFORE_WAKEUP: Number of beacon before wakeup.
* AUTO_WAKE: Enable auto wakeup / sleep mechanism.
*/
#define MAC_CSR18 0x0424
#define MAC_CSR18_DELAY_AFTER_BEACON FIELD16(0x00ff)
#define MAC_CSR18_BEACONS_BEFORE_WAKEUP FIELD16(0x7f00)
#define MAC_CSR18_AUTO_WAKE FIELD16(0x8000)
/*
* MAC_CSR19: GPIO control register.
* MAC_CSR19_VALx: GPIO value
* MAC_CSR19_DIRx: GPIO direction: 0 = input; 1 = output
*/
#define MAC_CSR19 0x0426
#define MAC_CSR19_VAL0 FIELD16(0x0001)
#define MAC_CSR19_VAL1 FIELD16(0x0002)
#define MAC_CSR19_VAL2 FIELD16(0x0004)
#define MAC_CSR19_VAL3 FIELD16(0x0008)
#define MAC_CSR19_VAL4 FIELD16(0x0010)
#define MAC_CSR19_VAL5 FIELD16(0x0020)
#define MAC_CSR19_VAL6 FIELD16(0x0040)
#define MAC_CSR19_VAL7 FIELD16(0x0080)
#define MAC_CSR19_DIR0 FIELD16(0x0100)
#define MAC_CSR19_DIR1 FIELD16(0x0200)
#define MAC_CSR19_DIR2 FIELD16(0x0400)
#define MAC_CSR19_DIR3 FIELD16(0x0800)
#define MAC_CSR19_DIR4 FIELD16(0x1000)
#define MAC_CSR19_DIR5 FIELD16(0x2000)
#define MAC_CSR19_DIR6 FIELD16(0x4000)
#define MAC_CSR19_DIR7 FIELD16(0x8000)
/*
* MAC_CSR20: LED control register.
* ACTIVITY: 0: idle, 1: active.
* LINK: 0: linkoff, 1: linkup.
* ACTIVITY_POLARITY: 0: active low, 1: active high.
*/
#define MAC_CSR20 0x0428
#define MAC_CSR20_ACTIVITY FIELD16(0x0001)
#define MAC_CSR20_LINK FIELD16(0x0002)
#define MAC_CSR20_ACTIVITY_POLARITY FIELD16(0x0004)
/*
* MAC_CSR21: LED control register.
* ON_PERIOD: On period, default 70ms.
* OFF_PERIOD: Off period, default 30ms.
*/
#define MAC_CSR21 0x042a
#define MAC_CSR21_ON_PERIOD FIELD16(0x00ff)
#define MAC_CSR21_OFF_PERIOD FIELD16(0xff00)
/*
* MAC_CSR22: Collision window control register.
*/
#define MAC_CSR22 0x042c
/*
* Transmit related CSRs.
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
/*
* TXRX_CSR0: Security control register.
*/
#define TXRX_CSR0 0x0440
#define TXRX_CSR0_ALGORITHM FIELD16(0x0007)
#define TXRX_CSR0_IV_OFFSET FIELD16(0x01f8)
#define TXRX_CSR0_KEY_ID FIELD16(0x1e00)
/*
* TXRX_CSR1: TX configuration.
* ACK_TIMEOUT: ACK Timeout in unit of 1-us.
* TSF_OFFSET: TSF offset in MAC header.
* AUTO_SEQUENCE: Let ASIC control frame sequence number.
*/
#define TXRX_CSR1 0x0442
#define TXRX_CSR1_ACK_TIMEOUT FIELD16(0x00ff)
#define TXRX_CSR1_TSF_OFFSET FIELD16(0x7f00)
#define TXRX_CSR1_AUTO_SEQUENCE FIELD16(0x8000)
/*
* TXRX_CSR2: RX control.
* DISABLE_RX: Disable rx engine.
* DROP_CRC: Drop crc error.
* DROP_PHYSICAL: Drop physical error.
* DROP_CONTROL: Drop control frame.
* DROP_NOT_TO_ME: Drop not to me unicast frame.
* DROP_TODS: Drop frame tods bit is true.
* DROP_VERSION_ERROR: Drop version error frame.
* DROP_MCAST: Drop multicast frames.
* DROP_BCAST: Drop broadcast frames.
*/
#define TXRX_CSR2 0x0444
#define TXRX_CSR2_DISABLE_RX FIELD16(0x0001)
#define TXRX_CSR2_DROP_CRC FIELD16(0x0002)
#define TXRX_CSR2_DROP_PHYSICAL FIELD16(0x0004)
#define TXRX_CSR2_DROP_CONTROL FIELD16(0x0008)
#define TXRX_CSR2_DROP_NOT_TO_ME FIELD16(0x0010)
#define TXRX_CSR2_DROP_TODS FIELD16(0x0020)
#define TXRX_CSR2_DROP_VERSION_ERROR FIELD16(0x0040)
#define TXRX_CSR2_DROP_MULTICAST FIELD16(0x0200)
#define TXRX_CSR2_DROP_BROADCAST FIELD16(0x0400)
/*
* RX BBP ID registers
* TXRX_CSR3: CCK RX BBP ID.
* TXRX_CSR4: OFDM RX BBP ID.
*/
#define TXRX_CSR3 0x0446
#define TXRX_CSR4 0x0448
/*
* TXRX_CSR5: CCK TX BBP ID0.
*/
#define TXRX_CSR5 0x044a
#define TXRX_CSR5_BBP_ID0 FIELD16(0x007f)
#define TXRX_CSR5_BBP_ID0_VALID FIELD16(0x0080)
#define TXRX_CSR5_BBP_ID1 FIELD16(0x7f00)
#define TXRX_CSR5_BBP_ID1_VALID FIELD16(0x8000)
/*
* TXRX_CSR6: CCK TX BBP ID1.
*/
#define TXRX_CSR6 0x044c
#define TXRX_CSR6_BBP_ID0 FIELD16(0x007f)
#define TXRX_CSR6_BBP_ID0_VALID FIELD16(0x0080)
#define TXRX_CSR6_BBP_ID1 FIELD16(0x7f00)
#define TXRX_CSR6_BBP_ID1_VALID FIELD16(0x8000)
/*
* TXRX_CSR7: OFDM TX BBP ID0.
*/
#define TXRX_CSR7 0x044e
#define TXRX_CSR7_BBP_ID0 FIELD16(0x007f)
#define TXRX_CSR7_BBP_ID0_VALID FIELD16(0x0080)
#define TXRX_CSR7_BBP_ID1 FIELD16(0x7f00)
#define TXRX_CSR7_BBP_ID1_VALID FIELD16(0x8000)
/*
* TXRX_CSR8: OFDM TX BBP ID1.
*/
#define TXRX_CSR8 0x0450
#define TXRX_CSR8_BBP_ID0 FIELD16(0x007f)
#define TXRX_CSR8_BBP_ID0_VALID FIELD16(0x0080)
#define TXRX_CSR8_BBP_ID1 FIELD16(0x7f00)
#define TXRX_CSR8_BBP_ID1_VALID FIELD16(0x8000)
/*
* TXRX_CSR9: TX ACK time-out.
*/
#define TXRX_CSR9 0x0452
/*
* TXRX_CSR10: Auto responder control.
*/
#define TXRX_CSR10 0x0454
#define TXRX_CSR10_AUTORESPOND_PREAMBLE FIELD16(0x0004)
/*
* TXRX_CSR11: Auto responder basic rate.
*/
#define TXRX_CSR11 0x0456
/*
* ACK/CTS time registers.
*/
#define TXRX_CSR12 0x0458
#define TXRX_CSR13 0x045a
#define TXRX_CSR14 0x045c
#define TXRX_CSR15 0x045e
#define TXRX_CSR16 0x0460
#define TXRX_CSR17 0x0462
/*
* TXRX_CSR18: Synchronization control register.
*/
#define TXRX_CSR18 0x0464
#define TXRX_CSR18_OFFSET FIELD16(0x000f)
#define TXRX_CSR18_INTERVAL FIELD16(0xfff0)
/*
* TXRX_CSR19: Synchronization control register.
* TSF_COUNT: Enable TSF auto counting.
* TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
* TBCN: Enable Tbcn with reload value.
* BEACON_GEN: Enable beacon generator.
*/
#define TXRX_CSR19 0x0466
#define TXRX_CSR19_TSF_COUNT FIELD16(0x0001)
#define TXRX_CSR19_TSF_SYNC FIELD16(0x0006)
#define TXRX_CSR19_TBCN FIELD16(0x0008)
#define TXRX_CSR19_BEACON_GEN FIELD16(0x0010)
/*
* TXRX_CSR20: Tx BEACON offset time control register.
* OFFSET: In units of usec.
* BCN_EXPECT_WINDOW: Default: 2^CWmin
*/
#define TXRX_CSR20 0x0468
#define TXRX_CSR20_OFFSET FIELD16(0x1fff)
#define TXRX_CSR20_BCN_EXPECT_WINDOW FIELD16(0xe000)
/*
* TXRX_CSR21
*/
#define TXRX_CSR21 0x046a
/*
* Encryption related CSRs.
*
*/
/*
* SEC_CSR0: Shared key 0, word 0
* SEC_CSR1: Shared key 0, word 1
* SEC_CSR2: Shared key 0, word 2
* SEC_CSR3: Shared key 0, word 3
* SEC_CSR4: Shared key 0, word 4
* SEC_CSR5: Shared key 0, word 5
* SEC_CSR6: Shared key 0, word 6
* SEC_CSR7: Shared key 0, word 7
*/
#define SEC_CSR0 0x0480
#define SEC_CSR1 0x0482
#define SEC_CSR2 0x0484
#define SEC_CSR3 0x0486
#define SEC_CSR4 0x0488
#define SEC_CSR5 0x048a
#define SEC_CSR6 0x048c
#define SEC_CSR7 0x048e
/*
* SEC_CSR8: Shared key 1, word 0
* SEC_CSR9: Shared key 1, word 1
* SEC_CSR10: Shared key 1, word 2
* SEC_CSR11: Shared key 1, word 3
* SEC_CSR12: Shared key 1, word 4
* SEC_CSR13: Shared key 1, word 5
* SEC_CSR14: Shared key 1, word 6
* SEC_CSR15: Shared key 1, word 7
*/
#define SEC_CSR8 0x0490
#define SEC_CSR9 0x0492
#define SEC_CSR10 0x0494
#define SEC_CSR11 0x0496
#define SEC_CSR12 0x0498
#define SEC_CSR13 0x049a
#define SEC_CSR14 0x049c
#define SEC_CSR15 0x049e
/*
* SEC_CSR16: Shared key 2, word 0
* SEC_CSR17: Shared key 2, word 1
* SEC_CSR18: Shared key 2, word 2
* SEC_CSR19: Shared key 2, word 3
* SEC_CSR20: Shared key 2, word 4
* SEC_CSR21: Shared key 2, word 5
* SEC_CSR22: Shared key 2, word 6
* SEC_CSR23: Shared key 2, word 7
*/
#define SEC_CSR16 0x04a0
#define SEC_CSR17 0x04a2
#define SEC_CSR18 0X04A4
#define SEC_CSR19 0x04a6
#define SEC_CSR20 0x04a8
#define SEC_CSR21 0x04aa
#define SEC_CSR22 0x04ac
#define SEC_CSR23 0x04ae
/*
* SEC_CSR24: Shared key 3, word 0
* SEC_CSR25: Shared key 3, word 1
* SEC_CSR26: Shared key 3, word 2
* SEC_CSR27: Shared key 3, word 3
* SEC_CSR28: Shared key 3, word 4
* SEC_CSR29: Shared key 3, word 5
* SEC_CSR30: Shared key 3, word 6
* SEC_CSR31: Shared key 3, word 7
*/
#define SEC_CSR24 0x04b0
#define SEC_CSR25 0x04b2
#define SEC_CSR26 0x04b4
#define SEC_CSR27 0x04b6
#define SEC_CSR28 0x04b8
#define SEC_CSR29 0x04ba
#define SEC_CSR30 0x04bc
#define SEC_CSR31 0x04be
#define KEY_ENTRY(__idx) \
( SEC_CSR0 + ((__idx) * 16) )
/*
* PHY control registers.
*/
/*
* PHY_CSR0: RF switching timing control.
*/
#define PHY_CSR0 0x04c0
/*
* PHY_CSR1: TX PA configuration.
*/
#define PHY_CSR1 0x04c2
/*
* MAC configuration registers.
*/
/*
* PHY_CSR2: TX MAC configuration.
* NOTE: Both register fields are complete dummy,
* documentation and legacy drivers are unclear un
* what this register means or what fields exists.
*/
#define PHY_CSR2 0x04c4
#define PHY_CSR2_LNA FIELD16(0x0002)
#define PHY_CSR2_LNA_MODE FIELD16(0x3000)
/*
* PHY_CSR3: RX MAC configuration.
*/
#define PHY_CSR3 0x04c6
/*
* PHY_CSR4: Interface configuration.
*/
#define PHY_CSR4 0x04c8
#define PHY_CSR4_LOW_RF_LE FIELD16(0x0001)
/*
* BBP pre-TX registers.
* PHY_CSR5: BBP pre-TX CCK.
*/
#define PHY_CSR5 0x04ca
#define PHY_CSR5_CCK FIELD16(0x0003)
#define PHY_CSR5_CCK_FLIP FIELD16(0x0004)
/*
* BBP pre-TX registers.
* PHY_CSR6: BBP pre-TX OFDM.
*/
#define PHY_CSR6 0x04cc
#define PHY_CSR6_OFDM FIELD16(0x0003)
#define PHY_CSR6_OFDM_FLIP FIELD16(0x0004)
/*
* PHY_CSR7: BBP access register 0.
* BBP_DATA: BBP data.
* BBP_REG_ID: BBP register ID.
* BBP_READ_CONTROL: 0: write, 1: read.
*/
#define PHY_CSR7 0x04ce
#define PHY_CSR7_DATA FIELD16(0x00ff)
#define PHY_CSR7_REG_ID FIELD16(0x7f00)
#define PHY_CSR7_READ_CONTROL FIELD16(0x8000)
/*
* PHY_CSR8: BBP access register 1.
* BBP_BUSY: ASIC is busy execute BBP programming.
*/
#define PHY_CSR8 0x04d0
#define PHY_CSR8_BUSY FIELD16(0x0001)
/*
* PHY_CSR9: RF access register.
* RF_VALUE: Register value + id to program into rf/if.
*/
#define PHY_CSR9 0x04d2
#define PHY_CSR9_RF_VALUE FIELD16(0xffff)
/*
* PHY_CSR10: RF access register.
* RF_VALUE: Register value + id to program into rf/if.
* RF_NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
* RF_IF_SELECT: Chip to program: 0: rf, 1: if.
* RF_PLL_LD: Rf pll_ld status.
* RF_BUSY: 1: asic is busy execute rf programming.
*/
#define PHY_CSR10 0x04d4
#define PHY_CSR10_RF_VALUE FIELD16(0x00ff)
#define PHY_CSR10_RF_NUMBER_OF_BITS FIELD16(0x1f00)
#define PHY_CSR10_RF_IF_SELECT FIELD16(0x2000)
#define PHY_CSR10_RF_PLL_LD FIELD16(0x4000)
#define PHY_CSR10_RF_BUSY FIELD16(0x8000)
/*
* STA_CSR0: FCS error count.
* FCS_ERROR: FCS error count, cleared when read.
*/
#define STA_CSR0 0x04e0
#define STA_CSR0_FCS_ERROR FIELD16(0xffff)
/*
* STA_CSR1: PLCP error count.
*/
#define STA_CSR1 0x04e2
/*
* STA_CSR2: LONG error count.
*/
#define STA_CSR2 0x04e4
/*
* STA_CSR3: CCA false alarm.
* FALSE_CCA_ERROR: False CCA error count, cleared when read.
*/
#define STA_CSR3 0x04e6
#define STA_CSR3_FALSE_CCA_ERROR FIELD16(0xffff)
/*
* STA_CSR4: RX FIFO overflow.
*/
#define STA_CSR4 0x04e8
/*
* STA_CSR5: Beacon sent counter.
*/
#define STA_CSR5 0x04ea
/*
* Statistics registers
*/
#define STA_CSR6 0x04ec
#define STA_CSR7 0x04ee
#define STA_CSR8 0x04f0
#define STA_CSR9 0x04f2
#define STA_CSR10 0x04f4
/*
* BBP registers.
* The wordsize of the BBP is 8 bits.
*/
/*
* R2: TX antenna control
*/
#define BBP_R2_TX_ANTENNA FIELD8(0x03)
#define BBP_R2_TX_IQ_FLIP FIELD8(0x04)
/*
* R14: RX antenna control
*/
#define BBP_R14_RX_ANTENNA FIELD8(0x03)
#define BBP_R14_RX_IQ_FLIP FIELD8(0x04)
/*
* RF registers.
*/
/*
* RF 1
*/
#define RF1_TUNER FIELD32(0x00020000)
/*
* RF 3
*/
#define RF3_TUNER FIELD32(0x00000100)
#define RF3_TXPOWER FIELD32(0x00003e00)
/*
* EEPROM contents.
*/
/*
* HW MAC address.
*/
#define EEPROM_MAC_ADDR_0 0x0002
#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
#define EEPROM_MAC_ADDR1 0x0003
#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
#define EEPROM_MAC_ADDR_2 0x0004
#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
/*
* EEPROM antenna.
* ANTENNA_NUM: Number of antenna's.
* TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* LED_MODE: 0: default, 1: TX/RX activity, 2: Single (ignore link), 3: rsvd.
* DYN_TXAGC: Dynamic TX AGC control.
* HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
* RF_TYPE: Rf_type of this adapter.
*/
#define EEPROM_ANTENNA 0x000b
#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0)
#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
/*
* EEPROM NIC config.
* CARDBUS_ACCEL: 0: enable, 1: disable.
* DYN_BBP_TUNE: 0: enable, 1: disable.
* CCK_TX_POWER: CCK TX power compensation.
*/
#define EEPROM_NIC 0x000c
#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001)
#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002)
#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c)
/*
* EEPROM geography.
* GEO: Default geography setting for device.
*/
#define EEPROM_GEOGRAPHY 0x000d
#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00)
/*
* EEPROM BBP.
*/
#define EEPROM_BBP_START 0x000e
#define EEPROM_BBP_SIZE 16
#define EEPROM_BBP_VALUE FIELD16(0x00ff)
#define EEPROM_BBP_REG_ID FIELD16(0xff00)
/*
* EEPROM TXPOWER
*/
#define EEPROM_TXPOWER_START 0x001e
#define EEPROM_TXPOWER_SIZE 7
#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
#define EEPROM_TXPOWER_2 FIELD16(0xff00)
/*
* EEPROM Tuning threshold
*/
#define EEPROM_BBPTUNE 0x0030
#define EEPROM_BBPTUNE_THRESHOLD FIELD16(0x00ff)
/*
* EEPROM BBP R24 Tuning.
*/
#define EEPROM_BBPTUNE_R24 0x0031
#define EEPROM_BBPTUNE_R24_LOW FIELD16(0x00ff)
#define EEPROM_BBPTUNE_R24_HIGH FIELD16(0xff00)
/*
* EEPROM BBP R25 Tuning.
*/
#define EEPROM_BBPTUNE_R25 0x0032
#define EEPROM_BBPTUNE_R25_LOW FIELD16(0x00ff)
#define EEPROM_BBPTUNE_R25_HIGH FIELD16(0xff00)
/*
* EEPROM BBP R24 Tuning.
*/
#define EEPROM_BBPTUNE_R61 0x0033
#define EEPROM_BBPTUNE_R61_LOW FIELD16(0x00ff)
#define EEPROM_BBPTUNE_R61_HIGH FIELD16(0xff00)
/*
* EEPROM BBP VGC Tuning.
*/
#define EEPROM_BBPTUNE_VGC 0x0034
#define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff)
#define EEPROM_BBPTUNE_VGCLOWER FIELD16(0xff00)
/*
* EEPROM BBP R17 Tuning.
*/
#define EEPROM_BBPTUNE_R17 0x0035
#define EEPROM_BBPTUNE_R17_LOW FIELD16(0x00ff)
#define EEPROM_BBPTUNE_R17_HIGH FIELD16(0xff00)
/*
* RSSI <-> dBm offset calibration
*/
#define EEPROM_CALIBRATE_OFFSET 0x0036
#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff)
/*
* DMA descriptor defines.
*/
#define TXD_DESC_SIZE ( 5 * sizeof(__le32) )
#define RXD_DESC_SIZE ( 4 * sizeof(__le32) )
/*
* TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
*/
/*
* Word0
*/
#define TXD_W0_PACKET_ID FIELD32(0x0000000f)
#define TXD_W0_RETRY_LIMIT FIELD32(0x000000f0)
#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
#define TXD_W0_ACK FIELD32(0x00000200)
#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
#define TXD_W0_OFDM FIELD32(0x00000800)
#define TXD_W0_NEW_SEQ FIELD32(0x00001000)
#define TXD_W0_IFS FIELD32(0x00006000)
#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
#define TXD_W0_CIPHER FIELD32(0x20000000)
#define TXD_W0_KEY_ID FIELD32(0xc0000000)
/*
* Word1
*/
#define TXD_W1_IV_OFFSET FIELD32(0x0000003f)
#define TXD_W1_AIFS FIELD32(0x000000c0)
#define TXD_W1_CWMIN FIELD32(0x00000f00)
#define TXD_W1_CWMAX FIELD32(0x0000f000)
/*
* Word2: PLCP information
*/
#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff)
#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00)
#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000)
/*
* Word3
*/
#define TXD_W3_IV FIELD32(0xffffffff)
/*
* Word4
*/
#define TXD_W4_EIV FIELD32(0xffffffff)
/*
* RX descriptor format for RX Ring.
*/
/*
* Word0
*/
#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
#define RXD_W0_MULTICAST FIELD32(0x00000004)
#define RXD_W0_BROADCAST FIELD32(0x00000008)
#define RXD_W0_MY_BSS FIELD32(0x00000010)
#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
#define RXD_W0_OFDM FIELD32(0x00000040)
#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
#define RXD_W0_CIPHER FIELD32(0x00000100)
#define RXD_W0_CIPHER_ERROR FIELD32(0x00000200)
#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
/*
* Word1
*/
#define RXD_W1_RSSI FIELD32(0x000000ff)
#define RXD_W1_SIGNAL FIELD32(0x0000ff00)
/*
* Word2
*/
#define RXD_W2_IV FIELD32(0xffffffff)
/*
* Word3
*/
#define RXD_W3_EIV FIELD32(0xffffffff)
/*
* Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
#define MAX_TXPOWER 31
#define DEFAULT_TXPOWER 24
#define TXPOWER_FROM_DEV(__txpower) \
(((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
#define TXPOWER_TO_DEV(__txpower) \
clamp_t(u8, __txpower, MIN_TXPOWER, MAX_TXPOWER)
#endif /* RT2500USB_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,276 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Bartlomiej Zolnierkiewicz
*/
#ifndef RT2800LIB_H
#define RT2800LIB_H
/*
* Hardware has 255 WCID table entries. First 32 entries are reserved for
* shared keys. Since parts of the pairwise key table might be shared with
* the beacon frame buffers 6 & 7 we could only use the first 222 entries.
*/
#define WCID_START 33
#define WCID_END 222
#define STA_IDS_SIZE (WCID_END - WCID_START + 2)
#define CHAIN_0 0x0
#define CHAIN_1 0x1
#define RF_ALC_NUM 6
#define CHAIN_NUM 2
struct rf_reg_pair {
u8 bank;
u8 reg;
u8 value;
};
/* RT2800 driver data structure */
struct rt2800_drv_data {
u8 calibration_bw20;
u8 calibration_bw40;
s8 rx_calibration_bw20;
s8 rx_calibration_bw40;
s8 tx_calibration_bw20;
s8 tx_calibration_bw40;
u8 bbp25;
u8 bbp26;
u8 txmixer_gain_24g;
u8 txmixer_gain_5g;
u8 max_psdu;
unsigned int tbtt_tick;
unsigned int ampdu_factor_cnt[4];
DECLARE_BITMAP(sta_ids, STA_IDS_SIZE);
struct ieee80211_sta *wcid_to_sta[STA_IDS_SIZE];
};
struct rt2800_ops {
u32 (*register_read)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset);
u32 (*register_read_lock)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset);
void (*register_write)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset, u32 value);
void (*register_write_lock)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset, u32 value);
void (*register_multiread)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u32 length);
void (*register_multiwrite)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const void *value, const u32 length);
int (*regbusy_read)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field, u32 *reg);
int (*read_eeprom)(struct rt2x00_dev *rt2x00dev);
bool (*hwcrypt_disabled)(struct rt2x00_dev *rt2x00dev);
int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
__le32 *(*drv_get_txwi)(struct queue_entry *entry);
unsigned int (*drv_get_dma_done)(struct data_queue *queue);
};
static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->register_read(rt2x00dev, offset);
}
static inline u32 rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->register_read_lock(rt2x00dev, offset);
}
static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_write(rt2x00dev, offset, value);
}
static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_write_lock(rt2x00dev, offset, value);
}
static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u32 length)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_multiread(rt2x00dev, offset, value, length);
}
static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const void *value,
const u32 length)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
rt2800ops->register_multiwrite(rt2x00dev, offset, value, length);
}
static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field,
u32 *reg)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg);
}
static inline int rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->read_eeprom(rt2x00dev);
}
static inline bool rt2800_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->hwcrypt_disabled(rt2x00dev);
}
static inline int rt2800_drv_write_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->drv_write_firmware(rt2x00dev, data, len);
}
static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
return rt2800ops->drv_init_registers(rt2x00dev);
}
static inline __le32 *rt2800_drv_get_txwi(struct queue_entry *entry)
{
const struct rt2800_ops *rt2800ops = entry->queue->rt2x00dev->ops->drv;
return rt2800ops->drv_get_txwi(entry);
}
static inline unsigned int rt2800_drv_get_dma_done(struct data_queue *queue)
{
const struct rt2800_ops *rt2800ops = queue->rt2x00dev->ops->drv;
return rt2800ops->drv_get_dma_done(queue);
}
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev);
int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev);
int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
void rt2800_write_tx_data(struct queue_entry *entry,
struct txentry_desc *txdesc);
void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
bool match);
void rt2800_txdone(struct rt2x00_dev *rt2x00dev, unsigned int quota);
void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev);
bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev);
bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev);
void rt2800_watchdog(struct rt2x00_dev *rt2x00dev);
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
void rt2800_clear_beacon(struct queue_entry *entry);
extern const struct rt2x00debug rt2800_rt2x00debug;
int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev);
int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
int rt2800_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int rt2800_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags);
void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
struct rt2x00intf_conf *conf, const unsigned int flags);
void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp,
u32 changed);
void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant);
void rt2800_config(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
const unsigned int flags);
void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
const u32 count);
void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev);
void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev);
int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
int rt2800_read_eeprom_nvmem(struct rt2x00_dev *rt2x00dev);
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
void rt2800_get_key_seq(struct ieee80211_hw *hw,
struct ieee80211_key_conf *key,
struct ieee80211_key_seq *seq);
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
u32 value);
int rt2800_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
unsigned int link_id, u16 queue_idx,
const struct ieee80211_tx_queue_params *params);
u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params);
int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey);
void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);
void rt2800_get_txwi_rxwi_size(struct rt2x00_dev *rt2x00dev,
unsigned short *txwi_size,
unsigned short *rxwi_size);
void rt2800_pre_reset_hw(struct rt2x00_dev *rt2x00dev);
#endif /* RT2800LIB_H */
@@ -0,0 +1,859 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
* Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
* Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
* Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
* Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
* Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
* Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com>
* <http://rt2x00.serialmonkey.com>
*/
/* Module: rt2800mmio
* Abstract: rt2800 MMIO device routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/export.h>
#include "rt2x00.h"
#include "rt2x00mmio.h"
#include "rt2800.h"
#include "rt2800lib.h"
#include "rt2800mmio.h"
unsigned int rt2800mmio_get_dma_done(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
struct queue_entry *entry;
int idx, qid;
switch (queue->qid) {
case QID_AC_VO:
case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
qid = queue->qid;
idx = rt2x00mmio_register_read(rt2x00dev, TX_DTX_IDX(qid));
break;
case QID_MGMT:
idx = rt2x00mmio_register_read(rt2x00dev, TX_DTX_IDX(5));
break;
case QID_RX:
entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
idx = entry->entry_idx;
break;
default:
WARN_ON_ONCE(1);
idx = 0;
break;
}
return idx;
}
EXPORT_SYMBOL_GPL(rt2800mmio_get_dma_done);
/*
* TX descriptor initialization
*/
__le32 *rt2800mmio_get_txwi(struct queue_entry *entry)
{
return (__le32 *) entry->skb->data;
}
EXPORT_SYMBOL_GPL(rt2800mmio_get_txwi);
void rt2800mmio_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
__le32 *txd = entry_priv->desc;
u32 word;
const unsigned int txwi_size = entry->queue->winfo_size;
/*
* The buffers pointed by SD_PTR0/SD_LEN0 and SD_PTR1/SD_LEN1
* must contains a TXWI structure + 802.11 header + padding + 802.11
* data. We choose to have SD_PTR0/SD_LEN0 only contains TXWI and
* SD_PTR1/SD_LEN1 contains 802.11 header + padding + 802.11
* data. It means that LAST_SEC0 is always 0.
*/
/*
* Initialize TX descriptor
*/
word = 0;
rt2x00_set_field32(&word, TXD_W0_SD_PTR0, skbdesc->skb_dma);
rt2x00_desc_write(txd, 0, word);
word = 0;
rt2x00_set_field32(&word, TXD_W1_SD_LEN1, entry->skb->len);
rt2x00_set_field32(&word, TXD_W1_LAST_SEC1,
!test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W1_BURST,
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W1_SD_LEN0, txwi_size);
rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0);
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
rt2x00_desc_write(txd, 1, word);
word = 0;
rt2x00_set_field32(&word, TXD_W2_SD_PTR1,
skbdesc->skb_dma + txwi_size);
rt2x00_desc_write(txd, 2, word);
word = 0;
rt2x00_set_field32(&word, TXD_W3_WIV,
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W3_QSEL, 2);
rt2x00_desc_write(txd, 3, word);
/*
* Register descriptor details in skb frame descriptor.
*/
skbdesc->desc = txd;
skbdesc->desc_len = TXD_DESC_SIZE;
}
EXPORT_SYMBOL_GPL(rt2800mmio_write_tx_desc);
/*
* RX control handlers
*/
void rt2800mmio_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
__le32 *rxd = entry_priv->desc;
u32 word;
word = rt2x00_desc_read(rxd, 3);
if (rt2x00_get_field32(word, RXD_W3_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
/*
* Unfortunately we don't know the cipher type used during
* decryption. This prevents us from correct providing
* correct statistics through debugfs.
*/
rxdesc->cipher_status = rt2x00_get_field32(word, RXD_W3_CIPHER_ERROR);
if (rt2x00_get_field32(word, RXD_W3_DECRYPTED)) {
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
* decryption. Unfortunately the descriptor doesn't contain
* any fields with the EIV/IV data either, so they can't
* be restored by rt2x00lib.
*/
rxdesc->flags |= RX_FLAG_IV_STRIPPED;
/*
* The hardware has already checked the Michael Mic and has
* stripped it from the frame. Signal this to mac80211.
*/
rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) {
rxdesc->flags |= RX_FLAG_DECRYPTED;
} else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) {
/*
* In order to check the Michael Mic, the packet must have
* been decrypted. Mac80211 doesnt check the MMIC failure
* flag to initiate MMIC countermeasures if the decoded flag
* has not been set.
*/
rxdesc->flags |= RX_FLAG_DECRYPTED;
rxdesc->flags |= RX_FLAG_MMIC_ERROR;
}
}
if (rt2x00_get_field32(word, RXD_W3_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
if (rt2x00_get_field32(word, RXD_W3_L2PAD))
rxdesc->dev_flags |= RXDONE_L2PAD;
/*
* Process the RXWI structure that is at the start of the buffer.
*/
rt2800_process_rxwi(entry, rxdesc);
}
EXPORT_SYMBOL_GPL(rt2800mmio_fill_rxdone);
/*
* Interrupt functions.
*/
static void rt2800mmio_wakeup(struct rt2x00_dev *rt2x00dev)
{
struct ieee80211_conf conf = { .flags = 0 };
struct rt2x00lib_conf libconf = { .conf = &conf };
rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev,
struct rt2x00_field32 irq_field)
{
u32 reg;
/*
* Enable a single interrupt. The interrupt mask register
* access needs locking.
*/
spin_lock_irq(&rt2x00dev->irqmask_lock);
reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR);
rt2x00_set_field32(&reg, irq_field, 1);
rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
void rt2800mmio_pretbtt_tasklet(struct tasklet_struct *t)
{
struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t,
pretbtt_tasklet);
rt2x00lib_pretbtt(rt2x00dev);
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2800mmio_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT);
}
EXPORT_SYMBOL_GPL(rt2800mmio_pretbtt_tasklet);
void rt2800mmio_tbtt_tasklet(struct tasklet_struct *t)
{
struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t, tbtt_tasklet);
struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
u32 reg;
rt2x00lib_beacondone(rt2x00dev);
if (rt2x00dev->intf_ap_count) {
/*
* The rt2800pci hardware tbtt timer is off by 1us per tbtt
* causing beacon skew and as a result causing problems with
* some powersaving clients over time. Shorten the beacon
* interval every 64 beacons by 64us to mitigate this effect.
*/
if (drv_data->tbtt_tick == (BCN_TBTT_OFFSET - 2)) {
reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
(rt2x00dev->beacon_int * 16) - 1);
rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg);
} else if (drv_data->tbtt_tick == (BCN_TBTT_OFFSET - 1)) {
reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
(rt2x00dev->beacon_int * 16));
rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg);
}
drv_data->tbtt_tick++;
drv_data->tbtt_tick %= BCN_TBTT_OFFSET;
}
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2800mmio_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT);
}
EXPORT_SYMBOL_GPL(rt2800mmio_tbtt_tasklet);
void rt2800mmio_rxdone_tasklet(struct tasklet_struct *t)
{
struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t,
rxdone_tasklet);
if (rt2x00mmio_rxdone(rt2x00dev))
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2800mmio_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
}
EXPORT_SYMBOL_GPL(rt2800mmio_rxdone_tasklet);
void rt2800mmio_autowake_tasklet(struct tasklet_struct *t)
{
struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t,
autowake_tasklet);
rt2800mmio_wakeup(rt2x00dev);
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2800mmio_enable_interrupt(rt2x00dev,
INT_MASK_CSR_AUTO_WAKEUP);
}
EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet);
static void rt2800mmio_fetch_txstatus(struct rt2x00_dev *rt2x00dev)
{
u32 status;
unsigned long flags;
/*
* The TX_FIFO_STATUS interrupt needs special care. We should
* read TX_STA_FIFO but we should do it immediately as otherwise
* the register can overflow and we would lose status reports.
*
* Hence, read the TX_STA_FIFO register and copy all tx status
* reports into a kernel FIFO which is handled in the txstatus
* tasklet. We use a tasklet to process the tx status reports
* because we can schedule the tasklet multiple times (when the
* interrupt fires again during tx status processing).
*
* We also read statuses from tx status timeout timer, use
* lock to prevent concurent writes to fifo.
*/
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
while (!kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
status = rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO);
if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
break;
kfifo_put(&rt2x00dev->txstatus_fifo, status);
}
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
}
void rt2800mmio_txstatus_tasklet(struct tasklet_struct *t)
{
struct rt2x00_dev *rt2x00dev = from_tasklet(rt2x00dev, t,
txstatus_tasklet);
rt2800_txdone(rt2x00dev, 16);
if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo))
tasklet_schedule(&rt2x00dev->txstatus_tasklet);
}
EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance)
{
struct rt2x00_dev *rt2x00dev = dev_instance;
u32 reg, mask;
/* Read status and ACK all interrupts */
reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR);
rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
if (!reg)
return IRQ_NONE;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return IRQ_HANDLED;
/*
* Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits
* for interrupts and interrupt masks we can just use the value of
* INT_SOURCE_CSR to create the interrupt mask.
*/
mask = ~reg;
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
rt2800mmio_fetch_txstatus(rt2x00dev);
if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo))
tasklet_schedule(&rt2x00dev->txstatus_tasklet);
}
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
tasklet_schedule(&rt2x00dev->autowake_tasklet);
/*
* Disable all interrupts for which a tasklet was scheduled right now,
* the tasklet will reenable the appropriate interrupts.
*/
spin_lock(&rt2x00dev->irqmask_lock);
reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR);
reg &= mask;
rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock(&rt2x00dev->irqmask_lock);
return IRQ_HANDLED;
}
EXPORT_SYMBOL_GPL(rt2800mmio_interrupt);
void rt2800mmio_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
u32 reg;
unsigned long flags;
/*
* When interrupts are being enabled, the interrupt registers
* should clear the register to assure a clean state.
*/
if (state == STATE_RADIO_IRQ_ON) {
reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR);
rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
}
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
reg = 0;
if (state == STATE_RADIO_IRQ_ON) {
rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, 1);
rt2x00_set_field32(&reg, INT_MASK_CSR_TBTT, 1);
rt2x00_set_field32(&reg, INT_MASK_CSR_PRE_TBTT, 1);
rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1);
rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, 1);
}
rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
if (state == STATE_RADIO_IRQ_OFF) {
/*
* Wait for possibly running tasklets to finish.
*/
tasklet_kill(&rt2x00dev->txstatus_tasklet);
tasklet_kill(&rt2x00dev->rxdone_tasklet);
tasklet_kill(&rt2x00dev->autowake_tasklet);
tasklet_kill(&rt2x00dev->tbtt_tasklet);
tasklet_kill(&rt2x00dev->pretbtt_tasklet);
}
}
EXPORT_SYMBOL_GPL(rt2800mmio_toggle_irq);
/*
* Queue handlers.
*/
void rt2800mmio_start_queue(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
u32 reg;
switch (queue->qid) {
case QID_RX:
reg = rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
break;
case QID_BEACON:
reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg);
reg = rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN);
rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 1);
rt2x00mmio_register_write(rt2x00dev, INT_TIMER_EN, reg);
break;
default:
break;
}
}
EXPORT_SYMBOL_GPL(rt2800mmio_start_queue);
/* 200 ms */
#define TXSTATUS_TIMEOUT 200000000
void rt2800mmio_kick_queue(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
struct queue_entry *entry;
switch (queue->qid) {
case QID_AC_VO:
case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
WARN_ON_ONCE(rt2x00queue_empty(queue));
entry = rt2x00queue_get_entry(queue, Q_INDEX);
rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX(queue->qid),
entry->entry_idx);
hrtimer_start(&rt2x00dev->txstatus_timer,
TXSTATUS_TIMEOUT, HRTIMER_MODE_REL);
break;
case QID_MGMT:
entry = rt2x00queue_get_entry(queue, Q_INDEX);
rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX(5),
entry->entry_idx);
break;
default:
break;
}
}
EXPORT_SYMBOL_GPL(rt2800mmio_kick_queue);
void rt2800mmio_flush_queue(struct data_queue *queue, bool drop)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
bool tx_queue = false;
unsigned int i;
switch (queue->qid) {
case QID_AC_VO:
case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
tx_queue = true;
break;
case QID_RX:
break;
default:
return;
}
for (i = 0; i < 5; i++) {
/*
* Check if the driver is already done, otherwise we
* have to sleep a little while to give the driver/hw
* the oppurtunity to complete interrupt process itself.
*/
if (rt2x00queue_empty(queue))
break;
/*
* For TX queues schedule completion tasklet to catch
* tx status timeouts, othewise just wait.
*/
if (tx_queue)
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
/*
* Wait for a little while to give the driver
* the oppurtunity to recover itself.
*/
msleep(50);
}
}
EXPORT_SYMBOL_GPL(rt2800mmio_flush_queue);
void rt2800mmio_stop_queue(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
u32 reg;
switch (queue->qid) {
case QID_RX:
reg = rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
break;
case QID_BEACON:
reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg);
reg = rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN);
rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 0);
rt2x00mmio_register_write(rt2x00dev, INT_TIMER_EN, reg);
/*
* Wait for current invocation to finish. The tasklet
* won't be scheduled anymore afterwards since we disabled
* the TBTT and PRE TBTT timer.
*/
tasklet_kill(&rt2x00dev->tbtt_tasklet);
tasklet_kill(&rt2x00dev->pretbtt_tasklet);
break;
default:
break;
}
}
EXPORT_SYMBOL_GPL(rt2800mmio_stop_queue);
void rt2800mmio_queue_init(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
unsigned short txwi_size, rxwi_size;
rt2800_get_txwi_rxwi_size(rt2x00dev, &txwi_size, &rxwi_size);
switch (queue->qid) {
case QID_RX:
queue->limit = 128;
queue->data_size = AGGREGATION_SIZE;
queue->desc_size = RXD_DESC_SIZE;
queue->winfo_size = rxwi_size;
queue->priv_size = sizeof(struct queue_entry_priv_mmio);
break;
case QID_AC_VO:
case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
queue->limit = 64;
queue->data_size = AGGREGATION_SIZE;
queue->desc_size = TXD_DESC_SIZE;
queue->winfo_size = txwi_size;
queue->priv_size = sizeof(struct queue_entry_priv_mmio);
break;
case QID_BEACON:
queue->limit = 8;
queue->data_size = 0; /* No DMA required for beacons */
queue->desc_size = TXD_DESC_SIZE;
queue->winfo_size = txwi_size;
queue->priv_size = sizeof(struct queue_entry_priv_mmio);
break;
case QID_ATIM:
default:
BUG();
break;
}
}
EXPORT_SYMBOL_GPL(rt2800mmio_queue_init);
/*
* Initialization functions.
*/
bool rt2800mmio_get_entry_state(struct queue_entry *entry)
{
struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
u32 word;
if (entry->queue->qid == QID_RX) {
word = rt2x00_desc_read(entry_priv->desc, 1);
return (!rt2x00_get_field32(word, RXD_W1_DMA_DONE));
} else {
word = rt2x00_desc_read(entry_priv->desc, 1);
return (!rt2x00_get_field32(word, TXD_W1_DMA_DONE));
}
}
EXPORT_SYMBOL_GPL(rt2800mmio_get_entry_state);
void rt2800mmio_clear_entry(struct queue_entry *entry)
{
struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
u32 word;
if (entry->queue->qid == QID_RX) {
word = rt2x00_desc_read(entry_priv->desc, 0);
rt2x00_set_field32(&word, RXD_W0_SDP0, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 0, word);
word = rt2x00_desc_read(entry_priv->desc, 1);
rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0);
rt2x00_desc_write(entry_priv->desc, 1, word);
/*
* Set RX IDX in register to inform hardware that we have
* handled this entry and it is available for reuse again.
*/
rt2x00mmio_register_write(rt2x00dev, RX_CRX_IDX,
entry->entry_idx);
} else {
word = rt2x00_desc_read(entry_priv->desc, 1);
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1);
rt2x00_desc_write(entry_priv->desc, 1, word);
/* If last entry stop txstatus timer */
if (entry->queue->length == 1)
hrtimer_cancel(&rt2x00dev->txstatus_timer);
}
}
EXPORT_SYMBOL_GPL(rt2800mmio_clear_entry);
int rt2800mmio_init_queues(struct rt2x00_dev *rt2x00dev)
{
struct queue_entry_priv_mmio *entry_priv;
/*
* Initialize registers.
*/
entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR0,
entry_priv->desc_dma);
rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT0,
rt2x00dev->tx[0].limit);
rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX0, 0);
rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX0, 0);
entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR1,
entry_priv->desc_dma);
rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT1,
rt2x00dev->tx[1].limit);
rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX1, 0);
rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX1, 0);
entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR2,
entry_priv->desc_dma);
rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT2,
rt2x00dev->tx[2].limit);
rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX2, 0);
rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX2, 0);
entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR3,
entry_priv->desc_dma);
rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT3,
rt2x00dev->tx[3].limit);
rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX3, 0);
rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX3, 0);
rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR4, 0);
rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT4, 0);
rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX4, 0);
rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX4, 0);
rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR5, 0);
rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT5, 0);
rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX5, 0);
rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX5, 0);
entry_priv = rt2x00dev->rx->entries[0].priv_data;
rt2x00mmio_register_write(rt2x00dev, RX_BASE_PTR,
entry_priv->desc_dma);
rt2x00mmio_register_write(rt2x00dev, RX_MAX_CNT,
rt2x00dev->rx[0].limit);
rt2x00mmio_register_write(rt2x00dev, RX_CRX_IDX,
rt2x00dev->rx[0].limit - 1);
rt2x00mmio_register_write(rt2x00dev, RX_DRX_IDX, 0);
rt2800_disable_wpdma(rt2x00dev);
rt2x00mmio_register_write(rt2x00dev, DELAY_INT_CFG, 0);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800mmio_init_queues);
int rt2800mmio_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
/*
* Reset DMA indexes
*/
reg = rt2x00mmio_register_read(rt2x00dev, WPDMA_RST_IDX);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
rt2x00mmio_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
if (rt2x00_is_pcie(rt2x00dev) &&
(rt2x00_rt(rt2x00dev, RT3090) ||
rt2x00_rt(rt2x00dev, RT3390) ||
rt2x00_rt(rt2x00dev, RT3572) ||
rt2x00_rt(rt2x00dev, RT3593) ||
rt2x00_rt(rt2x00dev, RT5390) ||
rt2x00_rt(rt2x00dev, RT5392) ||
rt2x00_rt(rt2x00dev, RT5592))) {
reg = rt2x00mmio_register_read(rt2x00dev, AUX_CTRL);
rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
rt2x00mmio_register_write(rt2x00dev, AUX_CTRL, reg);
}
rt2x00mmio_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
if (rt2x00_rt(rt2x00dev, RT6352))
return 0;
reg = 0;
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800mmio_init_registers);
/*
* Device state switch handlers.
*/
int rt2800mmio_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/* Wait for DMA, ignore error until we initialize queues. */
rt2800_wait_wpdma_ready(rt2x00dev);
if (unlikely(rt2800mmio_init_queues(rt2x00dev)))
return -EIO;
return rt2800_enable_radio(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2800mmio_enable_radio);
static void rt2800mmio_work_txdone(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, txdone_work);
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
rt2800_txstatus_timeout(rt2x00dev)) {
tasklet_disable(&rt2x00dev->txstatus_tasklet);
rt2800_txdone(rt2x00dev, UINT_MAX);
rt2800_txdone_nostatus(rt2x00dev);
tasklet_enable(&rt2x00dev->txstatus_tasklet);
}
if (rt2800_txstatus_pending(rt2x00dev))
hrtimer_start(&rt2x00dev->txstatus_timer,
TXSTATUS_TIMEOUT, HRTIMER_MODE_REL);
}
static enum hrtimer_restart rt2800mmio_tx_sta_fifo_timeout(struct hrtimer *timer)
{
struct rt2x00_dev *rt2x00dev =
container_of(timer, struct rt2x00_dev, txstatus_timer);
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
goto out;
if (!rt2800_txstatus_pending(rt2x00dev))
goto out;
rt2800mmio_fetch_txstatus(rt2x00dev);
if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo))
tasklet_schedule(&rt2x00dev->txstatus_tasklet);
else
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
out:
return HRTIMER_NORESTART;
}
int rt2800mmio_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
retval = rt2800_probe_hw(rt2x00dev);
if (retval)
return retval;
/*
* Set txstatus timer function.
*/
hrtimer_update_function(&rt2x00dev->txstatus_timer, rt2800mmio_tx_sta_fifo_timeout);
/*
* Overwrite TX done handler
*/
INIT_WORK(&rt2x00dev->txdone_work, rt2800mmio_work_txdone);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800mmio_probe_hw);
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("rt2800 MMIO library");
MODULE_LICENSE("GPL");
@@ -0,0 +1,155 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
* Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
* Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
* Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
* Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
* Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
* Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com>
* <http://rt2x00.serialmonkey.com>
*/
/* Module: rt2800mmio
* Abstract: forward declarations for the rt2800mmio module.
*/
#ifndef RT2800MMIO_H
#define RT2800MMIO_H
/*
* Queue register offset macros
*/
#define TX_QUEUE_REG_OFFSET 0x10
#define TX_BASE_PTR(__x) (TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET))
#define TX_MAX_CNT(__x) (TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET))
#define TX_CTX_IDX(__x) (TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET))
#define TX_DTX_IDX(__x) (TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET))
/*
* DMA descriptor defines.
*/
#define TXD_DESC_SIZE (4 * sizeof(__le32))
#define RXD_DESC_SIZE (4 * sizeof(__le32))
/*
* TX descriptor format for TX, PRIO and Beacon Ring.
*/
/*
* Word0
*/
#define TXD_W0_SD_PTR0 FIELD32(0xffffffff)
/*
* Word1
*/
#define TXD_W1_SD_LEN1 FIELD32(0x00003fff)
#define TXD_W1_LAST_SEC1 FIELD32(0x00004000)
#define TXD_W1_BURST FIELD32(0x00008000)
#define TXD_W1_SD_LEN0 FIELD32(0x3fff0000)
#define TXD_W1_LAST_SEC0 FIELD32(0x40000000)
#define TXD_W1_DMA_DONE FIELD32(0x80000000)
/*
* Word2
*/
#define TXD_W2_SD_PTR1 FIELD32(0xffffffff)
/*
* Word3
* WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI
* QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler.
* 0:MGMT, 1:HCCA 2:EDCA
*/
#define TXD_W3_WIV FIELD32(0x01000000)
#define TXD_W3_QSEL FIELD32(0x06000000)
#define TXD_W3_TCO FIELD32(0x20000000)
#define TXD_W3_UCO FIELD32(0x40000000)
#define TXD_W3_ICO FIELD32(0x80000000)
/*
* RX descriptor format for RX Ring.
*/
/*
* Word0
*/
#define RXD_W0_SDP0 FIELD32(0xffffffff)
/*
* Word1
*/
#define RXD_W1_SDL1 FIELD32(0x00003fff)
#define RXD_W1_SDL0 FIELD32(0x3fff0000)
#define RXD_W1_LS0 FIELD32(0x40000000)
#define RXD_W1_DMA_DONE FIELD32(0x80000000)
/*
* Word2
*/
#define RXD_W2_SDP1 FIELD32(0xffffffff)
/*
* Word3
* AMSDU: RX with 802.3 header, not 802.11 header.
* DECRYPTED: This frame is being decrypted.
*/
#define RXD_W3_BA FIELD32(0x00000001)
#define RXD_W3_DATA FIELD32(0x00000002)
#define RXD_W3_NULLDATA FIELD32(0x00000004)
#define RXD_W3_FRAG FIELD32(0x00000008)
#define RXD_W3_UNICAST_TO_ME FIELD32(0x00000010)
#define RXD_W3_MULTICAST FIELD32(0x00000020)
#define RXD_W3_BROADCAST FIELD32(0x00000040)
#define RXD_W3_MY_BSS FIELD32(0x00000080)
#define RXD_W3_CRC_ERROR FIELD32(0x00000100)
#define RXD_W3_CIPHER_ERROR FIELD32(0x00000600)
#define RXD_W3_AMSDU FIELD32(0x00000800)
#define RXD_W3_HTC FIELD32(0x00001000)
#define RXD_W3_RSSI FIELD32(0x00002000)
#define RXD_W3_L2PAD FIELD32(0x00004000)
#define RXD_W3_AMPDU FIELD32(0x00008000)
#define RXD_W3_DECRYPTED FIELD32(0x00010000)
#define RXD_W3_PLCP_SIGNAL FIELD32(0x00020000)
#define RXD_W3_PLCP_RSSI FIELD32(0x00040000)
unsigned int rt2800mmio_get_dma_done(struct data_queue *queue);
/* TX descriptor initialization */
__le32 *rt2800mmio_get_txwi(struct queue_entry *entry);
void rt2800mmio_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc);
/* RX control handlers */
void rt2800mmio_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc);
/* Interrupt functions */
void rt2800mmio_txstatus_tasklet(struct tasklet_struct *t);
void rt2800mmio_pretbtt_tasklet(struct tasklet_struct *t);
void rt2800mmio_tbtt_tasklet(struct tasklet_struct *t);
void rt2800mmio_rxdone_tasklet(struct tasklet_struct *t);
void rt2800mmio_autowake_tasklet(struct tasklet_struct *t);
irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance);
void rt2800mmio_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state);
/* Queue handlers */
void rt2800mmio_start_queue(struct data_queue *queue);
void rt2800mmio_kick_queue(struct data_queue *queue);
void rt2800mmio_flush_queue(struct data_queue *queue, bool drop);
void rt2800mmio_stop_queue(struct data_queue *queue);
void rt2800mmio_queue_init(struct data_queue *queue);
/* Initialization functions */
int rt2800mmio_probe_hw(struct rt2x00_dev *rt2x00dev);
bool rt2800mmio_get_entry_state(struct queue_entry *entry);
void rt2800mmio_clear_entry(struct queue_entry *entry);
int rt2800mmio_init_queues(struct rt2x00_dev *rt2x00dev);
int rt2800mmio_init_registers(struct rt2x00_dev *rt2x00dev);
/* Device state switch handlers. */
int rt2800mmio_enable_radio(struct rt2x00_dev *rt2x00dev);
#endif /* RT2800MMIO_H */
@@ -0,0 +1,468 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2800pci
Abstract: rt2800pci device specific routines.
Supported chipsets: RT2800E & RT2800ED.
*/
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/eeprom_93cx6.h>
#include "rt2x00.h"
#include "rt2x00mmio.h"
#include "rt2x00pci.h"
#include "rt2800lib.h"
#include "rt2800mmio.h"
#include "rt2800.h"
#include "rt2800pci.h"
/*
* Allow hardware encryption to be disabled.
*/
static bool modparam_nohwcrypt = false;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static bool rt2800pci_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev)
{
return modparam_nohwcrypt;
}
static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
{
unsigned int i;
u32 reg;
/*
* SOC devices don't support MCU requests.
*/
if (rt2x00_is_soc(rt2x00dev))
return;
for (i = 0; i < 200; i++) {
reg = rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID);
if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) ||
(rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) ||
(rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD2) == token) ||
(rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD3) == token))
break;
udelay(REGISTER_BUSY_DELAY);
}
if (i == 200)
rt2x00_err(rt2x00dev, "MCU request failed, no response from hardware\n");
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
}
static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
{
struct rt2x00_dev *rt2x00dev = eeprom->data;
u32 reg;
reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR);
eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
eeprom->reg_data_clock =
!!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK);
eeprom->reg_chip_select =
!!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT);
}
static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
{
struct rt2x00_dev *rt2x00dev = eeprom->data;
u32 reg = 0;
rt2x00_set_field32(&reg, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in);
rt2x00_set_field32(&reg, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out);
rt2x00_set_field32(&reg, E2PROM_CSR_DATA_CLOCK,
!!eeprom->reg_data_clock);
rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
!!eeprom->reg_chip_select);
rt2x00mmio_register_write(rt2x00dev, E2PROM_CSR, reg);
}
static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
{
struct eeprom_93cx6 eeprom = {};
u32 reg;
reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR);
eeprom.data = rt2x00dev;
eeprom.register_read = rt2800pci_eepromregister_read;
eeprom.register_write = rt2800pci_eepromregister_write;
switch (rt2x00_get_field32(reg, E2PROM_CSR_TYPE))
{
case 0:
eeprom.width = PCI_EEPROM_WIDTH_93C46;
break;
case 1:
eeprom.width = PCI_EEPROM_WIDTH_93C66;
break;
default:
eeprom.width = PCI_EEPROM_WIDTH_93C86;
break;
}
eeprom.reg_data_in = 0;
eeprom.reg_data_out = 0;
eeprom.reg_data_clock = 0;
eeprom.reg_chip_select = 0;
eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
EEPROM_SIZE / sizeof(u16));
return 0;
}
static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
{
return rt2800_efuse_detect(rt2x00dev);
}
static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
{
return rt2800_read_eeprom_efuse(rt2x00dev);
}
/*
* Firmware functions
*/
static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
{
/*
* Chip rt3290 use specific 4KB firmware named rt3290.bin.
*/
if (rt2x00_rt(rt2x00dev, RT3290))
return FIRMWARE_RT3290;
else
return FIRMWARE_RT2860;
}
static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
u32 reg;
/*
* enable Host program ram write selection
*/
reg = 0;
rt2x00_set_field32(&reg, PBF_SYS_CTRL_HOST_RAM_WRITE, 1);
rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
/*
* Write firmware to device.
*/
rt2x00mmio_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
data, len);
rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
rt2x00mmio_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
return 0;
}
/*
* Device state switch handlers.
*/
static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
{
int retval;
retval = rt2800mmio_enable_radio(rt2x00dev);
if (retval)
return retval;
/* After resume MCU_BOOT_SIGNAL will trash these. */
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, 0xff, 0x02);
rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF);
rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, 0, 0);
rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
return retval;
}
static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
if (state == STATE_AWAKE) {
rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP,
0, 0x02);
rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
} else if (state == STATE_SLEEP) {
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
0xffffffff);
rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID,
0xffffffff);
rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP,
0xff, 0x01);
}
return 0;
}
static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
int retval = 0;
switch (state) {
case STATE_RADIO_ON:
retval = rt2800pci_enable_radio(rt2x00dev);
break;
case STATE_RADIO_OFF:
/*
* After the radio has been disabled, the device should
* be put to sleep for powersaving.
*/
rt2800pci_set_state(rt2x00dev, STATE_SLEEP);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_OFF:
rt2800mmio_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
case STATE_SLEEP:
case STATE_STANDBY:
case STATE_AWAKE:
retval = rt2800pci_set_state(rt2x00dev, state);
break;
default:
retval = -ENOTSUPP;
break;
}
if (unlikely(retval))
rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
state, retval);
return retval;
}
/*
* Device probe functions.
*/
static int rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev)
{
int retval;
if (!rt2800_read_eeprom_nvmem(rt2x00dev))
return 0;
if (rt2800pci_efuse_detect(rt2x00dev))
retval = rt2800pci_read_eeprom_efuse(rt2x00dev);
else
retval = rt2800pci_read_eeprom_pci(rt2x00dev);
return retval;
}
static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.add_chanctx = ieee80211_emulate_add_chanctx,
.remove_chanctx = ieee80211_emulate_remove_chanctx,
.change_chanctx = ieee80211_emulate_change_chanctx,
.switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
.tx = rt2x00mac_tx,
.wake_tx_queue = ieee80211_handle_wake_tx_queue,
.start = rt2x00mac_start,
.stop = rt2x00mac_stop,
.add_interface = rt2x00mac_add_interface,
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
.set_key = rt2x00mac_set_key,
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.get_key_seq = rt2800_get_key_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.sta_add = rt2800_sta_add,
.sta_remove = rt2800_sta_remove,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2800_conf_tx,
.get_tsf = rt2800_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
.flush = rt2x00mac_flush,
.get_survey = rt2800_get_survey,
.get_ringparam = rt2x00mac_get_ringparam,
.tx_frames_pending = rt2x00mac_tx_frames_pending,
.reconfig_complete = rt2x00mac_reconfig_complete,
};
static const struct rt2800_ops rt2800pci_rt2800_ops = {
.register_read = rt2x00mmio_register_read,
.register_read_lock = rt2x00mmio_register_read, /* same for PCI */
.register_write = rt2x00mmio_register_write,
.register_write_lock = rt2x00mmio_register_write, /* same for PCI */
.register_multiread = rt2x00mmio_register_multiread,
.register_multiwrite = rt2x00mmio_register_multiwrite,
.regbusy_read = rt2x00mmio_regbusy_read,
.read_eeprom = rt2800pci_read_eeprom,
.hwcrypt_disabled = rt2800pci_hwcrypt_disabled,
.drv_write_firmware = rt2800pci_write_firmware,
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
.drv_get_dma_done = rt2800mmio_get_dma_done,
};
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.irq_handler = rt2800mmio_interrupt,
.txstatus_tasklet = rt2800mmio_txstatus_tasklet,
.pretbtt_tasklet = rt2800mmio_pretbtt_tasklet,
.tbtt_tasklet = rt2800mmio_tbtt_tasklet,
.rxdone_tasklet = rt2800mmio_rxdone_tasklet,
.autowake_tasklet = rt2800mmio_autowake_tasklet,
.probe_hw = rt2800mmio_probe_hw,
.get_firmware_name = rt2800pci_get_firmware_name,
.check_firmware = rt2800_check_firmware,
.load_firmware = rt2800_load_firmware,
.initialize = rt2x00mmio_initialize,
.uninitialize = rt2x00mmio_uninitialize,
.get_entry_state = rt2800mmio_get_entry_state,
.clear_entry = rt2800mmio_clear_entry,
.set_device_state = rt2800pci_set_device_state,
.rfkill_poll = rt2800_rfkill_poll,
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
.watchdog = rt2800_watchdog,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
.flush_queue = rt2800mmio_flush_queue,
.write_tx_desc = rt2800mmio_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
.clear_beacon = rt2800_clear_beacon,
.fill_rxdone = rt2800mmio_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
.config_filter = rt2800_config_filter,
.config_intf = rt2800_config_intf,
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
.pre_reset_hw = rt2800_pre_reset_hw,
};
static const struct rt2x00_ops rt2800pci_ops = {
.name = KBUILD_MODNAME,
.drv_data_size = sizeof(struct rt2800_drv_data),
.max_ap_intf = 8,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.queue_init = rt2800mmio_queue_init,
.lib = &rt2800pci_rt2x00_ops,
.drv = &rt2800pci_rt2800_ops,
.hw = &rt2800pci_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};
/*
* RT2800pci module information.
*/
static const struct pci_device_id rt2800pci_device_table[] = {
{ PCI_DEVICE(0x1814, 0x0601) },
{ PCI_DEVICE(0x1814, 0x0681) },
{ PCI_DEVICE(0x1814, 0x0701) },
{ PCI_DEVICE(0x1814, 0x0781) },
{ PCI_DEVICE(0x1814, 0x3090) },
{ PCI_DEVICE(0x1814, 0x3091) },
{ PCI_DEVICE(0x1814, 0x3092) },
{ PCI_DEVICE(0x1432, 0x7708) },
{ PCI_DEVICE(0x1432, 0x7727) },
{ PCI_DEVICE(0x1432, 0x7728) },
{ PCI_DEVICE(0x1432, 0x7738) },
{ PCI_DEVICE(0x1432, 0x7748) },
{ PCI_DEVICE(0x1432, 0x7758) },
{ PCI_DEVICE(0x1432, 0x7768) },
{ PCI_DEVICE(0x1462, 0x891a) },
{ PCI_DEVICE(0x1a3b, 0x1059) },
#ifdef CONFIG_RT2800PCI_RT3290
{ PCI_DEVICE(0x1814, 0x3290) },
#endif
#ifdef CONFIG_RT2800PCI_RT33XX
{ PCI_DEVICE(0x1814, 0x3390) },
#endif
#ifdef CONFIG_RT2800PCI_RT35XX
{ PCI_DEVICE(0x1432, 0x7711) },
{ PCI_DEVICE(0x1432, 0x7722) },
{ PCI_DEVICE(0x1814, 0x3060) },
{ PCI_DEVICE(0x1814, 0x3062) },
{ PCI_DEVICE(0x1814, 0x3562) },
{ PCI_DEVICE(0x1814, 0x3592) },
{ PCI_DEVICE(0x1814, 0x3593) },
{ PCI_DEVICE(0x1814, 0x359f) },
#endif
#ifdef CONFIG_RT2800PCI_RT53XX
{ PCI_DEVICE(0x1814, 0x5360) },
{ PCI_DEVICE(0x1814, 0x5362) },
{ PCI_DEVICE(0x1814, 0x5390) },
{ PCI_DEVICE(0x1814, 0x5392) },
{ PCI_DEVICE(0x1814, 0x539a) },
{ PCI_DEVICE(0x1814, 0x539b) },
{ PCI_DEVICE(0x1814, 0x539f) },
#endif
{ 0, }
};
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Ralink RT2800 PCI & PCMCIA Wireless LAN driver.");
MODULE_FIRMWARE(FIRMWARE_RT2860);
MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
MODULE_LICENSE("GPL");
static int rt2800pci_probe(struct pci_dev *pci_dev,
const struct pci_device_id *id)
{
return rt2x00pci_probe(pci_dev, &rt2800pci_ops);
}
static struct pci_driver rt2800pci_driver = {
.name = KBUILD_MODNAME,
.id_table = rt2800pci_device_table,
.probe = rt2800pci_probe,
.remove = rt2x00pci_remove,
.driver.pm = &rt2x00pci_pm_ops,
};
module_pci_driver(rt2800pci_driver);
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2800pci
Abstract: Data structures and registers for the rt2800pci module.
Supported chipsets: RT2800E & RT2800ED.
*/
#ifndef RT2800PCI_H
#define RT2800PCI_H
/*
* 8051 firmware image.
*/
#define FIRMWARE_RT2860 "rt2860.bin"
#define FIRMWARE_RT3290 "rt3290.bin"
#define FIRMWARE_IMAGE_BASE 0x2000
#endif /* RT2800PCI_H */
@@ -0,0 +1,366 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
* Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
* Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
* Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
* Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
* Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
* Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com>
* <http://rt2x00.serialmonkey.com>
*/
/* Module: rt2800soc
* Abstract: rt2800 WiSoC specific routines.
*/
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include "rt2x00.h"
#include "rt2x00mmio.h"
#include "rt2800.h"
#include "rt2800lib.h"
#include "rt2800mmio.h"
/* Allow hardware encryption to be disabled. */
static bool modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static bool rt2800soc_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev)
{
return modparam_nohwcrypt;
}
static void rt2800soc_disable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt2800_disable_radio(rt2x00dev);
rt2x00mmio_register_write(rt2x00dev, PWR_PIN_CFG, 0);
reg = 0;
if (rt2x00_rt(rt2x00dev, RT3883))
rt2x00_set_field32(&reg, TX_PIN_CFG_RFTR_EN, 1);
rt2x00mmio_register_write(rt2x00dev, TX_PIN_CFG, reg);
}
static int rt2800soc_set_device_state(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
int retval = 0;
switch (state) {
case STATE_RADIO_ON:
retval = rt2800mmio_enable_radio(rt2x00dev);
break;
case STATE_RADIO_OFF:
rt2800soc_disable_radio(rt2x00dev);
break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_OFF:
rt2800mmio_toggle_irq(rt2x00dev, state);
break;
case STATE_DEEP_SLEEP:
case STATE_SLEEP:
case STATE_STANDBY:
case STATE_AWAKE:
/* These states are not supported, but don't report an error */
retval = 0;
break;
default:
retval = -ENOTSUPP;
break;
}
if (unlikely(retval))
rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
state, retval);
return retval;
}
static int rt2800soc_read_eeprom(struct rt2x00_dev *rt2x00dev)
{
void __iomem *base_addr;
if (!rt2800_read_eeprom_nvmem(rt2x00dev))
return 0;
base_addr = ioremap(0x1F040000, EEPROM_SIZE);
if (!base_addr)
return -ENOMEM;
memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
iounmap(base_addr);
return 0;
}
/* Firmware functions */
static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev)
{
WARN_ON_ONCE(1);
return NULL;
}
static int rt2800soc_load_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
WARN_ON_ONCE(1);
return 0;
}
static int rt2800soc_check_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
WARN_ON_ONCE(1);
return 0;
}
static int rt2800soc_write_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len)
{
WARN_ON_ONCE(1);
return 0;
}
#ifdef CONFIG_PM
static int rt2800soc_suspend(struct platform_device *pdev, pm_message_t state)
{
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
struct rt2x00_dev *rt2x00dev = hw->priv;
return rt2x00lib_suspend(rt2x00dev);
}
static int rt2800soc_resume(struct platform_device *pdev)
{
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
struct rt2x00_dev *rt2x00dev = hw->priv;
return rt2x00lib_resume(rt2x00dev);
}
#endif /* CONFIG_PM */
static const struct ieee80211_ops rt2800soc_mac80211_ops = {
.add_chanctx = ieee80211_emulate_add_chanctx,
.remove_chanctx = ieee80211_emulate_remove_chanctx,
.change_chanctx = ieee80211_emulate_change_chanctx,
.switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
.tx = rt2x00mac_tx,
.wake_tx_queue = ieee80211_handle_wake_tx_queue,
.start = rt2x00mac_start,
.stop = rt2x00mac_stop,
.add_interface = rt2x00mac_add_interface,
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
.set_key = rt2x00mac_set_key,
.sw_scan_start = rt2x00mac_sw_scan_start,
.sw_scan_complete = rt2x00mac_sw_scan_complete,
.get_stats = rt2x00mac_get_stats,
.get_key_seq = rt2800_get_key_seq,
.set_rts_threshold = rt2800_set_rts_threshold,
.sta_add = rt2800_sta_add,
.sta_remove = rt2800_sta_remove,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2800_conf_tx,
.get_tsf = rt2800_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
.flush = rt2x00mac_flush,
.get_survey = rt2800_get_survey,
.get_ringparam = rt2x00mac_get_ringparam,
.tx_frames_pending = rt2x00mac_tx_frames_pending,
.reconfig_complete = rt2x00mac_reconfig_complete,
};
static const struct rt2800_ops rt2800soc_rt2800_ops = {
.register_read = rt2x00mmio_register_read,
.register_read_lock = rt2x00mmio_register_read, /* same for SoCs */
.register_write = rt2x00mmio_register_write,
.register_write_lock = rt2x00mmio_register_write, /* same for SoCs */
.register_multiread = rt2x00mmio_register_multiread,
.register_multiwrite = rt2x00mmio_register_multiwrite,
.regbusy_read = rt2x00mmio_regbusy_read,
.read_eeprom = rt2800soc_read_eeprom,
.hwcrypt_disabled = rt2800soc_hwcrypt_disabled,
.drv_write_firmware = rt2800soc_write_firmware,
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
.drv_get_dma_done = rt2800mmio_get_dma_done,
};
static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
.irq_handler = rt2800mmio_interrupt,
.txstatus_tasklet = rt2800mmio_txstatus_tasklet,
.pretbtt_tasklet = rt2800mmio_pretbtt_tasklet,
.tbtt_tasklet = rt2800mmio_tbtt_tasklet,
.rxdone_tasklet = rt2800mmio_rxdone_tasklet,
.autowake_tasklet = rt2800mmio_autowake_tasklet,
.probe_hw = rt2800mmio_probe_hw,
.get_firmware_name = rt2800soc_get_firmware_name,
.check_firmware = rt2800soc_check_firmware,
.load_firmware = rt2800soc_load_firmware,
.initialize = rt2x00mmio_initialize,
.uninitialize = rt2x00mmio_uninitialize,
.get_entry_state = rt2800mmio_get_entry_state,
.clear_entry = rt2800mmio_clear_entry,
.set_device_state = rt2800soc_set_device_state,
.rfkill_poll = rt2800_rfkill_poll,
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
.watchdog = rt2800_watchdog,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
.flush_queue = rt2800mmio_flush_queue,
.write_tx_desc = rt2800mmio_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
.clear_beacon = rt2800_clear_beacon,
.fill_rxdone = rt2800mmio_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
.config_filter = rt2800_config_filter,
.config_intf = rt2800_config_intf,
.config_erp = rt2800_config_erp,
.config_ant = rt2800_config_ant,
.config = rt2800_config,
.pre_reset_hw = rt2800_pre_reset_hw,
};
static const struct rt2x00_ops rt2800soc_ops = {
.name = KBUILD_MODNAME,
.drv_data_size = sizeof(struct rt2800_drv_data),
.max_ap_intf = 8,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.queue_init = rt2800mmio_queue_init,
.lib = &rt2800soc_rt2x00_ops,
.drv = &rt2800soc_rt2800_ops,
.hw = &rt2800soc_mac80211_ops,
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
.debugfs = &rt2800_rt2x00debug,
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};
static int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops)
{
struct rt2x00_dev *rt2x00dev;
struct ieee80211_hw *hw;
void __iomem *mem;
struct clk *clk;
__le16 *eeprom;
int retval;
u32 *rf;
int irq;
mem = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mem))
return PTR_ERR(mem);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
clk = devm_clk_get_optional(&pdev->dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
eeprom = devm_kzalloc(&pdev->dev, ops->eeprom_size, GFP_KERNEL);
if (!eeprom)
return -ENOMEM;
rf = devm_kzalloc(&pdev->dev, ops->rf_size, GFP_KERNEL);
if (!rf)
return -ENOMEM;
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw)
return dev_err_probe(&pdev->dev, -ENOMEM, "Failed to allocate hardware");
platform_set_drvdata(pdev, hw);
rt2x00dev = hw->priv;
rt2x00dev->dev = &pdev->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
rt2x00dev->irq = irq;
rt2x00dev->clk = clk;
rt2x00dev->eeprom = eeprom;
rt2x00dev->rf = rf;
rt2x00dev->name = pdev->dev.driver->name;
rt2x00dev->csr.base = mem;
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
retval = rt2x00lib_probe_dev(rt2x00dev);
if (retval)
goto exit_free_device;
return 0;
exit_free_device:
ieee80211_free_hw(hw);
return retval;
}
static int rt2800soc_probe(struct platform_device *pdev)
{
return rt2x00soc_probe(pdev, &rt2800soc_ops);
}
static void rt2800soc_remove(struct platform_device *pdev)
{
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* Free all allocated data.
*/
rt2x00lib_remove_dev(rt2x00dev);
ieee80211_free_hw(hw);
}
static const struct of_device_id rt2880_wmac_match[] = {
{ .compatible = "ralink,rt2880-wifi" },
{},
};
MODULE_DEVICE_TABLE(of, rt2880_wmac_match);
static struct platform_driver rt2800soc_driver = {
.driver = {
.name = "rt2800_wmac",
.of_match_table = rt2880_wmac_match,
},
.probe = rt2800soc_probe,
.remove = rt2800soc_remove,
#ifdef CONFIG_PM
.suspend = rt2800soc_suspend,
.resume = rt2800soc_resume,
#endif
};
module_platform_driver(rt2800soc_driver);
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Ralink WiSoC Wireless LAN driver.");
MODULE_LICENSE("GPL");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,99 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
Copyright (C) 2009 Axel Kollhofer <rain_maker@root-forum.org>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2800usb
Abstract: Data structures and registers for the rt2800usb module.
Supported chipsets: RT2800U.
*/
#ifndef RT2800USB_H
#define RT2800USB_H
/*
* 8051 firmware image.
*/
#define FIRMWARE_RT2870 "rt2870.bin"
#define FIRMWARE_IMAGE_BASE 0x3000
/*
* DMA descriptor defines.
*/
#define TXINFO_DESC_SIZE (1 * sizeof(__le32))
#define RXINFO_DESC_SIZE (1 * sizeof(__le32))
/*
* TX Info structure
*/
/*
* Word0
* WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI
* QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler.
* 0:MGMT, 1:HCCA 2:EDCA
* USB_DMA_NEXT_VALID: Used ONLY in USB bulk Aggregation, NextValid
* DMA_TX_BURST: used ONLY in USB bulk Aggregation.
* Force USB DMA transmit frame from current selected endpoint
*/
#define TXINFO_W0_USB_DMA_TX_PKT_LEN FIELD32(0x0000ffff)
#define TXINFO_W0_WIV FIELD32(0x01000000)
#define TXINFO_W0_QSEL FIELD32(0x06000000)
#define TXINFO_W0_SW_USE_LAST_ROUND FIELD32(0x08000000)
#define TXINFO_W0_USB_DMA_NEXT_VALID FIELD32(0x40000000)
#define TXINFO_W0_USB_DMA_TX_BURST FIELD32(0x80000000)
/*
* RX Info structure
*/
/*
* Word 0
*/
#define RXINFO_W0_USB_DMA_RX_PKT_LEN FIELD32(0x0000ffff)
/*
* RX descriptor format for RX Ring.
*/
/*
* Word0
* UNICAST_TO_ME: This RX frame is unicast to me.
* MULTICAST: This is a multicast frame.
* BROADCAST: This is a broadcast frame.
* MY_BSS: this frame belongs to the same BSSID.
* CRC_ERROR: CRC error.
* CIPHER_ERROR: 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid.
* AMSDU: rx with 802.3 header, not 802.11 header.
*/
#define RXD_W0_BA FIELD32(0x00000001)
#define RXD_W0_DATA FIELD32(0x00000002)
#define RXD_W0_NULLDATA FIELD32(0x00000004)
#define RXD_W0_FRAG FIELD32(0x00000008)
#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010)
#define RXD_W0_MULTICAST FIELD32(0x00000020)
#define RXD_W0_BROADCAST FIELD32(0x00000040)
#define RXD_W0_MY_BSS FIELD32(0x00000080)
#define RXD_W0_CRC_ERROR FIELD32(0x00000100)
#define RXD_W0_CIPHER_ERROR FIELD32(0x00000600)
#define RXD_W0_AMSDU FIELD32(0x00000800)
#define RXD_W0_HTC FIELD32(0x00001000)
#define RXD_W0_RSSI FIELD32(0x00002000)
#define RXD_W0_L2PAD FIELD32(0x00004000)
#define RXD_W0_AMPDU FIELD32(0x00008000)
#define RXD_W0_DECRYPTED FIELD32(0x00010000)
#define RXD_W0_PLCP_RSSI FIELD32(0x00020000)
#define RXD_W0_CIPHER_ALG FIELD32(0x00040000)
#define RXD_W0_LAST_AMSDU FIELD32(0x00080000)
#define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000)
#endif /* RT2800USB_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,280 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00lib
Abstract: rt2x00 generic configuration routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
enum nl80211_iftype type,
const u8 *mac, const u8 *bssid)
{
struct rt2x00intf_conf conf;
unsigned int flags = 0;
conf.type = type;
switch (type) {
case NL80211_IFTYPE_ADHOC:
conf.sync = TSF_SYNC_ADHOC;
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
conf.sync = TSF_SYNC_AP_NONE;
break;
case NL80211_IFTYPE_STATION:
conf.sync = TSF_SYNC_INFRA;
break;
default:
conf.sync = TSF_SYNC_NONE;
break;
}
/*
* Note that when NULL is passed as address we will send
* 00:00:00:00:00 to the device to clear the address.
* This will prevent the device being confused when it wants
* to ACK frames or considers itself associated.
*/
memset(conf.mac, 0, sizeof(conf.mac));
if (mac)
memcpy(conf.mac, mac, ETH_ALEN);
memset(conf.bssid, 0, sizeof(conf.bssid));
if (bssid)
memcpy(conf.bssid, bssid, ETH_ALEN);
flags |= CONFIG_UPDATE_TYPE;
if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
flags |= CONFIG_UPDATE_MAC;
if (bssid || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
flags |= CONFIG_UPDATE_BSSID;
rt2x00dev->ops->lib->config_intf(rt2x00dev, intf, &conf, flags);
}
void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
struct ieee80211_vif *vif = container_of(bss_conf, struct ieee80211_vif,
bss_conf);
struct rt2x00lib_erp erp;
memset(&erp, 0, sizeof(erp));
erp.short_preamble = bss_conf->use_short_preamble;
erp.cts_protection = bss_conf->use_cts_prot;
erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME;
erp.sifs = SIFS;
erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS;
erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS;
erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS;
erp.basic_rates = bss_conf->basic_rates;
erp.beacon_int = bss_conf->beacon_int;
/* Update the AID, this is needed for dynamic PS support */
rt2x00dev->aid = vif->cfg.assoc ? vif->cfg.aid : 0;
rt2x00dev->last_beacon = bss_conf->sync_tsf;
/* Update global beacon interval time, this is needed for PS support */
rt2x00dev->beacon_int = bss_conf->beacon_int;
if (changed & BSS_CHANGED_HT)
erp.ht_opmode = bss_conf->ht_operation_mode;
rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed);
}
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
struct antenna_setup config)
{
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup *def = &rt2x00dev->default_ant;
struct antenna_setup *active = &rt2x00dev->link.ant.active;
/*
* When the caller tries to send the SW diversity,
* we must update the ANTENNA_RX_DIVERSITY flag to
* enable the antenna diversity in the link tuner.
*
* Secondly, we must guarentee we never send the
* software antenna diversity command to the driver.
*/
if (!(ant->flags & ANTENNA_RX_DIVERSITY)) {
if (config.rx == ANTENNA_SW_DIVERSITY) {
ant->flags |= ANTENNA_RX_DIVERSITY;
if (def->rx == ANTENNA_SW_DIVERSITY)
config.rx = ANTENNA_B;
else
config.rx = def->rx;
}
} else if (config.rx == ANTENNA_SW_DIVERSITY)
config.rx = active->rx;
if (!(ant->flags & ANTENNA_TX_DIVERSITY)) {
if (config.tx == ANTENNA_SW_DIVERSITY) {
ant->flags |= ANTENNA_TX_DIVERSITY;
if (def->tx == ANTENNA_SW_DIVERSITY)
config.tx = ANTENNA_B;
else
config.tx = def->tx;
}
} else if (config.tx == ANTENNA_SW_DIVERSITY)
config.tx = active->tx;
/*
* Antenna setup changes require the RX to be disabled,
* else the changes will be ignored by the device.
*/
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00queue_stop_queue(rt2x00dev->rx);
/*
* Write new antenna setup to device and reset the link tuner.
* The latter is required since we need to recalibrate the
* noise-sensitivity ratio for the new setup.
*/
rt2x00dev->ops->lib->config_ant(rt2x00dev, &config);
rt2x00link_reset_tuner(rt2x00dev, true);
memcpy(active, &config, sizeof(config));
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00queue_start_queue(rt2x00dev->rx);
}
static u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
int center_channel;
u16 i;
/*
* Initialize center channel to current channel.
*/
center_channel = spec->channels[conf->chandef.chan->hw_value].channel;
/*
* Adjust center channel to HT40+ and HT40- operation.
*/
if (conf_is_ht40_plus(conf))
center_channel += 2;
else if (conf_is_ht40_minus(conf))
center_channel -= (center_channel == 14) ? 1 : 2;
for (i = 0; i < spec->num_channels; i++)
if (spec->channels[i].channel == center_channel)
return i;
WARN_ON(1);
return conf->chandef.chan->hw_value;
}
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
unsigned int ieee80211_flags)
{
struct rt2x00lib_conf libconf;
u16 hw_value;
u16 autowake_timeout;
u16 beacon_int;
u16 beacon_diff;
memset(&libconf, 0, sizeof(libconf));
libconf.conf = conf;
if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
if (!conf_is_ht(conf))
set_bit(CONFIG_HT_DISABLED, &rt2x00dev->flags);
else
clear_bit(CONFIG_HT_DISABLED, &rt2x00dev->flags);
if (conf_is_ht40(conf)) {
set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
hw_value = rt2x00ht_center_channel(rt2x00dev, conf);
} else {
clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
hw_value = conf->chandef.chan->hw_value;
}
memcpy(&libconf.rf,
&rt2x00dev->spec.channels[hw_value],
sizeof(libconf.rf));
memcpy(&libconf.channel,
&rt2x00dev->spec.channels_info[hw_value],
sizeof(libconf.channel));
/* Used for VCO periodic calibration */
rt2x00dev->rf_channel = libconf.rf.channel;
}
if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_PS_AUTOWAKE) &&
(ieee80211_flags & IEEE80211_CONF_CHANGE_PS))
cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
/*
* Start configuration.
*/
rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags);
if (conf->flags & IEEE80211_CONF_PS)
set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
else
clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
if (conf->flags & IEEE80211_CONF_MONITOR)
set_bit(CONFIG_MONITORING, &rt2x00dev->flags);
else
clear_bit(CONFIG_MONITORING, &rt2x00dev->flags);
rt2x00dev->curr_band = conf->chandef.chan->band;
rt2x00dev->curr_freq = conf->chandef.chan->center_freq;
rt2x00dev->tx_power = conf->power_level;
rt2x00dev->short_retry = conf->short_frame_max_tx_count;
rt2x00dev->long_retry = conf->long_frame_max_tx_count;
/*
* Some configuration changes affect the link quality
* which means we need to reset the link tuner.
*/
if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
rt2x00link_reset_tuner(rt2x00dev, false);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
rt2x00_has_cap_flag(rt2x00dev, REQUIRE_PS_AUTOWAKE) &&
(ieee80211_flags & IEEE80211_CONF_CHANGE_PS) &&
(conf->flags & IEEE80211_CONF_PS)) {
beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon;
beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int);
if (beacon_diff > beacon_int)
beacon_diff = 0;
autowake_timeout = (conf->ps_dtim_period * beacon_int) - beacon_diff;
queue_delayed_work(rt2x00dev->workqueue,
&rt2x00dev->autowakeup_work,
autowake_timeout - 15);
}
}
@@ -0,0 +1,242 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00lib
Abstract: rt2x00 crypto specific routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
{
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
return CIPHER_WEP64;
case WLAN_CIPHER_SUITE_WEP104:
return CIPHER_WEP128;
case WLAN_CIPHER_SUITE_TKIP:
return CIPHER_TKIP;
case WLAN_CIPHER_SUITE_CCMP:
return CIPHER_AES;
default:
return CIPHER_NONE;
}
}
void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct txentry_desc *txdesc)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || !hw_key)
return;
__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
__set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
txdesc->key_idx = hw_key->hw_key_idx;
txdesc->iv_offset = txdesc->header_length;
txdesc->iv_len = hw_key->iv_len;
if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
__set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
__set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
}
unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_key_conf *key = tx_info->control.hw_key;
unsigned int overhead = 0;
if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || !key)
return overhead;
/*
* Extend frame length to include IV/EIV/ICV/MMIC,
* note that these lengths should only be added when
* mac80211 does not generate it.
*/
overhead += key->icv_len;
if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
overhead += key->iv_len;
if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
overhead += 8;
}
return overhead;
}
void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
if (unlikely(!txdesc->iv_len))
return;
/* Copy IV/EIV data */
memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
}
void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
if (unlikely(!txdesc->iv_len))
return;
/* Copy IV/EIV data */
memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
/* Move ieee80211 header */
memmove(skb->data + txdesc->iv_len, skb->data, txdesc->iv_offset);
/* Pull buffer to correct size */
skb_pull(skb, txdesc->iv_len);
txdesc->length -= txdesc->iv_len;
/* IV/EIV data has officially been stripped */
skbdesc->flags |= SKBDESC_IV_STRIPPED;
}
void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
const unsigned int iv_len =
((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4);
if (!(skbdesc->flags & SKBDESC_IV_STRIPPED))
return;
skb_push(skb, iv_len);
/* Move ieee80211 header */
memmove(skb->data, skb->data + iv_len, header_length);
/* Copy IV/EIV data */
memcpy(skb->data + header_length, skbdesc->iv, iv_len);
/* IV/EIV data has returned into the frame */
skbdesc->flags &= ~SKBDESC_IV_STRIPPED;
}
void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
unsigned int header_length,
struct rxdone_entry_desc *rxdesc)
{
unsigned int payload_len = rxdesc->size - header_length;
unsigned int align = ALIGN_SIZE(skb, header_length);
unsigned int iv_len;
unsigned int icv_len;
unsigned int transfer = 0;
/*
* WEP64/WEP128: Provides IV & ICV
* TKIP: Provides IV/EIV & ICV
* AES: Provies IV/EIV & ICV
*/
switch (rxdesc->cipher) {
case CIPHER_WEP64:
case CIPHER_WEP128:
iv_len = 4;
icv_len = 4;
break;
case CIPHER_TKIP:
iv_len = 8;
icv_len = 4;
break;
case CIPHER_AES:
iv_len = 8;
icv_len = 8;
break;
default:
/* Unsupport type */
return;
}
/*
* Make room for new data. There are 2 possibilities
* either the alignment is already present between
* the 802.11 header and payload. In that case we
* have to move the header less than the iv_len
* since we can use the already available l2pad bytes
* for the iv data.
* When the alignment must be added manually we must
* move the header more then iv_len since we must
* make room for the payload move as well.
*/
if (rxdesc->dev_flags & RXDONE_L2PAD) {
skb_push(skb, iv_len - align);
skb_put(skb, icv_len);
/* Move ieee80211 header */
memmove(skb->data + transfer,
skb->data + transfer + (iv_len - align),
header_length);
transfer += header_length;
} else {
skb_push(skb, iv_len + align);
skb_put(skb, icv_len - align);
/* Move ieee80211 header */
memmove(skb->data + transfer,
skb->data + transfer + iv_len + align,
header_length);
transfer += header_length;
}
/* Copy IV/EIV data */
memcpy(skb->data + transfer, rxdesc->iv, iv_len);
transfer += iv_len;
/*
* Move payload for alignment purposes. Note that
* this is only needed when no l2 padding is present.
*/
if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {
memmove(skb->data + transfer,
skb->data + transfer + align,
payload_len);
}
/*
* NOTE: Always count the payload as transferred,
* even when alignment was set to zero. This is required
* for determining the correct offset for the ICV data.
*/
transfer += payload_len;
/*
* Copy ICV data
* AES appends 8 bytes, we can't fill the upper
* 4 bytes, but mac80211 doesn't care about what
* we provide here anyway and strips it immediately.
*/
memcpy(skb->data + transfer, &rxdesc->icv, 4);
transfer += icv_len;
/* IV/EIV/ICV has been inserted into frame */
rxdesc->size = transfer;
rxdesc->flags &= ~RX_FLAG_IV_STRIPPED;
}
@@ -0,0 +1,723 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00lib
Abstract: rt2x00 debugfs specific routines.
*/
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
#include "rt2x00dump.h"
#define MAX_LINE_LENGTH 64
struct rt2x00debug_crypto {
unsigned long success;
unsigned long icv_error;
unsigned long mic_error;
unsigned long key_error;
};
struct rt2x00debug_intf {
/*
* Pointer to driver structure where
* this debugfs entry belongs to.
*/
struct rt2x00_dev *rt2x00dev;
/*
* Reference to the rt2x00debug structure
* which can be used to communicate with
* the registers.
*/
const struct rt2x00debug *debug;
/*
* Debugfs entries for:
* - driver folder
* - driver file
* - chipset file
* - device state flags file
* - device capability flags file
* - hardware restart file
* - register folder
* - csr offset/value files
* - eeprom offset/value files
* - bbp offset/value files
* - rf offset/value files
* - rfcsr offset/value files
* - queue folder
* - frame dump file
* - queue stats file
* - crypto stats file
*/
struct dentry *driver_folder;
/*
* The frame dump file only allows a single reader,
* so we need to store the current state here.
*/
unsigned long frame_dump_flags;
#define FRAME_DUMP_FILE_OPEN 1
/*
* We queue each frame before dumping it to the user,
* per read command we will pass a single skb structure
* so we should be prepared to queue multiple sk buffers
* before sending it to userspace.
*/
struct sk_buff_head frame_dump_skbqueue;
wait_queue_head_t frame_dump_waitqueue;
/*
* HW crypto statistics.
* All statistics are stored separately per cipher type.
*/
struct rt2x00debug_crypto crypto_stats[CIPHER_MAX];
/*
* Driver and chipset files will use a data buffer
* that has been created in advance. This will simplify
* the code since we can use the debugfs functions.
*/
struct debugfs_blob_wrapper driver_blob;
struct debugfs_blob_wrapper chipset_blob;
/*
* Requested offset for each register type.
*/
unsigned int offset_csr;
unsigned int offset_eeprom;
unsigned int offset_bbp;
unsigned int offset_rf;
unsigned int offset_rfcsr;
};
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
enum cipher cipher = rxdesc->cipher;
enum rx_crypto status = rxdesc->cipher_status;
if (cipher == CIPHER_TKIP_NO_MIC)
cipher = CIPHER_TKIP;
if (cipher == CIPHER_NONE || cipher >= CIPHER_MAX)
return;
/* Remove CIPHER_NONE index */
cipher--;
intf->crypto_stats[cipher].success += (status == RX_CRYPTO_SUCCESS);
intf->crypto_stats[cipher].icv_error += (status == RX_CRYPTO_FAIL_ICV);
intf->crypto_stats[cipher].mic_error += (status == RX_CRYPTO_FAIL_MIC);
intf->crypto_stats[cipher].key_error += (status == RX_CRYPTO_FAIL_KEY);
}
void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
enum rt2x00_dump_type type, struct queue_entry *entry)
{
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
struct sk_buff *skb = entry->skb;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
struct sk_buff *skbcopy;
struct rt2x00dump_hdr *dump_hdr;
struct timespec64 timestamp;
u32 data_len;
if (likely(!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)))
return;
ktime_get_ts64(&timestamp);
if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) {
rt2x00_dbg(rt2x00dev, "txrx dump queue length exceeded\n");
return;
}
data_len = skb->len;
if (skbdesc->flags & SKBDESC_DESC_IN_SKB)
data_len -= skbdesc->desc_len;
skbcopy = alloc_skb(sizeof(*dump_hdr) + skbdesc->desc_len + data_len,
GFP_ATOMIC);
if (!skbcopy) {
rt2x00_dbg(rt2x00dev, "Failed to copy skb for dump\n");
return;
}
dump_hdr = skb_put(skbcopy, sizeof(*dump_hdr));
dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION);
dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr));
dump_hdr->desc_length = cpu_to_le32(skbdesc->desc_len);
dump_hdr->data_length = cpu_to_le32(data_len);
dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
dump_hdr->chip_rev = cpu_to_le16(rt2x00dev->chip.rev);
dump_hdr->type = cpu_to_le16(type);
dump_hdr->queue_index = entry->queue->qid;
dump_hdr->entry_index = entry->entry_idx;
dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_nsec /
NSEC_PER_USEC);
if (!(skbdesc->flags & SKBDESC_DESC_IN_SKB))
skb_put_data(skbcopy, skbdesc->desc, skbdesc->desc_len);
skb_put_data(skbcopy, skb->data, skb->len);
skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy);
wake_up_interruptible(&intf->frame_dump_waitqueue);
/*
* Verify that the file has not been closed while we were working.
*/
if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
skb_queue_purge(&intf->frame_dump_skbqueue);
}
EXPORT_SYMBOL_GPL(rt2x00debug_dump_frame);
static int rt2x00debug_file_open(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
file->private_data = inode->i_private;
if (!try_module_get(intf->debug->owner))
return -EBUSY;
return 0;
}
static int rt2x00debug_file_release(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = file->private_data;
module_put(intf->debug->owner);
return 0;
}
static int rt2x00debug_open_queue_dump(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
int retval;
retval = rt2x00debug_file_open(inode, file);
if (retval)
return retval;
if (test_and_set_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) {
rt2x00debug_file_release(inode, file);
return -EBUSY;
}
return 0;
}
static int rt2x00debug_release_queue_dump(struct inode *inode, struct file *file)
{
struct rt2x00debug_intf *intf = inode->i_private;
skb_queue_purge(&intf->frame_dump_skbqueue);
clear_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags);
return rt2x00debug_file_release(inode, file);
}
static ssize_t rt2x00debug_read_queue_dump(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
struct sk_buff *skb;
size_t status;
int retval;
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
retval =
wait_event_interruptible(intf->frame_dump_waitqueue,
(skb =
skb_dequeue(&intf->frame_dump_skbqueue)));
if (retval)
return retval;
status = min_t(size_t, skb->len, length);
if (copy_to_user(buf, skb->data, status)) {
status = -EFAULT;
goto exit;
}
*offset += status;
exit:
kfree_skb(skb);
return status;
}
static __poll_t rt2x00debug_poll_queue_dump(struct file *file,
poll_table *wait)
{
struct rt2x00debug_intf *intf = file->private_data;
poll_wait(file, &intf->frame_dump_waitqueue, wait);
if (!skb_queue_empty(&intf->frame_dump_skbqueue))
return EPOLLOUT | EPOLLWRNORM;
return 0;
}
static const struct file_operations rt2x00debug_fop_queue_dump = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_queue_dump,
.poll = rt2x00debug_poll_queue_dump,
.open = rt2x00debug_open_queue_dump,
.release = rt2x00debug_release_queue_dump,
.llseek = default_llseek,
};
static ssize_t rt2x00debug_read_queue_stats(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
struct data_queue *queue;
unsigned long irqflags;
unsigned int lines = 1 + intf->rt2x00dev->data_queues;
size_t size;
char *data;
char *temp;
if (*offset)
return 0;
data = kcalloc(lines, MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return -ENOMEM;
temp = data +
sprintf(data, "qid\tflags\t\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
queue_for_each(intf->rt2x00dev, queue) {
spin_lock_irqsave(&queue->index_lock, irqflags);
temp += sprintf(temp, "%d\t0x%.8x\t%d\t%d\t%d\t%d\t%d\t\t%d\n",
queue->qid, (unsigned int)queue->flags,
queue->count, queue->limit, queue->length,
queue->index[Q_INDEX],
queue->index[Q_INDEX_DMA_DONE],
queue->index[Q_INDEX_DONE]);
spin_unlock_irqrestore(&queue->index_lock, irqflags);
}
size = strlen(data);
size = min(size, length);
if (copy_to_user(buf, data, size)) {
kfree(data);
return -EFAULT;
}
kfree(data);
*offset += size;
return size;
}
static const struct file_operations rt2x00debug_fop_queue_stats = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_queue_stats,
.open = rt2x00debug_file_open,
.release = rt2x00debug_file_release,
.llseek = default_llseek,
};
#ifdef CONFIG_RT2X00_LIB_CRYPTO
static ssize_t rt2x00debug_read_crypto_stats(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
static const char * const name[] = { "WEP64", "WEP128", "TKIP", "AES" };
char *data;
char *temp;
size_t size;
unsigned int i;
if (*offset)
return 0;
data = kcalloc(1 + CIPHER_MAX, MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return -ENOMEM;
temp = data;
temp += sprintf(data, "cipher\tsuccess\ticv err\tmic err\tkey err\n");
for (i = 0; i < CIPHER_MAX; i++) {
temp += sprintf(temp, "%s\t%lu\t%lu\t%lu\t%lu\n", name[i],
intf->crypto_stats[i].success,
intf->crypto_stats[i].icv_error,
intf->crypto_stats[i].mic_error,
intf->crypto_stats[i].key_error);
}
size = strlen(data);
size = min(size, length);
if (copy_to_user(buf, data, size)) {
kfree(data);
return -EFAULT;
}
kfree(data);
*offset += size;
return size;
}
static const struct file_operations rt2x00debug_fop_crypto_stats = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_crypto_stats,
.open = rt2x00debug_file_open,
.release = rt2x00debug_file_release,
.llseek = default_llseek,
};
#endif
#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
static ssize_t rt2x00debug_read_##__name(struct file *file, \
char __user *buf, \
size_t length, \
loff_t *offset) \
{ \
struct rt2x00debug_intf *intf = file->private_data; \
const struct rt2x00debug *debug = intf->debug; \
char line[16]; \
size_t size; \
unsigned int index = intf->offset_##__name; \
__type value; \
\
if (*offset) \
return 0; \
\
if (index >= debug->__name.word_count) \
return -EINVAL; \
\
index += (debug->__name.word_base / \
debug->__name.word_size); \
\
if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \
index *= debug->__name.word_size; \
\
value = debug->__name.read(intf->rt2x00dev, index); \
\
size = sprintf(line, __format, value); \
\
return simple_read_from_buffer(buf, length, offset, line, size); \
}
#define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \
static ssize_t rt2x00debug_write_##__name(struct file *file, \
const char __user *buf,\
size_t length, \
loff_t *offset) \
{ \
struct rt2x00debug_intf *intf = file->private_data; \
const struct rt2x00debug *debug = intf->debug; \
char line[17]; \
size_t size; \
unsigned int index = intf->offset_##__name; \
__type value; \
\
if (*offset) \
return 0; \
\
if (index >= debug->__name.word_count) \
return -EINVAL; \
\
if (length > sizeof(line)) \
return -EINVAL; \
\
if (copy_from_user(line, buf, length)) \
return -EFAULT; \
line[16] = 0; \
\
size = strlen(line); \
value = simple_strtoul(line, NULL, 0); \
\
index += (debug->__name.word_base / \
debug->__name.word_size); \
\
if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \
index *= debug->__name.word_size; \
\
debug->__name.write(intf->rt2x00dev, index, value); \
\
*offset += size; \
return size; \
}
#define RT2X00DEBUGFS_OPS(__name, __format, __type) \
RT2X00DEBUGFS_OPS_READ(__name, __format, __type); \
RT2X00DEBUGFS_OPS_WRITE(__name, __type); \
\
static const struct file_operations rt2x00debug_fop_##__name = {\
.owner = THIS_MODULE, \
.read = rt2x00debug_read_##__name, \
.write = rt2x00debug_write_##__name, \
.open = rt2x00debug_file_open, \
.release = rt2x00debug_file_release, \
.llseek = generic_file_llseek, \
};
RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32);
RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16);
RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8);
RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32);
RT2X00DEBUGFS_OPS(rfcsr, "0x%.2x\n", u8);
static ssize_t rt2x00debug_read_dev_flags(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
char line[16];
size_t size;
if (*offset)
return 0;
size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags);
return simple_read_from_buffer(buf, length, offset, line, size);
}
static const struct file_operations rt2x00debug_fop_dev_flags = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_dev_flags,
.open = rt2x00debug_file_open,
.release = rt2x00debug_file_release,
.llseek = default_llseek,
};
static ssize_t rt2x00debug_read_cap_flags(struct file *file,
char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
char line[16];
size_t size;
if (*offset)
return 0;
size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags);
return simple_read_from_buffer(buf, length, offset, line, size);
}
static const struct file_operations rt2x00debug_fop_cap_flags = {
.owner = THIS_MODULE,
.read = rt2x00debug_read_cap_flags,
.open = rt2x00debug_file_open,
.release = rt2x00debug_file_release,
.llseek = default_llseek,
};
static ssize_t rt2x00debug_write_restart_hw(struct file *file,
const char __user *buf,
size_t length,
loff_t *offset)
{
struct rt2x00debug_intf *intf = file->private_data;
struct rt2x00_dev *rt2x00dev = intf->rt2x00dev;
static unsigned long last_reset = INITIAL_JIFFIES;
if (!rt2x00_has_cap_restart_hw(rt2x00dev))
return -EOPNOTSUPP;
if (time_before(jiffies, last_reset + msecs_to_jiffies(2000)))
return -EBUSY;
last_reset = jiffies;
ieee80211_restart_hw(rt2x00dev->hw);
return length;
}
static const struct file_operations rt2x00debug_restart_hw = {
.owner = THIS_MODULE,
.write = rt2x00debug_write_restart_hw,
.open = simple_open,
.llseek = generic_file_llseek,
};
static void rt2x00debug_create_file_driver(const char *name,
struct rt2x00debug_intf *intf,
struct debugfs_blob_wrapper *blob)
{
char *data;
data = kzalloc(3 * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return;
blob->data = data;
data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name);
data += sprintf(data, "version:\t%s\n", DRV_VERSION);
blob->size = strlen(blob->data);
debugfs_create_blob(name, 0400, intf->driver_folder, blob);
}
static void rt2x00debug_create_file_chipset(const char *name,
struct rt2x00debug_intf *intf,
struct debugfs_blob_wrapper *blob)
{
const struct rt2x00debug *debug = intf->debug;
char *data;
data = kzalloc(9 * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return;
blob->data = data;
data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt);
data += sprintf(data, "rf chip:\t%04x\n", intf->rt2x00dev->chip.rf);
data += sprintf(data, "revision:\t%04x\n", intf->rt2x00dev->chip.rev);
data += sprintf(data, "\n");
data += sprintf(data, "register\tbase\twords\twordsize\n");
#define RT2X00DEBUGFS_SPRINTF_REGISTER(__name) \
{ \
if (debug->__name.read) \
data += sprintf(data, __stringify(__name) \
"\t%d\t%d\t%d\n", \
debug->__name.word_base, \
debug->__name.word_count, \
debug->__name.word_size); \
}
RT2X00DEBUGFS_SPRINTF_REGISTER(csr);
RT2X00DEBUGFS_SPRINTF_REGISTER(eeprom);
RT2X00DEBUGFS_SPRINTF_REGISTER(bbp);
RT2X00DEBUGFS_SPRINTF_REGISTER(rf);
RT2X00DEBUGFS_SPRINTF_REGISTER(rfcsr);
#undef RT2X00DEBUGFS_SPRINTF_REGISTER
blob->size = strlen(blob->data);
debugfs_create_blob(name, 0400, intf->driver_folder, blob);
}
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{
const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;
struct rt2x00debug_intf *intf;
struct dentry *queue_folder;
struct dentry *register_folder;
intf = kzalloc_obj(struct rt2x00debug_intf);
if (!intf) {
rt2x00_err(rt2x00dev, "Failed to allocate debug handler\n");
return;
}
intf->debug = debug;
intf->rt2x00dev = rt2x00dev;
rt2x00dev->debugfs_intf = intf;
intf->driver_folder =
debugfs_create_dir(intf->rt2x00dev->ops->name,
rt2x00dev->hw->wiphy->debugfsdir);
rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
rt2x00debug_create_file_chipset("chipset", intf, &intf->chipset_blob);
debugfs_create_file("dev_flags", 0400, intf->driver_folder, intf,
&rt2x00debug_fop_dev_flags);
debugfs_create_file("cap_flags", 0400, intf->driver_folder, intf,
&rt2x00debug_fop_cap_flags);
debugfs_create_file("restart_hw", 0200, intf->driver_folder, intf,
&rt2x00debug_restart_hw);
register_folder = debugfs_create_dir("register", intf->driver_folder);
#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
({ \
if (debug->__name.read) { \
debugfs_create_u32(__stringify(__name) "_offset", 0600, \
register_folder, \
&(__intf)->offset_##__name); \
\
debugfs_create_file(__stringify(__name) "_value", 0600, \
register_folder, (__intf), \
&rt2x00debug_fop_##__name); \
} \
})
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, csr);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, eeprom);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, bbp);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rf);
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rfcsr);
#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
queue_folder = debugfs_create_dir("queue", intf->driver_folder);
debugfs_create_file("dump", 0400, queue_folder, intf,
&rt2x00debug_fop_queue_dump);
skb_queue_head_init(&intf->frame_dump_skbqueue);
init_waitqueue_head(&intf->frame_dump_waitqueue);
debugfs_create_file("queue", 0400, queue_folder, intf,
&rt2x00debug_fop_queue_stats);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
if (rt2x00_has_cap_hw_crypto(rt2x00dev))
debugfs_create_file("crypto", 0444, queue_folder, intf,
&rt2x00debug_fop_crypto_stats);
#endif
return;
}
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
{
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
if (unlikely(!intf))
return;
skb_queue_purge(&intf->frame_dump_skbqueue);
debugfs_remove_recursive(intf->driver_folder);
kfree(intf->chipset_blob.data);
kfree(intf->driver_blob.data);
kfree(intf);
rt2x00dev->debugfs_intf = NULL;
}
@@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00debug
Abstract: Data structures for the rt2x00debug.
*/
#ifndef RT2X00DEBUG_H
#define RT2X00DEBUG_H
struct rt2x00_dev;
/**
* enum rt2x00debugfs_entry_flags: Flags for debugfs registry entry
*
* @RT2X00DEBUGFS_OFFSET: rt2x00lib should pass the register offset
* as argument when using the callback function read()/write()
*/
enum rt2x00debugfs_entry_flags {
RT2X00DEBUGFS_OFFSET = (1 << 0),
};
#define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \
struct reg##__name { \
__type (*read)(struct rt2x00_dev *rt2x00dev, \
const unsigned int word); \
void (*write)(struct rt2x00_dev *rt2x00dev, \
const unsigned int word, __type data); \
\
unsigned int flags; \
\
unsigned int word_base; \
unsigned int word_size; \
unsigned int word_count; \
} __name
struct rt2x00debug {
/*
* Reference to the modules structure.
*/
struct module *owner;
/*
* Register access entries.
*/
RT2X00DEBUGFS_REGISTER_ENTRY(csr, u32);
RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16);
RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8);
RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32);
RT2X00DEBUGFS_REGISTER_ENTRY(rfcsr, u8);
};
#endif /* RT2X00DEBUG_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,116 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00dump
Abstract:
Data structures for the rt2x00debug & userspace.
The declarations in this file can be used by both rt2x00
and userspace and therefore should be kept together in
this file.
*/
#ifndef RT2X00DUMP_H
#define RT2X00DUMP_H
/**
* DOC: Introduction
*
* This header is intended to be exported to userspace,
* to make the structures and enumerations available to userspace
* applications. This means that all data types should be exportable.
*
* When rt2x00 is compiled with debugfs support enabled,
* it is possible to capture all data coming in and out of the device
* by reading the frame dump file. This file can have only a single reader.
* The following frames will be reported:
* - All incoming frames (rx)
* - All outgoing frames (tx, including beacon and atim)
* - All completed frames (txdone including atim)
*
* The data is send to the file using the following format:
*
* [rt2x00dump header][hardware descriptor][ieee802.11 frame]
*
* rt2x00dump header: The description of the dumped frame, as well as
* additional information useful for debugging. See &rt2x00dump_hdr.
* hardware descriptor: Descriptor that was used to receive or transmit
* the frame.
* ieee802.11 frame: The actual frame that was received or transmitted.
*/
/**
* enum rt2x00_dump_type - Frame type
*
* These values are used for the @type member of &rt2x00dump_hdr.
* @DUMP_FRAME_RXDONE: This frame has been received by the hardware.
* @DUMP_FRAME_TX: This frame is queued for transmission to the hardware.
* @DUMP_FRAME_TXDONE: This frame indicates the device has handled
* the tx event which has either succeeded or failed. A frame
* with this type should also have been reported with as a
* %DUMP_FRAME_TX frame.
* @DUMP_FRAME_BEACON: This beacon frame is queued for transmission to the
* hardware.
*/
enum rt2x00_dump_type {
DUMP_FRAME_RXDONE = 1,
DUMP_FRAME_TX = 2,
DUMP_FRAME_TXDONE = 3,
DUMP_FRAME_BEACON = 4,
};
/**
* struct rt2x00dump_hdr - Dump frame header
*
* Each frame dumped to the debugfs file starts with this header
* attached. This header contains the description of the actual
* frame which was dumped.
*
* New fields inside the structure must be appended to the end of
* the structure. This way userspace tools compiled for earlier
* header versions can still correctly handle the frame dump
* (although they will not handle all data passed to them in the dump).
*
* @version: Header version should always be set to %DUMP_HEADER_VERSION.
* This field must be checked by userspace to determine if it can
* handle this frame.
* @header_length: The length of the &rt2x00dump_hdr structure. This is
* used for compatibility reasons so userspace can easily determine
* the location of the next field in the dump.
* @desc_length: The length of the device descriptor.
* @data_length: The length of the frame data (including the ieee802.11 header.
* @chip_rt: RT chipset
* @chip_rf: RF chipset
* @chip_rev: Chipset revision
* @type: The frame type (&rt2x00_dump_type)
* @queue_index: The index number of the data queue.
* @entry_index: The index number of the entry inside the data queue.
* @timestamp_sec: Timestamp - seconds
* @timestamp_usec: Timestamp - microseconds
*/
struct rt2x00dump_hdr {
__le32 version;
#define DUMP_HEADER_VERSION 3
__le32 header_length;
__le32 desc_length;
__le32 data_length;
__le16 chip_rt;
__le16 chip_rf;
__le16 chip_rev;
__le16 type;
__u8 queue_index;
__u8 entry_index;
__le32 timestamp_sec;
__le32 timestamp_usec;
};
#endif /* RT2X00DUMP_H */
@@ -0,0 +1,118 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00lib
Abstract: rt2x00 firmware loading routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
{
struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
const struct firmware *fw;
char *fw_name;
int retval;
/*
* Read correct firmware from harddisk.
*/
fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev);
if (!fw_name) {
rt2x00_err(rt2x00dev,
"Invalid firmware filename\n"
"Please file bug report to %s\n", DRV_PROJECT);
return -EINVAL;
}
rt2x00_info(rt2x00dev, "Loading firmware file '%s'\n", fw_name);
retval = request_firmware(&fw, fw_name, device);
if (retval) {
rt2x00_err(rt2x00dev, "Failed to request Firmware\n");
return retval;
}
if (!fw || !fw->size || !fw->data) {
rt2x00_err(rt2x00dev, "Failed to read Firmware\n");
release_firmware(fw);
return -ENOENT;
}
rt2x00_info(rt2x00dev, "Firmware detected - version: %d.%d\n",
fw->data[fw->size - 4], fw->data[fw->size - 3]);
snprintf(rt2x00dev->hw->wiphy->fw_version,
sizeof(rt2x00dev->hw->wiphy->fw_version), "%d.%d",
fw->data[fw->size - 4], fw->data[fw->size - 3]);
retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size);
switch (retval) {
case FW_OK:
break;
case FW_BAD_CRC:
rt2x00_err(rt2x00dev, "Firmware checksum error\n");
goto exit;
case FW_BAD_LENGTH:
rt2x00_err(rt2x00dev, "Invalid firmware file length (len=%zu)\n",
fw->size);
goto exit;
case FW_BAD_VERSION:
rt2x00_err(rt2x00dev, "Current firmware does not support detected chipset\n");
goto exit;
}
rt2x00dev->fw = fw;
return 0;
exit:
release_firmware(fw);
return -ENOENT;
}
int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
{
int retval;
if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_FIRMWARE))
return 0;
if (!rt2x00dev->fw) {
retval = rt2x00lib_request_firmware(rt2x00dev);
if (retval)
return retval;
}
/*
* Send firmware to the device.
*/
retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
rt2x00dev->fw->data,
rt2x00dev->fw->size);
/*
* When the firmware is uploaded to the hardware the LED
* association status might have been triggered, for correct
* LED handling it should now be reset.
*/
rt2x00leds_led_assoc(rt2x00dev, false);
return retval;
}
void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
{
release_firmware(rt2x00dev->fw);
rt2x00dev->fw = NULL;
}
@@ -0,0 +1,233 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00lib
Abstract: rt2x00 led specific routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi)
{
struct rt2x00_led *led = &rt2x00dev->led_qual;
unsigned int brightness;
if ((led->type != LED_TYPE_QUALITY) || !(led->flags & LED_REGISTERED))
return;
/*
* Led handling requires a positive value for the rssi,
* to do that correctly we need to add the correction.
*/
rssi += rt2x00dev->rssi_offset;
/*
* Get the rssi level, this is used to convert the rssi
* to a LED value inside the range LED_OFF - LED_FULL.
*/
if (rssi <= 30)
rssi = 0;
else if (rssi <= 39)
rssi = 1;
else if (rssi <= 49)
rssi = 2;
else if (rssi <= 53)
rssi = 3;
else if (rssi <= 63)
rssi = 4;
else
rssi = 5;
/*
* Note that we must _not_ send LED_OFF since the driver
* is going to calculate the value and might use it in a
* division.
*/
brightness = ((LED_FULL / 6) * rssi) + 1;
if (brightness != led->led_dev.brightness) {
led->led_dev.brightness_set(&led->led_dev, brightness);
led->led_dev.brightness = brightness;
}
}
static void rt2x00led_led_simple(struct rt2x00_led *led, bool enabled)
{
unsigned int brightness = enabled ? LED_FULL : LED_OFF;
if (!(led->flags & LED_REGISTERED))
return;
led->led_dev.brightness_set(&led->led_dev, brightness);
led->led_dev.brightness = brightness;
}
void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled)
{
if (rt2x00dev->led_qual.type == LED_TYPE_ACTIVITY)
rt2x00led_led_simple(&rt2x00dev->led_qual, enabled);
}
void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled)
{
if (rt2x00dev->led_assoc.type == LED_TYPE_ASSOC)
rt2x00led_led_simple(&rt2x00dev->led_assoc, enabled);
}
void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled)
{
if (rt2x00dev->led_radio.type == LED_TYPE_RADIO)
rt2x00led_led_simple(&rt2x00dev->led_radio, enabled);
}
static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
struct rt2x00_led *led,
const char *name)
{
struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
int retval;
led->led_dev.name = name;
led->led_dev.brightness = LED_OFF;
retval = led_classdev_register(device, &led->led_dev);
if (retval) {
rt2x00_err(rt2x00dev, "Failed to register led handler\n");
return retval;
}
led->flags |= LED_REGISTERED;
return 0;
}
void rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
{
char name[36];
int retval;
unsigned long on_period;
unsigned long off_period;
const char *phy_name = wiphy_name(rt2x00dev->hw->wiphy);
if (rt2x00dev->led_radio.flags & LED_INITIALIZED) {
snprintf(name, sizeof(name), "%s-%s::radio",
rt2x00dev->ops->name, phy_name);
retval = rt2x00leds_register_led(rt2x00dev,
&rt2x00dev->led_radio,
name);
if (retval)
goto exit_fail;
}
if (rt2x00dev->led_assoc.flags & LED_INITIALIZED) {
snprintf(name, sizeof(name), "%s-%s::assoc",
rt2x00dev->ops->name, phy_name);
retval = rt2x00leds_register_led(rt2x00dev,
&rt2x00dev->led_assoc,
name);
if (retval)
goto exit_fail;
}
if (rt2x00dev->led_qual.flags & LED_INITIALIZED) {
snprintf(name, sizeof(name), "%s-%s::quality",
rt2x00dev->ops->name, phy_name);
retval = rt2x00leds_register_led(rt2x00dev,
&rt2x00dev->led_qual,
name);
if (retval)
goto exit_fail;
}
/*
* Initialize blink time to default value:
* On period: 70ms
* Off period: 30ms
*/
if (rt2x00dev->led_radio.led_dev.blink_set) {
on_period = 70;
off_period = 30;
rt2x00dev->led_radio.led_dev.blink_set(
&rt2x00dev->led_radio.led_dev, &on_period, &off_period);
}
return;
exit_fail:
rt2x00leds_unregister(rt2x00dev);
}
static void rt2x00leds_unregister_led(struct rt2x00_led *led)
{
led_classdev_unregister(&led->led_dev);
/*
* This might look weird, but when we are unregistering while
* suspended the led is already off, and since we haven't
* fully resumed yet, access to the device might not be
* possible yet.
*/
if (!(led->led_dev.flags & LED_SUSPENDED))
led->led_dev.brightness_set(&led->led_dev, LED_OFF);
led->flags &= ~LED_REGISTERED;
}
void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_qual.flags & LED_REGISTERED)
rt2x00leds_unregister_led(&rt2x00dev->led_qual);
if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
rt2x00leds_unregister_led(&rt2x00dev->led_assoc);
if (rt2x00dev->led_radio.flags & LED_REGISTERED)
rt2x00leds_unregister_led(&rt2x00dev->led_radio);
}
static inline void rt2x00leds_suspend_led(struct rt2x00_led *led)
{
led_classdev_suspend(&led->led_dev);
/* This shouldn't be needed, but just to be safe */
led->led_dev.brightness_set(&led->led_dev, LED_OFF);
led->led_dev.brightness = LED_OFF;
}
void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_qual.flags & LED_REGISTERED)
rt2x00leds_suspend_led(&rt2x00dev->led_qual);
if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
rt2x00leds_suspend_led(&rt2x00dev->led_assoc);
if (rt2x00dev->led_radio.flags & LED_REGISTERED)
rt2x00leds_suspend_led(&rt2x00dev->led_radio);
}
static inline void rt2x00leds_resume_led(struct rt2x00_led *led)
{
led_classdev_resume(&led->led_dev);
/* Device might have enabled the LEDS during resume */
led->led_dev.brightness_set(&led->led_dev, LED_OFF);
led->led_dev.brightness = LED_OFF;
}
void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_radio.flags & LED_REGISTERED)
rt2x00leds_resume_led(&rt2x00dev->led_radio);
if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
rt2x00leds_resume_led(&rt2x00dev->led_assoc);
if (rt2x00dev->led_qual.flags & LED_REGISTERED)
rt2x00leds_resume_led(&rt2x00dev->led_qual);
}
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00lib
Abstract: rt2x00 led datastructures and routines
*/
#ifndef RT2X00LEDS_H
#define RT2X00LEDS_H
enum led_type {
LED_TYPE_RADIO,
LED_TYPE_ASSOC,
LED_TYPE_ACTIVITY,
LED_TYPE_QUALITY,
};
struct rt2x00_led {
struct rt2x00_dev *rt2x00dev;
struct led_classdev led_dev;
enum led_type type;
unsigned int flags;
#define LED_INITIALIZED ( 1 << 0 )
#define LED_REGISTERED ( 1 << 1 )
};
#endif /* RT2X00LEDS_H */
@@ -0,0 +1,434 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00lib
Abstract: Data structures and definitions for the rt2x00lib module.
*/
#ifndef RT2X00LIB_H
#define RT2X00LIB_H
/*
* Interval defines
*/
#define WATCHDOG_INTERVAL round_jiffies_relative(HZ)
#define LINK_TUNE_SECONDS 1
#define LINK_TUNE_INTERVAL round_jiffies_relative(LINK_TUNE_SECONDS * HZ)
#define AGC_SECONDS 4
#define VCO_SECONDS 10
/*
* rt2x00_rate: Per rate device information
*/
struct rt2x00_rate {
unsigned short flags;
#define DEV_RATE_CCK 0x0001
#define DEV_RATE_OFDM 0x0002
#define DEV_RATE_SHORT_PREAMBLE 0x0004
unsigned short bitrate; /* In 100kbit/s */
unsigned short ratemask;
unsigned short plcp;
unsigned short mcs;
};
extern const struct rt2x00_rate rt2x00_supported_rates[12];
static inline const struct rt2x00_rate *rt2x00_get_rate(const u16 hw_value)
{
return &rt2x00_supported_rates[hw_value & 0xff];
}
#define RATE_MCS(__mode, __mcs) \
((((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff))
static inline int rt2x00_get_rate_mcs(const u16 mcs_value)
{
return (mcs_value & 0x00ff);
}
/*
* Radio control handlers.
*/
int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev);
/*
* Initialization handlers.
*/
int rt2x00lib_start(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev);
/*
* Configuration handlers.
*/
void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
enum nl80211_iftype type,
const u8 *mac, const u8 *bssid);
void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
struct ieee80211_bss_conf *conf,
u32 changed);
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
struct antenna_setup ant);
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
const unsigned int changed_flags);
/**
* DOC: Queue handlers
*/
/**
* rt2x00queue_alloc_rxskb - allocate a skb for RX purposes.
* @entry: The entry for which the skb will be applicable.
*/
struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp);
/**
* rt2x00queue_free_skb - free a skb
* @entry: The entry for which the skb will be applicable.
*/
void rt2x00queue_free_skb(struct queue_entry *entry);
/**
* rt2x00queue_align_frame - Align 802.11 frame to 4-byte boundary
* @skb: The skb to align
*
* Align the start of the 802.11 frame to a 4-byte boundary, this could
* mean the payload is not aligned properly though.
*/
void rt2x00queue_align_frame(struct sk_buff *skb);
/**
* rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary
* @skb: The skb to align
* @header_length: Length of 802.11 header
*
* Apply L2 padding to align both header and payload to 4-byte boundary
*/
void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length);
/**
* rt2x00queue_insert_l2pad - Remove L2 padding from 802.11 frame
* @skb: The skb to align
* @header_length: Length of 802.11 header
*
* Remove L2 padding used to align both header and payload to 4-byte boundary,
* by removing the L2 padding the header will no longer be 4-byte aligned.
*/
void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length);
/**
* rt2x00queue_write_tx_frame - Write TX frame to hardware
* @queue: Queue over which the frame should be send
* @skb: The skb to send
* @local: frame is not from mac80211
*/
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
struct ieee80211_sta *sta, bool local);
/**
* rt2x00queue_update_beacon - Send new beacon from mac80211
* to hardware. Handles locking by itself (mutex).
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @vif: Interface for which the beacon should be updated.
*/
int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif);
/**
* rt2x00queue_update_beacon_locked - Send new beacon from mac80211
* to hardware. Caller needs to ensure locking.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @vif: Interface for which the beacon should be updated.
*/
int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif);
/**
* rt2x00queue_clear_beacon - Clear beacon in hardware
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @vif: Interface for which the beacon should be updated.
*/
int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif);
/**
* rt2x00queue_index_inc - Index incrementation function
* @entry: Queue entry (&struct queue_entry) to perform the action on.
* @index: Index type (&enum queue_index) to perform the action on.
*
* This function will increase the requested index on the entry's queue,
* it will grab the appropriate locks and handle queue overflow events by
* resetting the index to the start of the queue.
*/
void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index);
/**
* rt2x00queue_init_queues - Initialize all data queues
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* This function will loop through all available queues to clear all
* index numbers and set the queue entry to the correct initialization
* state.
*/
void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev);
int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev);
int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_free(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_update_stats - Update link statistics from RX frame
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: Received frame
* @rxdesc: Received frame descriptor
*
* Update link statistics based on the information from the
* received frame descriptor.
*/
void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc);
/**
* rt2x00link_start_tuner - Start periodic link tuner work
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* This start the link tuner periodic work, this work will
* be executed periodically until &rt2x00link_stop_tuner has
* been called.
*/
void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_stop_tuner - Stop periodic link tuner work
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* After this function completed the link tuner will not
* be running until &rt2x00link_start_tuner is called.
*/
void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_reset_tuner - Reset periodic link tuner work
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @antenna: Should the antenna tuning also be reset
*
* The VGC limit configured in the hardware will be reset to 0
* which forces the driver to rediscover the correct value for
* the current association. This is needed when configuration
* options have changed which could drastically change the
* SNR level or link quality (i.e. changing the antenna setting).
*
* Resetting the link tuner will also cause the periodic work counter
* to be reset. Any driver which has a fixed limit on the number
* of rounds the link tuner is supposed to work will accept the
* tuner actions again if this limit was previously reached.
*
* If @antenna is set to true a the software antenna diversity
* tuning will also be reset.
*/
void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna);
/**
* rt2x00link_start_watchdog - Start periodic watchdog monitoring
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* This start the watchdog periodic work, this work will
*be executed periodically until &rt2x00link_stop_watchdog has
* been called.
*/
void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_stop_watchdog - Stop periodic watchdog monitoring
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* After this function completed the watchdog monitoring will not
* be running until &rt2x00link_start_watchdog is called.
*/
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00link_register - Initialize link tuning & watchdog functionality
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
* Initialize work structure and all link tuning and watchdog related
* parameters. This will not start the periodic work itself.
*/
void rt2x00link_register(struct rt2x00_dev *rt2x00dev);
/*
* Firmware handlers.
*/
#ifdef CONFIG_RT2X00_LIB_FIRMWARE
int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev);
#else
static inline int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
{
return 0;
}
static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
{
}
#endif /* CONFIG_RT2X00_LIB_FIRMWARE */
/*
* Debugfs handlers.
*/
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc);
#else
static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
}
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
/*
* Crypto handlers.
*/
#ifdef CONFIG_RT2X00_LIB_CRYPTO
enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key);
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);
void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
struct txentry_desc *txdesc);
void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
struct txentry_desc *txdesc);
void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length);
void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
unsigned int header_length,
struct rxdone_entry_desc *rxdesc);
#else
static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
{
return CIPHER_NONE;
}
static inline void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct txentry_desc *txdesc)
{
}
static inline unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb)
{
return 0;
}
static inline void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
struct txentry_desc *txdesc)
{
}
static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
struct txentry_desc *txdesc)
{
}
static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb,
unsigned int header_length)
{
}
static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
unsigned int header_length,
struct rxdone_entry_desc *rxdesc)
{
}
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
/*
* RFkill handlers.
*/
static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
{
if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags))
wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy);
}
static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
{
if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags))
wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy);
}
/*
* LED handlers
*/
#ifdef CONFIG_RT2X00_LIB_LEDS
void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi);
void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled);
void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled);
void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled);
void rt2x00leds_register(struct rt2x00_dev *rt2x00dev);
void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev);
void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev);
void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev);
#else
static inline void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev,
int rssi)
{
}
static inline void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev,
bool enabled)
{
}
static inline void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev,
bool enabled)
{
}
static inline void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev,
bool enabled)
{
}
static inline void rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
{
}
static inline void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
{
}
#endif /* CONFIG_RT2X00_LIB_LEDS */
#endif /* RT2X00LIB_H */
@@ -0,0 +1,428 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00lib
Abstract: rt2x00 generic link tuning routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
/*
* When we lack RSSI information return something less then -80 to
* tell the driver to tune the device to maximum sensitivity.
*/
#define DEFAULT_RSSI -128
static inline int rt2x00link_get_avg_rssi(struct ewma_rssi *ewma)
{
unsigned long avg;
avg = ewma_rssi_read(ewma);
if (avg)
return -avg;
return DEFAULT_RSSI;
}
static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
if (rt2x00dev->link.qual.rx_success)
return rt2x00link_get_avg_rssi(&ant->rssi_ant);
return DEFAULT_RSSI;
}
static int rt2x00link_antenna_get_rssi_history(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
if (ant->rssi_history)
return ant->rssi_history;
return DEFAULT_RSSI;
}
static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
int rssi)
{
struct link_ant *ant = &rt2x00dev->link.ant;
ant->rssi_history = rssi;
}
static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
{
ewma_rssi_init(&rt2x00dev->link.ant.rssi_ant);
}
static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup new_ant;
int other_antenna;
int sample_current = rt2x00link_antenna_get_link_rssi(rt2x00dev);
int sample_other = rt2x00link_antenna_get_rssi_history(rt2x00dev);
memcpy(&new_ant, &ant->active, sizeof(new_ant));
/*
* We are done sampling. Now we should evaluate the results.
*/
ant->flags &= ~ANTENNA_MODE_SAMPLE;
/*
* During the last period we have sampled the RSSI
* from both antennas. It now is time to determine
* which antenna demonstrated the best performance.
* When we are already on the antenna with the best
* performance, just create a good starting point
* for the history and we are done.
*/
if (sample_current >= sample_other) {
rt2x00link_antenna_update_rssi_history(rt2x00dev,
sample_current);
return;
}
other_antenna = (ant->active.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
if (ant->flags & ANTENNA_RX_DIVERSITY)
new_ant.rx = other_antenna;
if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = other_antenna;
rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
static void rt2x00lib_antenna_diversity_eval(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup new_ant;
int rssi_curr;
int rssi_old;
memcpy(&new_ant, &ant->active, sizeof(new_ant));
/*
* Get current RSSI value along with the historical value,
* after that update the history with the current value.
*/
rssi_curr = rt2x00link_antenna_get_link_rssi(rt2x00dev);
rssi_old = rt2x00link_antenna_get_rssi_history(rt2x00dev);
rt2x00link_antenna_update_rssi_history(rt2x00dev, rssi_curr);
/*
* Legacy driver indicates that we should swap antenna's
* when the difference in RSSI is greater that 5. This
* also should be done when the RSSI was actually better
* then the previous sample.
* When the difference exceeds the threshold we should
* sample the rssi from the other antenna to make a valid
* comparison between the 2 antennas.
*/
if (abs(rssi_curr - rssi_old) < 5)
return;
ant->flags |= ANTENNA_MODE_SAMPLE;
if (ant->flags & ANTENNA_RX_DIVERSITY)
new_ant.rx = (new_ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
if (ant->flags & ANTENNA_TX_DIVERSITY)
new_ant.tx = (new_ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
rt2x00lib_config_antenna(rt2x00dev, new_ant);
}
static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
/*
* Determine if software diversity is enabled for
* either the TX or RX antenna (or both).
*/
if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
!(ant->flags & ANTENNA_TX_DIVERSITY)) {
ant->flags = 0;
return true;
}
/*
* If we have only sampled the data over the last period
* we should now harvest the data. Otherwise just evaluate
* the data. The latter should only be performed once
* every 2 seconds.
*/
if (ant->flags & ANTENNA_MODE_SAMPLE) {
rt2x00lib_antenna_diversity_sample(rt2x00dev);
return true;
} else if (rt2x00dev->link.count & 1) {
rt2x00lib_antenna_diversity_eval(rt2x00dev);
return true;
}
return false;
}
void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc)
{
struct link *link = &rt2x00dev->link;
struct link_qual *qual = &rt2x00dev->link.qual;
struct link_ant *ant = &rt2x00dev->link.ant;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
/*
* No need to update the stats for !=STA interfaces
*/
if (!rt2x00dev->intf_sta_count)
return;
/*
* Frame was received successfully since non-successful
* frames would have been dropped by the hardware.
*/
qual->rx_success++;
/*
* We are only interested in quality statistics from
* beacons which came from the BSS which we are
* associated with.
*/
if (!ieee80211_is_beacon(hdr->frame_control) ||
!(rxdesc->dev_flags & RXDONE_MY_BSS))
return;
/*
* Update global RSSI
*/
ewma_rssi_add(&link->avg_rssi, -rxdesc->rssi);
/*
* Update antenna RSSI
*/
ewma_rssi_add(&ant->rssi_ant, -rxdesc->rssi);
}
void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
{
struct link *link = &rt2x00dev->link;
/*
* Single monitor mode interfaces should never have
* work with link tuners.
*/
if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
return;
/*
* While scanning, link tuning is disabled. By default
* the most sensitive settings will be used to make sure
* that all beacons and probe responses will be received
* during the scan.
*/
if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
return;
rt2x00link_reset_tuner(rt2x00dev, false);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
{
cancel_delayed_work_sync(&rt2x00dev->link.work);
}
void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
{
struct link_qual *qual = &rt2x00dev->link.qual;
u8 vgc_level = qual->vgc_level_reg;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
/*
* Reset link information.
* Both the currently active vgc level as well as
* the link tuner counter should be reset. Resetting
* the counter is important for devices where the
* device should only perform link tuning during the
* first minute after being enabled.
*/
rt2x00dev->link.count = 0;
memset(qual, 0, sizeof(*qual));
ewma_rssi_init(&rt2x00dev->link.avg_rssi);
/*
* Restore the VGC level as stored in the registers,
* the driver can use this to determine if the register
* must be updated during reset or not.
*/
qual->vgc_level_reg = vgc_level;
/*
* Reset the link tuner.
*/
rt2x00dev->ops->lib->reset_tuner(rt2x00dev, qual);
if (antenna)
rt2x00link_antenna_reset(rt2x00dev);
}
static void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev)
{
struct link_qual *qual = &rt2x00dev->link.qual;
qual->rx_success = 0;
qual->rx_failed = 0;
qual->tx_success = 0;
qual->tx_failed = 0;
}
static void rt2x00link_tuner_sta(struct rt2x00_dev *rt2x00dev, struct link *link)
{
struct link_qual *qual = &rt2x00dev->link.qual;
/*
* Update statistics.
*/
rt2x00dev->ops->lib->link_stats(rt2x00dev, qual);
rt2x00dev->low_level_stats.dot11FCSErrorCount += qual->rx_failed;
/*
* Update quality RSSI for link tuning,
* when we have received some frames and we managed to
* collect the RSSI data we could use this. Otherwise we
* must fallback to the default RSSI value.
*/
if (!qual->rx_success)
qual->rssi = DEFAULT_RSSI;
else
qual->rssi = rt2x00link_get_avg_rssi(&link->avg_rssi);
/*
* Check if link tuning is supported by the hardware, some hardware
* do not support link tuning at all, while other devices can disable
* the feature from the EEPROM.
*/
if (rt2x00_has_cap_link_tuning(rt2x00dev))
rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
/*
* Send a signal to the led to update the led signal strength.
*/
rt2x00leds_led_quality(rt2x00dev, qual->rssi);
/*
* Evaluate antenna setup, make this the last step when
* rt2x00lib_antenna_diversity made changes the quality
* statistics will be reset.
*/
if (rt2x00lib_antenna_diversity(rt2x00dev))
rt2x00link_reset_qual(rt2x00dev);
}
static void rt2x00link_tuner(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, link.work.work);
struct link *link = &rt2x00dev->link;
/*
* When the radio is shutting down we should
* immediately cease all link tuning.
*/
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
return;
/* Do not race with rt2x00mac_config(). */
mutex_lock(&rt2x00dev->conf_mutex);
if (rt2x00dev->intf_sta_count)
rt2x00link_tuner_sta(rt2x00dev, link);
if (rt2x00dev->ops->lib->gain_calibration &&
(link->count % (AGC_SECONDS / LINK_TUNE_SECONDS)) == 0)
rt2x00dev->ops->lib->gain_calibration(rt2x00dev);
if (rt2x00dev->ops->lib->vco_calibration &&
rt2x00_has_cap_vco_recalibration(rt2x00dev) &&
(link->count % (VCO_SECONDS / LINK_TUNE_SECONDS)) == 0)
rt2x00dev->ops->lib->vco_calibration(rt2x00dev);
mutex_unlock(&rt2x00dev->conf_mutex);
/*
* Increase tuner counter, and reschedule the next link tuner run.
*/
link->count++;
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
{
struct link *link = &rt2x00dev->link;
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
rt2x00dev->ops->lib->watchdog && link->watchdog)
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
link->watchdog_interval);
}
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
{
cancel_delayed_work_sync(&rt2x00dev->link.watchdog_work);
}
static void rt2x00link_watchdog(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, link.watchdog_work.work);
struct link *link = &rt2x00dev->link;
/*
* When the radio is shutting down we should
* immediately cease the watchdog monitoring.
*/
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
rt2x00dev->ops->lib->watchdog(rt2x00dev);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
link->watchdog_interval);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
{
struct link *link = &rt2x00dev->link;
INIT_DELAYED_WORK(&link->work, rt2x00link_tuner);
INIT_DELAYED_WORK(&link->watchdog_work, rt2x00link_watchdog);
if (link->watchdog_interval == 0)
link->watchdog_interval = WATCHDOG_INTERVAL;
}
@@ -0,0 +1,840 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00mac
Abstract: rt2x00 generic mac80211 routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue,
struct sk_buff *frag_skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb);
struct ieee80211_tx_info *rts_info;
struct sk_buff *skb;
unsigned int data_length;
int retval = 0;
if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
data_length = sizeof(struct ieee80211_cts);
else
data_length = sizeof(struct ieee80211_rts);
skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom);
if (unlikely(!skb)) {
rt2x00_warn(rt2x00dev, "Failed to create RTS/CTS frame\n");
return -ENOMEM;
}
skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
skb_put(skb, data_length);
/*
* Copy TX information over from original frame to
* RTS/CTS frame. Note that we set the no encryption flag
* since we don't want this frame to be encrypted.
* RTS frames should be acked, while CTS-to-self frames
* should not. The ready for TX flag is cleared to prevent
* it being automatically send when the descriptor is
* written to the hardware.
*/
memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
rts_info = IEEE80211_SKB_CB(skb);
rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
else
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
/* Disable hardware encryption */
rts_info->control.hw_key = NULL;
/*
* RTS/CTS frame should use the length of the frame plus any
* encryption overhead that will be added by the hardware.
*/
data_length += rt2x00crypto_tx_overhead(rt2x00dev, skb);
if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
frag_skb->data, data_length, tx_info,
(struct ieee80211_cts *)(skb->data));
else
ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif,
frag_skb->data, data_length, tx_info,
(struct ieee80211_rts *)(skb->data));
retval = rt2x00queue_write_tx_frame(queue, skb, NULL, true);
if (retval) {
dev_kfree_skb_any(skb);
rt2x00_warn(rt2x00dev, "Failed to send RTS/CTS frame\n");
}
return retval;
}
void rt2x00mac_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
enum data_queue_qid qid = skb_get_queue_mapping(skb);
struct data_queue *queue = NULL;
/*
* Mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
* Note that we can only stop the TX queues inside the TX path
* due to possible race conditions in mac80211.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
goto exit_free_skb;
/*
* Use the ATIM queue if appropriate and present.
*/
if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE))
qid = QID_ATIM;
queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
if (unlikely(!queue)) {
rt2x00_err(rt2x00dev,
"Attempt to send packet over invalid queue %d\n"
"Please file bug report to %s\n", qid, DRV_PROJECT);
goto exit_free_skb;
}
/*
* If CTS/RTS is required. create and queue that frame first.
* Make sure we have at least enough entries available to send
* this CTS/RTS frame as well as the data frame.
* Note that when the driver has set the set_rts_threshold()
* callback function it doesn't need software generation of
* either RTS or CTS-to-self frame and handles everything
* inside the hardware.
*/
if (!rt2x00dev->ops->hw->set_rts_threshold &&
(tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
IEEE80211_TX_RC_USE_CTS_PROTECT))) {
if (rt2x00queue_available(queue) <= 1) {
/*
* Recheck for full queue under lock to avoid race
* conditions with rt2x00lib_txdone().
*/
spin_lock(&queue->tx_lock);
if (rt2x00queue_threshold(queue))
rt2x00queue_pause_queue(queue);
spin_unlock(&queue->tx_lock);
goto exit_free_skb;
}
if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb))
goto exit_free_skb;
}
if (unlikely(rt2x00queue_write_tx_frame(queue, skb, control->sta, false)))
goto exit_free_skb;
return;
exit_free_skb:
ieee80211_free_txskb(hw, skb);
}
EXPORT_SYMBOL_GPL(rt2x00mac_tx);
int rt2x00mac_start(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) {
/*
* This is special case for ieee80211_restart_hw(), otherwise
* mac80211 never call start() two times in row without stop();
*/
set_bit(DEVICE_STATE_RESET, &rt2x00dev->flags);
rt2x00dev->ops->lib->pre_reset_hw(rt2x00dev);
rt2x00lib_stop(rt2x00dev);
}
return rt2x00lib_start(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_start);
void rt2x00mac_stop(struct ieee80211_hw *hw, bool suspend)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
rt2x00lib_stop(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_stop);
void
rt2x00mac_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART)
clear_bit(DEVICE_STATE_RESET, &rt2x00dev->flags);
}
EXPORT_SYMBOL_GPL(rt2x00mac_reconfig_complete);
int rt2x00mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
struct data_queue *queue = rt2x00dev->bcn;
struct queue_entry *entry = NULL;
unsigned int i;
/*
* Don't allow interfaces to be added
* the device has disappeared.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
return -ENODEV;
/*
* Loop through all beacon queues to find a free
* entry. Since there are as much beacon entries
* as the maximum interfaces, this search shouldn't
* fail.
*/
for (i = 0; i < queue->limit; i++) {
entry = &queue->entries[i];
if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags))
break;
}
if (unlikely(i == queue->limit))
return -ENOBUFS;
/*
* We are now absolutely sure the interface can be created,
* increase interface count and start initialization.
*/
if (vif->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count++;
else
rt2x00dev->intf_sta_count++;
mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
/*
* The MAC address must be configured after the device
* has been initialized. Otherwise the device can reset
* the MAC registers.
* The BSSID address must only be configured in AP mode,
* however we should not send an empty BSSID address for
* STA interfaces at this time, since this can cause
* invalid behavior in the device.
*/
rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
vif->addr, NULL);
/*
* Some filters depend on the current working mode. We can force
* an update during the next configure_filter() run by mac80211 by
* resetting the current packet_filter state.
*/
rt2x00dev->packet_filter = 0;
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
/*
* Don't allow interfaces to be remove while
* either the device has disappeared or when
* no interface is present.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
(vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
(vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
return;
if (vif->type == NL80211_IFTYPE_AP)
rt2x00dev->intf_ap_count--;
else
rt2x00dev->intf_sta_count--;
/*
* Release beacon entry so it is available for
* new interfaces again.
*/
clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags);
/*
* Make sure the bssid and mac address registers
* are cleared to prevent false ACKing of frames.
*/
rt2x00lib_config_intf(rt2x00dev, intf,
NL80211_IFTYPE_UNSPECIFIED, NULL, NULL);
}
EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
int rt2x00mac_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
/*
* mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
/*
* Some configuration parameters (e.g. channel and antenna values) can
* only be set when the radio is enabled, but do require the RX to
* be off. During this period we should keep link tuning enabled,
* if for any reason the link tuner must be reset, this will be
* handled by rt2x00lib_config().
*/
rt2x00queue_stop_queue(rt2x00dev->rx);
/* Do not race with link tuner. */
mutex_lock(&rt2x00dev->conf_mutex);
/*
* When we've just turned on the radio, we want to reprogram
* everything to ensure a consistent state
*/
rt2x00lib_config(rt2x00dev, conf, changed);
/*
* After the radio has been enabled we need to configure
* the antenna to the default settings. rt2x00lib_config_antenna()
* should determine if any action should be taken based on
* checking if diversity has been enabled or no antenna changes
* have been made since the last configuration change.
*/
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
mutex_unlock(&rt2x00dev->conf_mutex);
/* Turn RX back on */
rt2x00queue_start_queue(rt2x00dev->rx);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_config);
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* Mask off any flags we are going to ignore
* from the total_flags field.
*/
*total_flags &=
FIF_ALLMULTI |
FIF_FCSFAIL |
FIF_PLCPFAIL |
FIF_CONTROL |
FIF_PSPOLL |
FIF_OTHER_BSS;
/*
* Apply some rules to the filters:
* - Some filters imply different filters to be set.
* - Some things we can't filter out at all.
* - Multicast filter seems to kill broadcast traffic so never use it.
*/
*total_flags |= FIF_ALLMULTI;
/*
* If the device has a single filter for all control frames,
* FIF_CONTROL and FIF_PSPOLL flags imply each other.
* And if the device has more than one filter for control frames
* of different types, but has no a separate filter for PS Poll frames,
* FIF_CONTROL flag implies FIF_PSPOLL.
*/
if (!rt2x00_has_cap_control_filters(rt2x00dev)) {
if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL)
*total_flags |= FIF_CONTROL | FIF_PSPOLL;
}
if (!rt2x00_has_cap_control_filter_pspoll(rt2x00dev)) {
if (*total_flags & FIF_CONTROL)
*total_flags |= FIF_PSPOLL;
}
rt2x00dev->packet_filter = *total_flags;
rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
static void rt2x00mac_set_tim_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rt2x00_intf *intf = vif_to_intf(vif);
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_ADHOC &&
vif->type != NL80211_IFTYPE_MESH_POINT)
return;
set_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags);
}
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return 0;
ieee80211_iterate_active_interfaces_atomic(
rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
rt2x00mac_set_tim_iter, rt2x00dev);
/* queue work to upodate the beacon template */
ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
{
if (key_len > NL80211_TKIP_DATA_OFFSET_ENCR_KEY)
memcpy(crypto->key,
&key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY],
sizeof(crypto->key));
if (key_len > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
memcpy(crypto->tx_mic,
&key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
sizeof(crypto->tx_mic));
if (key_len > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY)
memcpy(crypto->rx_mic,
&key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
sizeof(crypto->rx_mic));
}
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
int (*set_key) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
struct rt2x00lib_crypto crypto;
static const u8 bcast_addr[ETH_ALEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, };
struct rt2x00_sta *sta_priv = NULL;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
/* The hardware can't do MFP */
if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || (sta && sta->mfp))
return -EOPNOTSUPP;
/*
* To support IBSS RSN, don't program group keys in IBSS, the
* hardware will then not attempt to decrypt the frames.
*/
if (vif->type == NL80211_IFTYPE_ADHOC &&
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -EOPNOTSUPP;
if (key->keylen > 32)
return -ENOSPC;
memset(&crypto, 0, sizeof(crypto));
crypto.bssidx = rt2x00lib_get_bssidx(rt2x00dev, vif);
crypto.cipher = rt2x00crypto_key_to_cipher(key);
if (crypto.cipher == CIPHER_NONE)
return -EOPNOTSUPP;
if (crypto.cipher == CIPHER_TKIP && rt2x00_is_usb(rt2x00dev))
return -EOPNOTSUPP;
crypto.cmd = cmd;
if (sta) {
crypto.address = sta->addr;
sta_priv = sta_to_rt2x00_sta(sta);
crypto.wcid = sta_priv->wcid;
} else
crypto.address = bcast_addr;
if (crypto.cipher == CIPHER_TKIP)
memcpy_tkip(&crypto, &key->key[0], key->keylen);
else
memcpy(crypto.key, &key->key[0], key->keylen);
/*
* Each BSS has a maximum of 4 shared keys.
* Shared key index values:
* 0) BSS0 key0
* 1) BSS0 key1
* ...
* 4) BSS1 key0
* ...
* 8) BSS2 key0
* ...
* Both pairwise as shared key indeces are determined by
* driver. This is required because the hardware requires
* keys to be assigned in correct order (When key 1 is
* provided but key 0 is not, then the key is not found
* by the hardware during RX).
*/
if (cmd == SET_KEY)
key->hw_key_idx = 0;
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
set_key = rt2x00dev->ops->lib->config_pairwise_key;
else
set_key = rt2x00dev->ops->lib->config_shared_key;
if (!set_key)
return -EOPNOTSUPP;
return set_key(rt2x00dev, &crypto, key);
}
EXPORT_SYMBOL_GPL(rt2x00mac_set_key);
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const u8 *mac_addr)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
rt2x00link_stop_tuner(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start);
void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
rt2x00link_start_tuner(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete);
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* The dot11ACKFailureCount, dot11RTSFailureCount and
* dot11RTSSuccessCount are updated in interrupt time.
* dot11FCSErrorCount is updated in the link tuner.
*/
memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats));
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u64 changes)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
/*
* mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
/*
* Update the BSSID.
*/
if (changes & BSS_CHANGED_BSSID)
rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
bss_conf->bssid);
/*
* Start/stop beaconing.
*/
if (changes & BSS_CHANGED_BEACON_ENABLED) {
mutex_lock(&intf->beacon_skb_mutex);
/*
* Clear the 'enable_beacon' flag and clear beacon because
* the beacon queue has been stopped after hardware reset.
*/
if (test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags) &&
intf->enable_beacon) {
intf->enable_beacon = false;
rt2x00queue_clear_beacon(rt2x00dev, vif);
}
if (!bss_conf->enable_beacon && intf->enable_beacon) {
rt2x00dev->intf_beaconing--;
intf->enable_beacon = false;
if (rt2x00dev->intf_beaconing == 0) {
/*
* Last beaconing interface disabled
* -> stop beacon queue.
*/
rt2x00queue_stop_queue(rt2x00dev->bcn);
}
/*
* Clear beacon in the H/W for this vif. This is needed
* to disable beaconing on this particular interface
* and keep it running on other interfaces.
*/
rt2x00queue_clear_beacon(rt2x00dev, vif);
} else if (bss_conf->enable_beacon && !intf->enable_beacon) {
rt2x00dev->intf_beaconing++;
intf->enable_beacon = true;
/*
* Upload beacon to the H/W. This is only required on
* USB devices. PCI devices fetch beacons periodically.
*/
if (rt2x00_is_usb(rt2x00dev))
rt2x00queue_update_beacon(rt2x00dev, vif);
if (rt2x00dev->intf_beaconing == 1) {
/*
* First beaconing interface enabled
* -> start beacon queue.
*/
rt2x00queue_start_queue(rt2x00dev->bcn);
}
}
mutex_unlock(&intf->beacon_skb_mutex);
}
/*
* When the association status has changed we must reset the link
* tuner counter. This is because some drivers determine if they
* should perform link tuning based on the number of seconds
* while associated or not associated.
*/
if (changes & BSS_CHANGED_ASSOC) {
rt2x00dev->link.count = 0;
if (vif->cfg.assoc)
rt2x00dev->intf_associated++;
else
rt2x00dev->intf_associated--;
rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
}
/*
* When the erp information has changed, we should perform
* additional configuration steps. For all other changes we are done.
*/
if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE |
BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BASIC_RATES |
BSS_CHANGED_BEACON_INT | BSS_CHANGED_HT))
rt2x00lib_config_erp(rt2x00dev, intf, bss_conf, changes);
}
EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
unsigned int link_id, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx);
if (unlikely(!queue))
return -EINVAL;
/*
* The passed variables are stored as real value ((2^n)-1).
* Ralink registers require to know the bit number 'n'.
*/
if (params->cw_min > 0)
queue->cw_min = fls(params->cw_min);
else
queue->cw_min = 5; /* cw_min: 2^5 = 32. */
if (params->cw_max > 0)
queue->cw_max = fls(params->cw_max);
else
queue->cw_max = 10; /* cw_min: 2^10 = 1024. */
queue->aifs = params->aifs;
queue->txop = params->txop;
rt2x00_dbg(rt2x00dev,
"Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d\n",
queue_idx, queue->cw_min, queue->cw_max, queue->aifs,
queue->txop);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
bool active = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
wiphy_rfkill_set_hw_state(hw->wiphy, !active);
}
EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
set_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_flush_queue(queue, drop);
clear_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
}
EXPORT_SYMBOL_GPL(rt2x00mac_flush);
int rt2x00mac_set_antenna(struct ieee80211_hw *hw, int radio_idx,
u32 tx_ant, u32 rx_ant)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup *def = &rt2x00dev->default_ant;
struct antenna_setup setup;
// The antenna value is not supposed to be 0,
// or exceed the maximum number of antenna's.
if (!tx_ant || (tx_ant & ~3) || !rx_ant || (rx_ant & ~3))
return -EINVAL;
// When the client tried to configure the antenna to or from
// diversity mode, we must reset the default antenna as well
// as that controls the diversity switch.
if (ant->flags & ANTENNA_TX_DIVERSITY && tx_ant != 3)
ant->flags &= ~ANTENNA_TX_DIVERSITY;
if (ant->flags & ANTENNA_RX_DIVERSITY && rx_ant != 3)
ant->flags &= ~ANTENNA_RX_DIVERSITY;
// If diversity is being enabled, check if we need hardware
// or software diversity. In the latter case, reset the value,
// and make sure we update the antenna flags to have the
// link tuner pick up the diversity tuning.
if (tx_ant == 3 && def->tx == ANTENNA_SW_DIVERSITY) {
tx_ant = ANTENNA_SW_DIVERSITY;
ant->flags |= ANTENNA_TX_DIVERSITY;
}
if (rx_ant == 3 && def->rx == ANTENNA_SW_DIVERSITY) {
rx_ant = ANTENNA_SW_DIVERSITY;
ant->flags |= ANTENNA_RX_DIVERSITY;
}
setup.tx = tx_ant;
setup.rx = rx_ant;
setup.rx_chain_num = 0;
setup.tx_chain_num = 0;
rt2x00lib_config_antenna(rt2x00dev, setup);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_set_antenna);
int rt2x00mac_get_antenna(struct ieee80211_hw *hw, int radio_idx,
u32 *tx_ant, u32 *rx_ant)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct link_ant *ant = &rt2x00dev->link.ant;
struct antenna_setup *active = &rt2x00dev->link.ant.active;
// When software diversity is active, we must report this to the
// client and not the current active antenna state.
if (ant->flags & ANTENNA_TX_DIVERSITY)
*tx_ant = ANTENNA_HW_DIVERSITY;
else
*tx_ant = active->tx;
if (ant->flags & ANTENNA_RX_DIVERSITY)
*rx_ant = ANTENNA_HW_DIVERSITY;
else
*rx_ant = active->rx;
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_get_antenna);
void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
tx_queue_for_each(rt2x00dev, queue) {
*tx += queue->length;
*tx_max += queue->limit;
}
*rx = rt2x00dev->rx->length;
*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);
@@ -0,0 +1,201 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00mmio
Abstract: rt2x00 generic mmio device routines.
*/
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "rt2x00.h"
#include "rt2x00mmio.h"
/*
* Register access.
*/
int rt2x00mmio_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field,
u32 *reg)
{
unsigned int i;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
*reg = rt2x00mmio_register_read(rt2x00dev, offset);
if (!rt2x00_get_field32(*reg, field))
return 1;
udelay(REGISTER_BUSY_DELAY);
}
printk_once(KERN_ERR "%s() Indirect register access failed: "
"offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg);
*reg = ~0;
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mmio_regbusy_read);
bool rt2x00mmio_rxdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue = rt2x00dev->rx;
struct queue_entry *entry;
struct queue_entry_priv_mmio *entry_priv;
struct skb_frame_desc *skbdesc;
int max_rx = 16;
while (--max_rx) {
entry = rt2x00queue_get_entry(queue, Q_INDEX);
entry_priv = entry->priv_data;
if (rt2x00dev->ops->lib->get_entry_state(entry))
break;
/*
* Fill in desc fields of the skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = entry->queue->desc_size;
/*
* DMA is already done, notify rt2x00lib that
* it finished successfully.
*/
rt2x00lib_dmastart(entry);
rt2x00lib_dmadone(entry);
/*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(entry, GFP_ATOMIC);
}
return !max_rx;
}
EXPORT_SYMBOL_GPL(rt2x00mmio_rxdone);
void rt2x00mmio_flush_queue(struct data_queue *queue, bool drop)
{
unsigned int i;
for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
msleep(50);
}
EXPORT_SYMBOL_GPL(rt2x00mmio_flush_queue);
/*
* Device initialization handlers.
*/
static int rt2x00mmio_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
struct queue_entry_priv_mmio *entry_priv;
void *addr;
dma_addr_t dma;
unsigned int i;
/*
* Allocate DMA memory for descriptor and buffer.
*/
addr = dma_alloc_coherent(rt2x00dev->dev,
queue->limit * queue->desc_size, &dma,
GFP_KERNEL);
if (!addr)
return -ENOMEM;
/*
* Initialize all queue entries to contain valid addresses.
*/
for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data;
entry_priv->desc = addr + i * queue->desc_size;
entry_priv->desc_dma = dma + i * queue->desc_size;
}
return 0;
}
static void rt2x00mmio_free_queue_dma(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
struct queue_entry_priv_mmio *entry_priv =
queue->entries[0].priv_data;
if (entry_priv->desc)
dma_free_coherent(rt2x00dev->dev,
queue->limit * queue->desc_size,
entry_priv->desc, entry_priv->desc_dma);
entry_priv->desc = NULL;
}
int rt2x00mmio_initialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
int status;
/*
* Allocate DMA
*/
queue_for_each(rt2x00dev, queue) {
status = rt2x00mmio_alloc_queue_dma(rt2x00dev, queue);
if (status)
goto exit;
}
/*
* Register interrupt handler.
*/
status = request_irq(rt2x00dev->irq,
rt2x00dev->ops->lib->irq_handler,
IRQF_SHARED, rt2x00dev->name, rt2x00dev);
if (status) {
rt2x00_err(rt2x00dev, "IRQ %d allocation failed (error %d)\n",
rt2x00dev->irq, status);
goto exit;
}
return 0;
exit:
queue_for_each(rt2x00dev, queue)
rt2x00mmio_free_queue_dma(rt2x00dev, queue);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00mmio_initialize);
void rt2x00mmio_uninitialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
/*
* Free irq line.
*/
free_irq(rt2x00dev->irq, rt2x00dev);
/*
* Free DMA
*/
queue_for_each(rt2x00dev, queue)
rt2x00mmio_free_queue_dma(rt2x00dev, queue);
}
EXPORT_SYMBOL_GPL(rt2x00mmio_uninitialize);
/*
* rt2x00mmio module information.
*/
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("rt2x00 mmio library");
MODULE_LICENSE("GPL");
@@ -0,0 +1,103 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00mmio
Abstract: Data structures for the rt2x00mmio module.
*/
#ifndef RT2X00MMIO_H
#define RT2X00MMIO_H
#include <linux/io.h>
/*
* Register access.
*/
static inline u32 rt2x00mmio_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset)
{
return readl(rt2x00dev->csr.base + offset);
}
static inline void rt2x00mmio_register_multiread(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u32 length)
{
memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
}
static inline void rt2x00mmio_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
writel(value, rt2x00dev->csr.base + offset);
}
static inline void rt2x00mmio_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const void *value,
const u32 length)
{
__iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
}
/**
* rt2x00mmio_regbusy_read - Read from register with busy check
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @field: Field to check if register is busy
* @reg: Pointer to where register contents should be stored
*
* This function will read the given register, and checks if the
* register is busy. If it is, it will sleep for a couple of
* microseconds before reading the register again. If the register
* is not read after a certain timeout, this function will return
* FALSE.
*/
int rt2x00mmio_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field,
u32 *reg);
/**
* struct queue_entry_priv_mmio: Per entry PCI specific information
*
* @desc: Pointer to device descriptor
* @desc_dma: DMA pointer to &desc.
*/
struct queue_entry_priv_mmio {
__le32 *desc;
dma_addr_t desc_dma;
};
/**
* rt2x00mmio_rxdone - Handle RX done events
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
*
* Returns true if there are still rx frames pending and false if all
* pending rx frames were processed.
*/
bool rt2x00mmio_rxdone(struct rt2x00_dev *rt2x00dev);
/**
* rt2x00mmio_flush_queue - Flush data queue
* @queue: Data queue to stop
* @drop: True to drop all pending frames.
*
* This will wait for a maximum of 100ms, waiting for the queues
* to become empty.
*/
void rt2x00mmio_flush_queue(struct data_queue *queue, bool drop);
/*
* Device initialization handlers.
*/
int rt2x00mmio_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00mmio_uninitialize(struct rt2x00_dev *rt2x00dev);
#endif /* RT2X00MMIO_H */
@@ -0,0 +1,197 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00pci
Abstract: rt2x00 generic pci device routines.
*/
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "rt2x00.h"
#include "rt2x00pci.h"
/*
* PCI driver handlers.
*/
static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
{
kfree(rt2x00dev->rf);
rt2x00dev->rf = NULL;
kfree(rt2x00dev->eeprom);
rt2x00dev->eeprom = NULL;
if (rt2x00dev->csr.base) {
iounmap(rt2x00dev->csr.base);
rt2x00dev->csr.base = NULL;
}
}
static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0);
if (!rt2x00dev->csr.base)
goto exit;
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
if (!rt2x00dev->eeprom)
goto exit;
rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
if (!rt2x00dev->rf)
goto exit;
return 0;
exit:
rt2x00_probe_err("Failed to allocate registers\n");
rt2x00pci_free_reg(rt2x00dev);
return -ENOMEM;
}
int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
{
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
u16 chip;
retval = pci_enable_device(pci_dev);
if (retval) {
rt2x00_probe_err("Enable device failed\n");
return retval;
}
retval = pci_request_regions(pci_dev, pci_name(pci_dev));
if (retval) {
rt2x00_probe_err("PCI request regions failed\n");
goto exit_disable_device;
}
pci_set_master(pci_dev);
if (pci_set_mwi(pci_dev))
rt2x00_probe_err("MWI not available\n");
if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
rt2x00_probe_err("PCI DMA not supported\n");
retval = -EIO;
goto exit_release_regions;
}
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw) {
rt2x00_probe_err("Failed to allocate hardware\n");
retval = -ENOMEM;
goto exit_release_regions;
}
pci_set_drvdata(pci_dev, hw);
rt2x00dev = hw->priv;
rt2x00dev->dev = &pci_dev->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
rt2x00dev->irq = pci_dev->irq;
rt2x00dev->name = ops->name;
if (pci_is_pcie(pci_dev))
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
else
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
retval = rt2x00pci_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
/*
* Because rt3290 chip use different efuse offset to read efuse data.
* So before read efuse it need to indicate it is the
* rt3290 or not.
*/
pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip);
rt2x00dev->chip.rt = chip;
retval = rt2x00lib_probe_dev(rt2x00dev);
if (retval)
goto exit_free_reg;
return 0;
exit_free_reg:
rt2x00pci_free_reg(rt2x00dev);
exit_free_device:
ieee80211_free_hw(hw);
exit_release_regions:
pci_clear_mwi(pci_dev);
pci_release_regions(pci_dev);
exit_disable_device:
pci_disable_device(pci_dev);
return retval;
}
EXPORT_SYMBOL_GPL(rt2x00pci_probe);
void rt2x00pci_remove(struct pci_dev *pci_dev)
{
struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* Free all allocated data.
*/
rt2x00lib_remove_dev(rt2x00dev);
rt2x00pci_free_reg(rt2x00dev);
ieee80211_free_hw(hw);
/*
* Free the PCI device data.
*/
pci_clear_mwi(pci_dev);
pci_disable_device(pci_dev);
pci_release_regions(pci_dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_remove);
static int __maybe_unused rt2x00pci_suspend(struct device *dev)
{
struct ieee80211_hw *hw = dev_get_drvdata(dev);
struct rt2x00_dev *rt2x00dev = hw->priv;
return rt2x00lib_suspend(rt2x00dev);
}
static int __maybe_unused rt2x00pci_resume(struct device *dev)
{
struct ieee80211_hw *hw = dev_get_drvdata(dev);
struct rt2x00_dev *rt2x00dev = hw->priv;
return rt2x00lib_resume(rt2x00dev);
}
SIMPLE_DEV_PM_OPS(rt2x00pci_pm_ops, rt2x00pci_suspend, rt2x00pci_resume);
EXPORT_SYMBOL_GPL(rt2x00pci_pm_ops);
/*
* rt2x00pci module information.
*/
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("rt2x00 pci library");
MODULE_LICENSE("GPL");
@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00pci
Abstract: Data structures for the rt2x00pci module.
*/
#ifndef RT2X00PCI_H
#define RT2X00PCI_H
#include <linux/io.h>
#include <linux/pci.h>
/*
* PCI driver handlers.
*/
int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops);
void rt2x00pci_remove(struct pci_dev *pci_dev);
extern const struct dev_pm_ops rt2x00pci_pm_ops;
#endif /* RT2X00PCI_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,677 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00
Abstract: rt2x00 queue datastructures and routines
*/
#ifndef RT2X00QUEUE_H
#define RT2X00QUEUE_H
#include <linux/prefetch.h>
/**
* DOC: Entry frame size
*
* Ralink PCI devices demand the Frame size to be a multiple of 128 bytes,
* for USB devices this restriction does not apply, but the value of
* 2432 makes sense since it is big enough to contain the maximum fragment
* size according to the ieee802.11 specs.
* The aggregation size depends on support from the driver, but should
* be something around 3840 bytes.
*/
#define DATA_FRAME_SIZE 2432
#define MGMT_FRAME_SIZE 256
#define AGGREGATION_SIZE 3840
/**
* enum data_queue_qid: Queue identification
*
* @QID_AC_VO: AC VO queue
* @QID_AC_VI: AC VI queue
* @QID_AC_BE: AC BE queue
* @QID_AC_BK: AC BK queue
* @QID_HCCA: HCCA queue
* @QID_MGMT: MGMT queue (prio queue)
* @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 unspecified, don't send it to device)
*/
enum data_queue_qid {
QID_AC_VO = 0,
QID_AC_VI = 1,
QID_AC_BE = 2,
QID_AC_BK = 3,
QID_HCCA = 4,
QID_MGMT = 13,
QID_RX = 14,
QID_OTHER = 15,
QID_BEACON,
QID_ATIM,
};
/**
* enum skb_frame_desc_flags: Flags for &struct skb_frame_desc
*
* @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX
* @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
* @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by
* mac80211 but was stripped for processing by the driver.
* @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
* don't try to pass it back.
* @SKBDESC_DESC_IN_SKB: The descriptor is at the start of the
* skb, instead of in the desc field.
*/
enum skb_frame_desc_flags {
SKBDESC_DMA_MAPPED_RX = 1 << 0,
SKBDESC_DMA_MAPPED_TX = 1 << 1,
SKBDESC_IV_STRIPPED = 1 << 2,
SKBDESC_NOT_MAC80211 = 1 << 3,
SKBDESC_DESC_IN_SKB = 1 << 4,
};
/**
* struct skb_frame_desc: Descriptor information for the skb buffer
*
* This structure is placed over the driver_data array, this means that
* this structure should not exceed the size of that array (40 bytes).
*
* @flags: Frame flags, see &enum skb_frame_desc_flags.
* @desc_len: Length of the frame descriptor.
* @tx_rate_idx: the index of the TX rate, used for TX status reporting
* @tx_rate_flags: the TX rate flags, used for TX status reporting
* @desc: Pointer to descriptor part of the frame.
* Note that this pointer could point to something outside
* of the scope of the skb->data pointer.
* @iv: IV/EIV data used during encryption/decryption.
* @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
* @sta: The station where sk buffer was sent.
*/
struct skb_frame_desc {
u8 flags;
u8 desc_len;
u8 tx_rate_idx;
u8 tx_rate_flags;
void *desc;
__le32 iv[2];
dma_addr_t skb_dma;
struct ieee80211_sta *sta;
};
/**
* get_skb_frame_desc - Obtain the rt2x00 frame descriptor from a sk_buff.
* @skb: &struct sk_buff from where we obtain the &struct skb_frame_desc
*/
static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb)
{
BUILD_BUG_ON(sizeof(struct skb_frame_desc) >
IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
return (struct skb_frame_desc *)&IEEE80211_SKB_CB(skb)->driver_data;
}
/**
* enum rxdone_entry_desc_flags: Flags for &struct rxdone_entry_desc
*
* @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value.
* @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value.
* @RXDONE_SIGNAL_MCS: Signal field contains the mcs value.
* @RXDONE_MY_BSS: Does this frame originate from device's BSS.
* @RXDONE_CRYPTO_IV: Driver provided IV/EIV data.
* @RXDONE_CRYPTO_ICV: Driver provided ICV data.
* @RXDONE_L2PAD: 802.11 payload has been padded to 4-byte boundary.
*/
enum rxdone_entry_desc_flags {
RXDONE_SIGNAL_PLCP = BIT(0),
RXDONE_SIGNAL_BITRATE = BIT(1),
RXDONE_SIGNAL_MCS = BIT(2),
RXDONE_MY_BSS = BIT(3),
RXDONE_CRYPTO_IV = BIT(4),
RXDONE_CRYPTO_ICV = BIT(5),
RXDONE_L2PAD = BIT(6),
};
/**
* RXDONE_SIGNAL_MASK - Define to mask off all &rxdone_entry_desc_flags flags
* except for the RXDONE_SIGNAL_* flags. This is useful to convert the dev_flags
* from &rxdone_entry_desc to a signal value type.
*/
#define RXDONE_SIGNAL_MASK \
( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE | RXDONE_SIGNAL_MCS )
/**
* struct rxdone_entry_desc: RX Entry descriptor
*
* Summary of information that has been read from the RX frame descriptor.
*
* @timestamp: RX Timestamp
* @signal: Signal of the received frame.
* @rssi: RSSI of the received frame.
* @size: Data size of the received frame.
* @flags: MAC80211 receive flags (See &enum mac80211_rx_flags).
* @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags).
* @rate_mode: Rate mode (See @enum rate_modulation).
* @cipher: Cipher type used during decryption.
* @cipher_status: Decryption status.
* @iv: IV/EIV data used during decryption.
* @icv: ICV data used during decryption.
*/
struct rxdone_entry_desc {
u64 timestamp;
int signal;
int rssi;
int size;
int flags;
int dev_flags;
u16 rate_mode;
u16 enc_flags;
enum mac80211_rx_encoding encoding;
enum rate_info_bw bw;
u8 cipher;
u8 cipher_status;
__le32 iv[2];
__le32 icv;
};
/**
* enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc
*
* Every txdone report has to contain the basic result of the
* transmission, either &TXDONE_UNKNOWN, &TXDONE_SUCCESS or
* &TXDONE_FAILURE. The flag &TXDONE_FALLBACK can be used in
* conjunction with all of these flags but should only be set
* if retires > 0. The flag &TXDONE_EXCESSIVE_RETRY can only be used
* in conjunction with &TXDONE_FAILURE.
*
* @TXDONE_UNKNOWN: Hardware could not determine success of transmission.
* @TXDONE_SUCCESS: Frame was successfully send
* @TXDONE_FALLBACK: Hardware used fallback rates for retries
* @TXDONE_FAILURE: Frame was not successfully send
* @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the
* frame transmission failed due to excessive retries.
*/
enum txdone_entry_desc_flags {
TXDONE_UNKNOWN,
TXDONE_SUCCESS,
TXDONE_FALLBACK,
TXDONE_FAILURE,
TXDONE_EXCESSIVE_RETRY,
TXDONE_AMPDU,
TXDONE_NO_ACK_REQ,
};
/**
* struct txdone_entry_desc: TX done entry descriptor
*
* Summary of information that has been read from the TX frame descriptor
* after the device is done with transmission.
*
* @flags: TX done flags (See &enum txdone_entry_desc_flags).
* @retry: Retry count.
*/
struct txdone_entry_desc {
unsigned long flags;
int retry;
};
/**
* enum txentry_desc_flags: Status flags for TX entry descriptor
*
* @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame.
* @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame.
* @ENTRY_TXD_GENERATE_SEQ: This frame requires sequence counter.
* @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame.
* @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
* @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted.
* @ENTRY_TXD_BURST: This frame belongs to the same burst event.
* @ENTRY_TXD_ACK: An ACK is required for this frame.
* @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used.
* @ENTRY_TXD_ENCRYPT: This frame should be encrypted.
* @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared).
* @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware.
* @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware.
* @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU.
* @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth.
* @ENTRY_TXD_HT_SHORT_GI: Use short GI.
* @ENTRY_TXD_HT_MIMO_PS: The receiving STA is in dynamic SM PS mode.
*/
enum txentry_desc_flags {
ENTRY_TXD_RTS_FRAME,
ENTRY_TXD_CTS_FRAME,
ENTRY_TXD_GENERATE_SEQ,
ENTRY_TXD_FIRST_FRAGMENT,
ENTRY_TXD_MORE_FRAG,
ENTRY_TXD_REQ_TIMESTAMP,
ENTRY_TXD_BURST,
ENTRY_TXD_ACK,
ENTRY_TXD_RETRY_MODE,
ENTRY_TXD_ENCRYPT,
ENTRY_TXD_ENCRYPT_PAIRWISE,
ENTRY_TXD_ENCRYPT_IV,
ENTRY_TXD_ENCRYPT_MMIC,
ENTRY_TXD_HT_AMPDU,
ENTRY_TXD_HT_BW_40,
ENTRY_TXD_HT_SHORT_GI,
ENTRY_TXD_HT_MIMO_PS,
};
/**
* struct txentry_desc: TX Entry descriptor
*
* Summary of information for the frame descriptor before sending a TX frame.
*
* @flags: Descriptor flags (See &enum queue_entry_flags).
* @length: Length of the entire frame.
* @header_length: Length of 802.11 header.
* @length_high: PLCP length high word.
* @length_low: PLCP length low word.
* @signal: PLCP signal.
* @service: PLCP service.
* @msc: MCS.
* @stbc: Use Space Time Block Coding (only available for MCS rates < 8).
* @ba_size: Size of the recepients RX reorder buffer - 1.
* @rate_mode: Rate mode (See @enum rate_modulation).
* @mpdu_density: MDPU density.
* @retry_limit: Max number of retries.
* @ifs: IFS value.
* @txop: IFS value for 11n capable chips.
* @cipher: Cipher type used for encryption.
* @key_idx: Key index used for encryption.
* @iv_offset: Position where IV should be inserted by hardware.
* @iv_len: Length of IV data.
*/
struct txentry_desc {
unsigned long flags;
u16 length;
u16 header_length;
union {
struct {
u16 length_high;
u16 length_low;
u16 signal;
u16 service;
enum ifs ifs;
} plcp;
struct {
u16 mcs;
u8 stbc;
u8 ba_size;
u8 mpdu_density;
enum txop txop;
int wcid;
} ht;
} u;
enum rate_modulation rate_mode;
short retry_limit;
enum cipher cipher;
u16 key_idx;
u16 iv_offset;
u16 iv_len;
};
/**
* enum queue_entry_flags: Status flags for queue entry
*
* @ENTRY_BCN_ASSIGNED: This entry has been assigned to an interface.
* As long as this bit is set, this entry may only be touched
* through the interface structure.
* @ENTRY_OWNER_DEVICE_DATA: This entry is owned by the device for data
* transfer (either TX or RX depending on the queue). The entry should
* only be touched after the device has signaled it is done with it.
* @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting
* for the signal to start sending.
* @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occurred
* while transferring the data to the hardware. No TX status report will
* be expected from the hardware.
* @ENTRY_DATA_STATUS_PENDING: The entry has been send to the device and
* returned. It is now waiting for the status reporting before the
* entry can be reused again.
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_BCN_ENABLED,
ENTRY_OWNER_DEVICE_DATA,
ENTRY_DATA_PENDING,
ENTRY_DATA_IO_FAILED,
ENTRY_DATA_STATUS_PENDING,
};
/**
* struct queue_entry: Entry inside the &struct data_queue
*
* @flags: Entry flags, see &enum queue_entry_flags.
* @last_action: Timestamp of last change.
* @queue: The data queue (&struct data_queue) to which this entry belongs.
* @skb: The buffer which is currently being transmitted (for TX queue),
* or used to directly receive data in (for RX queue).
* @entry_idx: The entry index number.
* @priv_data: Private data belonging to this queue entry. The pointer
* points to data specific to a particular driver and queue type.
* @status: Device specific status
*/
struct queue_entry {
unsigned long flags;
unsigned long last_action;
struct data_queue *queue;
struct sk_buff *skb;
unsigned int entry_idx;
void *priv_data;
};
/**
* enum queue_index: Queue index type
*
* @Q_INDEX: Index pointer to the current entry in the queue, if this entry is
* owned by the hardware then the queue is considered to be full.
* @Q_INDEX_DMA_DONE: Index pointer for the next entry which will have been
* transferred to the hardware.
* @Q_INDEX_DONE: Index pointer to the next entry which will be completed by
* the hardware and for which we need to run the txdone handler. If this
* entry is not owned by the hardware the queue is considered to be empty.
* @Q_INDEX_MAX: Keep last, used in &struct data_queue to determine the size
* of the index array.
*/
enum queue_index {
Q_INDEX,
Q_INDEX_DMA_DONE,
Q_INDEX_DONE,
Q_INDEX_MAX,
};
/**
* enum data_queue_flags: Status flags for data queues
*
* @QUEUE_STARTED: The queue has been started. Fox RX queues this means the
* device might be DMA'ing skbuffers. TX queues will accept skbuffers to
* be transmitted and beacon queues will start beaconing the configured
* beacons.
* @QUEUE_PAUSED: The queue has been started but is currently paused.
* When this bit is set, the queue has been stopped in mac80211,
* preventing new frames to be enqueued. However, a few frames
* might still appear shortly after the pausing...
*/
enum data_queue_flags {
QUEUE_STARTED,
QUEUE_PAUSED,
};
/**
* struct data_queue: Data queue
*
* @rt2x00dev: Pointer to main &struct rt2x00dev where this queue belongs to.
* @entries: Base address of the &struct queue_entry which are
* part of this queue.
* @qid: The queue identification, see &enum data_queue_qid.
* @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.
* @count: Number of frames handled in the queue.
* @limit: Maximum number of entries in the queue.
* @threshold: Minimum number of free entries before queue is kicked by force.
* @length: Number of frames in queue.
* @index: Index pointers to entry positions in the queue,
* use &enum queue_index to get a specific index field.
* @wd_count: watchdog counter number of times entry does change
* in the queue
* @wd_idx: index of queue entry saved by watchdog
* @txop: maximum burst time.
* @aifs: The aifs value for outgoing frames (field ignored in RX queue).
* @cw_min: The cw min value for outgoing frames (field ignored in RX queue).
* @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
* @data_size: Maximum data size for the frames in this queue.
* @desc_size: Hardware descriptor size for the data in this queue.
* @priv_size: Size of per-queue_entry private data.
* @usb_endpoint: Device endpoint used for communication (USB only)
* @usb_maxpacket: Max packet size for given endpoint (USB only)
*/
struct data_queue {
struct rt2x00_dev *rt2x00dev;
struct queue_entry *entries;
enum data_queue_qid qid;
unsigned long flags;
struct mutex status_lock;
spinlock_t tx_lock;
spinlock_t index_lock;
unsigned int count;
unsigned short limit;
unsigned short threshold;
unsigned short length;
unsigned short index[Q_INDEX_MAX];
unsigned short wd_count;
unsigned int wd_idx;
unsigned short txop;
unsigned short aifs;
unsigned short cw_min;
unsigned short cw_max;
unsigned short data_size;
unsigned char desc_size;
unsigned char winfo_size;
unsigned short priv_size;
unsigned short usb_endpoint;
unsigned short usb_maxpacket;
};
/**
* queue_end - Return pointer to the last queue (HELPER MACRO).
* @__dev: Pointer to &struct rt2x00_dev
*
* Using the base rx pointer and the maximum number of available queues,
* this macro will return the address of 1 position beyond the end of the
* queues array.
*/
#define queue_end(__dev) \
&(__dev)->rx[(__dev)->data_queues]
/**
* tx_queue_end - Return pointer to the last TX queue (HELPER MACRO).
* @__dev: Pointer to &struct rt2x00_dev
*
* Using the base tx pointer and the maximum number of available TX
* queues, this macro will return the address of 1 position beyond
* the end of the TX queue array.
*/
#define tx_queue_end(__dev) \
&(__dev)->tx[(__dev)->ops->tx_queues]
/**
* queue_next - Return pointer to next queue in list (HELPER MACRO).
* @__queue: Current queue for which we need the next queue
*
* Using the current queue address we take the address directly
* after the queue to take the next queue. Note that this macro
* should be used carefully since it does not protect against
* moving past the end of the list. (See macros &queue_end and
* &tx_queue_end for determining the end of the queue).
*/
#define queue_next(__queue) \
&(__queue)[1]
/**
* queue_loop - Loop through the queues within a specific range (HELPER MACRO).
* @__entry: Pointer where the current queue entry will be stored in.
* @__start: Start queue pointer.
* @__end: End queue pointer.
*
* This macro will loop through all queues between &__start and &__end.
*/
#define queue_loop(__entry, __start, __end) \
for ((__entry) = (__start); \
prefetch(queue_next(__entry)), (__entry) != (__end);\
(__entry) = queue_next(__entry))
/**
* queue_for_each - Loop through all queues
* @__dev: Pointer to &struct rt2x00_dev
* @__entry: Pointer where the current queue entry will be stored in.
*
* This macro will loop through all available queues.
*/
#define queue_for_each(__dev, __entry) \
queue_loop(__entry, (__dev)->rx, queue_end(__dev))
/**
* tx_queue_for_each - Loop through the TX queues
* @__dev: Pointer to &struct rt2x00_dev
* @__entry: Pointer where the current queue entry will be stored in.
*
* This macro will loop through all TX related queues excluding
* the Beacon and Atim queues.
*/
#define tx_queue_for_each(__dev, __entry) \
queue_loop(__entry, (__dev)->tx, tx_queue_end(__dev))
/**
* txall_queue_for_each - Loop through all TX related queues
* @__dev: Pointer to &struct rt2x00_dev
* @__entry: Pointer where the current queue entry will be stored in.
*
* This macro will loop through all TX related queues including
* the Beacon and Atim queues.
*/
#define txall_queue_for_each(__dev, __entry) \
queue_loop(__entry, (__dev)->tx, queue_end(__dev))
/**
* rt2x00queue_for_each_entry - Loop through all entries in the queue
* @queue: Pointer to @data_queue
* @start: &enum queue_index Pointer to start index
* @end: &enum queue_index Pointer to end index
* @data: Data to pass to the callback function
* @fn: The function to call for each &struct queue_entry
*
* This will walk through all entries in the queue, in chronological
* order. This means it will start at the current @start pointer
* and will walk through the queue until it reaches the @end pointer.
*
* If fn returns true for an entry rt2x00queue_for_each_entry will stop
* processing and return true as well.
*/
bool rt2x00queue_for_each_entry(struct data_queue *queue,
enum queue_index start,
enum queue_index end,
void *data,
bool (*fn)(struct queue_entry *entry,
void *data));
/**
* rt2x00queue_empty - Check if the queue is empty.
* @queue: Queue to check if empty.
*/
static inline int rt2x00queue_empty(struct data_queue *queue)
{
return queue->length == 0;
}
/**
* rt2x00queue_full - Check if the queue is full.
* @queue: Queue to check if full.
*/
static inline int rt2x00queue_full(struct data_queue *queue)
{
return queue->length == queue->limit;
}
/**
* rt2x00queue_free - Check the number of available entries in queue.
* @queue: Queue to check.
*/
static inline int rt2x00queue_available(struct data_queue *queue)
{
return queue->limit - queue->length;
}
/**
* rt2x00queue_threshold - Check if the queue is below threshold
* @queue: Queue to check.
*/
static inline int rt2x00queue_threshold(struct data_queue *queue)
{
return rt2x00queue_available(queue) < queue->threshold;
}
/**
* rt2x00queue_dma_timeout - Check if a timeout occurred for DMA transfers
* @entry: Queue entry to check.
*/
static inline int rt2x00queue_dma_timeout(struct queue_entry *entry)
{
if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return false;
return time_after(jiffies, entry->last_action + msecs_to_jiffies(100));
}
/**
* _rt2x00_desc_read - Read a word from the hardware descriptor.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be read.
*/
static inline __le32 _rt2x00_desc_read(__le32 *desc, const u8 word)
{
return desc[word];
}
/**
* rt2x00_desc_read - Read a word from the hardware descriptor, this
* function will take care of the byte ordering.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be read.
*/
static inline u32 rt2x00_desc_read(__le32 *desc, const u8 word)
{
return le32_to_cpu(_rt2x00_desc_read(desc, word));
}
/**
* rt2x00_desc_write - write a word to the hardware descriptor, this
* function will take care of the byte ordering.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be written.
* @value: Value that should be written into the descriptor.
*/
static inline void _rt2x00_desc_write(__le32 *desc, const u8 word, __le32 value)
{
desc[word] = value;
}
/**
* rt2x00_desc_write - write a word to the hardware descriptor.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be written.
* @value: Value that should be written into the descriptor.
*/
static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value)
{
_rt2x00_desc_write(desc, word, cpu_to_le32(value));
}
#endif /* RT2X00QUEUE_H */
@@ -0,0 +1,266 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00
Abstract: rt2x00 generic register information.
*/
#ifndef RT2X00REG_H
#define RT2X00REG_H
/*
* RX crypto status
*/
enum rx_crypto {
RX_CRYPTO_SUCCESS = 0,
RX_CRYPTO_FAIL_ICV = 1,
RX_CRYPTO_FAIL_MIC = 2,
RX_CRYPTO_FAIL_KEY = 3,
};
/*
* Antenna values
*/
enum antenna {
ANTENNA_SW_DIVERSITY = 0,
ANTENNA_A = 1,
ANTENNA_B = 2,
ANTENNA_HW_DIVERSITY = 3,
};
/*
* Led mode values.
*/
enum led_mode {
LED_MODE_DEFAULT = 0,
LED_MODE_TXRX_ACTIVITY = 1,
LED_MODE_SIGNAL_STRENGTH = 2,
LED_MODE_ASUS = 3,
LED_MODE_ALPHA = 4,
};
/*
* TSF sync values
*/
enum tsf_sync {
TSF_SYNC_NONE = 0,
TSF_SYNC_INFRA = 1,
TSF_SYNC_ADHOC = 2,
TSF_SYNC_AP_NONE = 3,
};
/*
* Device states
*/
enum dev_state {
STATE_DEEP_SLEEP = 0,
STATE_SLEEP = 1,
STATE_STANDBY = 2,
STATE_AWAKE = 3,
/*
* Additional device states, these values are
* not strict since they are not directly passed
* into the device.
*/
STATE_RADIO_ON,
STATE_RADIO_OFF,
STATE_RADIO_IRQ_ON,
STATE_RADIO_IRQ_OFF,
};
/*
* IFS backoff values
*/
enum ifs {
IFS_BACKOFF = 0,
IFS_SIFS = 1,
IFS_NEW_BACKOFF = 2,
IFS_NONE = 3,
};
/*
* IFS backoff values for HT devices
*/
enum txop {
TXOP_HTTXOP = 0,
TXOP_PIFS = 1,
TXOP_SIFS = 2,
TXOP_BACKOFF = 3,
};
/*
* Cipher types for hardware encryption
*/
enum cipher {
CIPHER_NONE = 0,
CIPHER_WEP64 = 1,
CIPHER_WEP128 = 2,
CIPHER_TKIP = 3,
CIPHER_AES = 4,
/*
* The following fields were added by rt61pci and rt73usb.
*/
CIPHER_CKIP64 = 5,
CIPHER_CKIP128 = 6,
CIPHER_TKIP_NO_MIC = 7, /* Don't send to device */
/*
* Max cipher type.
* Note that CIPHER_NONE isn't counted, and CKIP64 and CKIP128
* are excluded due to limitations in mac80211.
*/
CIPHER_MAX = 4,
};
/*
* Rate modulations
*/
enum rate_modulation {
RATE_MODE_CCK = 0,
RATE_MODE_OFDM = 1,
RATE_MODE_HT_MIX = 2,
RATE_MODE_HT_GREENFIELD = 3,
};
/*
* Firmware validation error codes
*/
enum firmware_errors {
FW_OK,
FW_BAD_CRC,
FW_BAD_LENGTH,
FW_BAD_VERSION,
};
/*
* Register handlers.
* We store the position of a register field inside a field structure,
* This will simplify the process of setting and reading a certain field
* inside the register while making sure the process remains byte order safe.
*/
struct rt2x00_field8 {
u8 bit_offset;
u8 bit_mask;
};
struct rt2x00_field16 {
u16 bit_offset;
u16 bit_mask;
};
struct rt2x00_field32 {
u32 bit_offset;
u32 bit_mask;
};
/*
* Power of two check, this will check
* if the mask that has been given contains and contiguous set of bits.
* Note that we cannot use the is_power_of_2() function since this
* check must be done at compile-time.
*/
#define is_power_of_two(x) ( !((x) & ((x)-1)) )
#define low_bit_mask(x) ( ((x)-1) & ~(x) )
#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
/*
* Macros to find first set bit in a variable.
* These macros behave the same as the __ffs() functions but
* the most important difference that this is done during
* compile-time rather then run-time.
*/
#define compile_ffs2(__x) \
__builtin_choose_expr(((__x) & 0x1), 0, 1)
#define compile_ffs4(__x) \
__builtin_choose_expr(((__x) & 0x3), \
(compile_ffs2((__x))), \
(compile_ffs2((__x) >> 2) + 2))
#define compile_ffs8(__x) \
__builtin_choose_expr(((__x) & 0xf), \
(compile_ffs4((__x))), \
(compile_ffs4((__x) >> 4) + 4))
#define compile_ffs16(__x) \
__builtin_choose_expr(((__x) & 0xff), \
(compile_ffs8((__x))), \
(compile_ffs8((__x) >> 8) + 8))
#define compile_ffs32(__x) \
__builtin_choose_expr(((__x) & 0xffff), \
(compile_ffs16((__x))), \
(compile_ffs16((__x) >> 16) + 16))
/*
* This macro will check the requirements for the FIELD{8,16,32} macros
* The mask should be a constant non-zero contiguous set of bits which
* does not exceed the given typelimit.
*/
#define FIELD_CHECK(__mask, __type) \
BUILD_BUG_ON(!(__mask) || \
!is_valid_mask(__mask) || \
(__mask) != (__type)(__mask)) \
#define FIELD8(__mask) \
({ \
FIELD_CHECK(__mask, u8); \
(struct rt2x00_field8) { \
compile_ffs8(__mask), (__mask) \
}; \
})
#define FIELD16(__mask) \
({ \
FIELD_CHECK(__mask, u16); \
(struct rt2x00_field16) { \
compile_ffs16(__mask), (__mask) \
}; \
})
#define FIELD32(__mask) \
({ \
FIELD_CHECK(__mask, u32); \
(struct rt2x00_field32) { \
compile_ffs32(__mask), (__mask) \
}; \
})
#define SET_FIELD(__reg, __type, __field, __value)\
({ \
typecheck(__type, __field); \
*(__reg) &= ~((__field).bit_mask); \
*(__reg) |= ((__value) << \
((__field).bit_offset)) & \
((__field).bit_mask); \
})
#define GET_FIELD(__reg, __type, __field) \
({ \
typecheck(__type, __field); \
((__reg) & ((__field).bit_mask)) >> \
((__field).bit_offset); \
})
#define rt2x00_set_field32(__reg, __field, __value) \
SET_FIELD(__reg, struct rt2x00_field32, __field, __value)
#define rt2x00_get_field32(__reg, __field) \
GET_FIELD(__reg, struct rt2x00_field32, __field)
#define rt2x00_set_field16(__reg, __field, __value) \
SET_FIELD(__reg, struct rt2x00_field16, __field, __value)
#define rt2x00_get_field16(__reg, __field) \
GET_FIELD(__reg, struct rt2x00_field16, __field)
#define rt2x00_set_field8(__reg, __field, __value) \
SET_FIELD(__reg, struct rt2x00_field8, __field, __value)
#define rt2x00_get_field8(__reg, __field) \
GET_FIELD(__reg, struct rt2x00_field8, __field)
#endif /* RT2X00REG_H */
@@ -0,0 +1,891 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00usb
Abstract: rt2x00 generic usb device routines.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/bug.h>
#include "rt2x00.h"
#include "rt2x00usb.h"
static bool rt2x00usb_check_usb_error(struct rt2x00_dev *rt2x00dev, int status)
{
if (status == -ENODEV || status == -ENOENT)
return true;
if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
return false;
if (status == -EPROTO || status == -ETIMEDOUT)
rt2x00dev->num_proto_errs++;
else
rt2x00dev->num_proto_errs = 0;
if (rt2x00dev->num_proto_errs > 3)
return true;
return false;
}
/*
* Interfacing with the HW.
*/
int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, const u16 value,
void *buffer, const u16 buffer_length,
const int timeout)
{
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
int status;
unsigned int pipe =
(requesttype == USB_VENDOR_REQUEST_IN) ?
usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
unsigned long expire = jiffies + msecs_to_jiffies(timeout);
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return -ENODEV;
do {
status = usb_control_msg(usb_dev, pipe, request, requesttype,
value, offset, buffer, buffer_length,
timeout / 2);
if (status >= 0)
return 0;
if (rt2x00usb_check_usb_error(rt2x00dev, status)) {
/* Device has disappeared. */
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
break;
}
} while (time_before(jiffies, expire));
rt2x00_err(rt2x00dev,
"Vendor Request 0x%02x failed for offset 0x%04x with error %d\n",
request, offset, status);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request);
int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout)
{
int status;
BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex));
/*
* Check for Cache availability.
*/
if (unlikely(!rt2x00dev->csr.cache || buffer_length > CSR_CACHE_SIZE)) {
rt2x00_err(rt2x00dev, "CSR cache not available\n");
return -ENOMEM;
}
if (requesttype == USB_VENDOR_REQUEST_OUT)
memcpy(rt2x00dev->csr.cache, buffer, buffer_length);
status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype,
offset, 0, rt2x00dev->csr.cache,
buffer_length, timeout);
if (!status && requesttype == USB_VENDOR_REQUEST_IN)
memcpy(buffer, rt2x00dev->csr.cache, buffer_length);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_req_buff_lock);
int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
const u16 buffer_length)
{
int status = 0;
u8 *tb;
u16 off, len, bsize;
mutex_lock(&rt2x00dev->csr_mutex);
tb = (u8 *)buffer;
off = offset;
len = buffer_length;
while (len && !status) {
bsize = min_t(u16, CSR_CACHE_SIZE, len);
status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
requesttype, off, tb,
bsize, REGISTER_TIMEOUT);
tb += bsize;
len -= bsize;
off += bsize;
}
mutex_unlock(&rt2x00dev->csr_mutex);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field,
u32 *reg)
{
unsigned int i;
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return -ENODEV;
for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) {
*reg = rt2x00usb_register_read_lock(rt2x00dev, offset);
if (!rt2x00_get_field32(*reg, field))
return 1;
udelay(REGISTER_BUSY_DELAY);
}
rt2x00_err(rt2x00dev, "Indirect register access failed: offset=0x%.08x, value=0x%.08x\n",
offset, *reg);
*reg = ~0;
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
struct rt2x00_async_read_data {
__le32 reg;
struct usb_ctrlrequest cr;
struct rt2x00_dev *rt2x00dev;
bool (*callback)(struct rt2x00_dev *, int, u32);
};
static void rt2x00usb_register_read_async_cb(struct urb *urb)
{
struct rt2x00_async_read_data *rd = urb->context;
if (rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg))) {
usb_anchor_urb(urb, rd->rt2x00dev->anchor);
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
usb_unanchor_urb(urb);
kfree(rd);
}
} else
kfree(rd);
}
void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
bool (*callback)(struct rt2x00_dev*, int, u32))
{
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct urb *urb;
struct rt2x00_async_read_data *rd;
rd = kmalloc_obj(*rd, GFP_ATOMIC);
if (!rd)
return;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
kfree(rd);
return;
}
rd->rt2x00dev = rt2x00dev;
rd->callback = callback;
rd->cr.bRequestType = USB_VENDOR_REQUEST_IN;
rd->cr.bRequest = USB_MULTI_READ;
rd->cr.wValue = 0;
rd->cr.wIndex = cpu_to_le16(offset);
rd->cr.wLength = cpu_to_le16(sizeof(u32));
usb_fill_control_urb(urb, usb_dev, usb_rcvctrlpipe(usb_dev, 0),
(u8 *)(&rd->cr), &rd->reg, sizeof(rd->reg),
rt2x00usb_register_read_async_cb, rd);
usb_anchor_urb(urb, rt2x00dev->anchor);
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
usb_unanchor_urb(urb);
kfree(rd);
}
usb_free_urb(urb);
}
EXPORT_SYMBOL_GPL(rt2x00usb_register_read_async);
/*
* TX data handlers.
*/
static void rt2x00usb_work_txdone_entry(struct queue_entry *entry)
{
/*
* If the transfer to hardware succeeded, it does not mean the
* frame was send out correctly. It only means the frame
* was successfully pushed to the hardware, we have no
* way to determine the transmission status right now.
* (Only indirectly by looking at the failed TX counters
* in the register).
*/
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
else
rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
}
static void rt2x00usb_work_txdone(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, txdone_work);
struct data_queue *queue;
struct queue_entry *entry;
tx_queue_for_each(rt2x00dev, queue) {
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;
rt2x00usb_work_txdone_entry(entry);
}
}
}
static void rt2x00usb_interrupt_txdone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
* Check if the frame was correctly uploaded
*/
if (urb->status)
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
/*
* Report the frame as DMA done
*/
rt2x00lib_dmadone(entry);
if (rt2x00dev->ops->lib->tx_dma_done)
rt2x00dev->ops->lib->tx_dma_done(entry);
/*
* Schedule the delayed work for reading the TX status
* from the device.
*/
if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TXSTATUS_FIFO) ||
!kfifo_is_empty(&rt2x00dev->txstatus_fifo))
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
}
static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void *data)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
u32 length;
int status;
if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) ||
test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
return false;
/*
* USB devices require certain padding at the end of each frame
* and urb. Those paddings are not included in skbs. Pass entry
* to the driver to determine what the overall length should be.
*/
length = rt2x00dev->ops->lib->get_tx_data_len(entry);
status = skb_padto(entry->skb, length);
if (unlikely(status)) {
/* TODO: report something more appropriate than IO_FAILED. */
rt2x00_warn(rt2x00dev, "TX SKB padding error, out of memory\n");
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
return false;
}
usb_fill_bulk_urb(entry_priv->urb, usb_dev,
usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
entry->skb->data, length,
rt2x00usb_interrupt_txdone, entry);
status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
if (status) {
if (rt2x00usb_check_usb_error(rt2x00dev, status))
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
}
return false;
}
/*
* RX data handlers.
*/
static void rt2x00usb_work_rxdone(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, rxdone_work);
struct queue_entry *entry;
struct skb_frame_desc *skbdesc;
u8 rxd[32];
while (!rt2x00queue_empty(rt2x00dev->rx)) {
entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);
if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
break;
/*
* Fill in desc fields of the skb descriptor
*/
skbdesc = get_skb_frame_desc(entry->skb);
skbdesc->desc = rxd;
skbdesc->desc_len = entry->queue->desc_size;
/*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(entry, GFP_KERNEL);
}
}
static void rt2x00usb_interrupt_rxdone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
* Check if the received data is simply too small
* to be actually valid, or if the urb is signaling
* a problem.
*/
if (urb->actual_length < entry->queue->desc_size || urb->status)
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
/*
* Report the frame as DMA done
*/
rt2x00lib_dmadone(entry);
/*
* Schedule the delayed work for processing RX data
*/
queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work);
}
static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void *data)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
int status;
if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return false;
rt2x00lib_dmastart(entry);
usb_fill_bulk_urb(entry_priv->urb, usb_dev,
usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint),
entry->skb->data, entry->skb->len,
rt2x00usb_interrupt_rxdone, entry);
status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
if (status) {
if (rt2x00usb_check_usb_error(rt2x00dev, status))
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
}
return false;
}
void rt2x00usb_kick_queue(struct data_queue *queue)
{
switch (queue->qid) {
case QID_AC_VO:
case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
if (!rt2x00queue_empty(queue))
rt2x00queue_for_each_entry(queue,
Q_INDEX_DONE,
Q_INDEX,
NULL,
rt2x00usb_kick_tx_entry);
break;
case QID_RX:
if (!rt2x00queue_full(queue))
rt2x00queue_for_each_entry(queue,
Q_INDEX,
Q_INDEX_DONE,
NULL,
rt2x00usb_kick_rx_entry);
break;
default:
break;
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue);
static bool rt2x00usb_flush_entry(struct queue_entry *entry, void *data)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return false;
usb_kill_urb(entry_priv->urb);
/*
* Kill guardian urb (if required by driver).
*/
if ((entry->queue->qid == QID_BEACON) &&
(rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD)))
usb_kill_urb(bcn_priv->guardian_urb);
return false;
}
void rt2x00usb_flush_queue(struct data_queue *queue, bool drop)
{
struct work_struct *completion;
unsigned int i;
if (drop)
rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL,
rt2x00usb_flush_entry);
/*
* Obtain the queue completion handler
*/
switch (queue->qid) {
case QID_AC_VO:
case QID_AC_VI:
case QID_AC_BE:
case QID_AC_BK:
completion = &queue->rt2x00dev->txdone_work;
break;
case QID_RX:
completion = &queue->rt2x00dev->rxdone_work;
break;
default:
return;
}
for (i = 0; i < 10; i++) {
/*
* Check if the driver is already done, otherwise we
* have to sleep a little while to give the driver/hw
* the oppurtunity to complete interrupt process itself.
*/
if (rt2x00queue_empty(queue))
break;
/*
* Schedule the completion handler manually, when this
* worker function runs, it should cleanup the queue.
*/
queue_work(queue->rt2x00dev->workqueue, completion);
/*
* Wait for a little while to give the driver
* the oppurtunity to recover itself.
*/
msleep(50);
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_flush_queue);
static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
{
rt2x00_warn(queue->rt2x00dev, "TX queue %d DMA timed out, invoke forced reset\n",
queue->qid);
rt2x00queue_stop_queue(queue);
rt2x00queue_flush_queue(queue, true);
rt2x00queue_start_queue(queue);
}
static int rt2x00usb_dma_timeout(struct data_queue *queue)
{
struct queue_entry *entry;
entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
return rt2x00queue_dma_timeout(entry);
}
void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
tx_queue_for_each(rt2x00dev, queue) {
if (!rt2x00queue_empty(queue)) {
if (rt2x00usb_dma_timeout(queue))
rt2x00usb_watchdog_tx_dma(queue);
}
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
/*
* Radio handlers
*/
void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
REGISTER_TIMEOUT);
}
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
/*
* Device initialization handlers.
*/
void rt2x00usb_clear_entry(struct queue_entry *entry)
{
entry->flags = 0;
if (entry->queue->qid == QID_RX)
rt2x00usb_kick_rx_entry(entry, NULL);
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
static void rt2x00usb_assign_endpoint(struct data_queue *queue,
struct usb_endpoint_descriptor *ep_desc)
{
struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev);
int pipe;
queue->usb_endpoint = usb_endpoint_num(ep_desc);
if (queue->qid == QID_RX) {
pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint);
queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe);
} else {
pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint);
queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe);
}
if (!queue->usb_maxpacket)
queue->usb_maxpacket = 1;
}
static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
{
struct usb_interface *intf = to_usb_interface(rt2x00dev->dev);
struct usb_host_interface *intf_desc = intf->cur_altsetting;
struct usb_endpoint_descriptor *ep_desc;
struct data_queue *queue = rt2x00dev->tx;
struct usb_endpoint_descriptor *tx_ep_desc = NULL;
unsigned int i;
/*
* Walk through all available endpoints to search for "bulk in"
* and "bulk out" endpoints. When we find such endpoints collect
* the information we need from the descriptor and assign it
* to the queue.
*/
for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
ep_desc = &intf_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(ep_desc)) {
rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc);
} else if (usb_endpoint_is_bulk_out(ep_desc) &&
(queue != queue_end(rt2x00dev))) {
rt2x00usb_assign_endpoint(queue, ep_desc);
queue = queue_next(queue);
tx_ep_desc = ep_desc;
}
}
/*
* At least 1 endpoint for RX and 1 endpoint for TX must be available.
*/
if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) {
rt2x00_err(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
return -EPIPE;
}
/*
* It might be possible not all queues have a dedicated endpoint.
* Loop through all TX queues and copy the endpoint information
* which we have gathered from already assigned endpoints.
*/
txall_queue_for_each(rt2x00dev, queue) {
if (!queue->usb_endpoint)
rt2x00usb_assign_endpoint(queue, tx_ep_desc);
}
return 0;
}
static int rt2x00usb_alloc_entries(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data;
entry_priv->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!entry_priv->urb)
return -ENOMEM;
}
/*
* If this is not the beacon queue or
* no guardian byte was required for the beacon,
* then we are done.
*/
if (queue->qid != QID_BEACON ||
!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD))
return 0;
for (i = 0; i < queue->limit; i++) {
bcn_priv = queue->entries[i].priv_data;
bcn_priv->guardian_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!bcn_priv->guardian_urb)
return -ENOMEM;
}
return 0;
}
static void rt2x00usb_free_entries(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
if (!queue->entries)
return;
for (i = 0; i < queue->limit; i++) {
entry_priv = queue->entries[i].priv_data;
usb_kill_urb(entry_priv->urb);
usb_free_urb(entry_priv->urb);
}
/*
* If this is not the beacon queue or
* no guardian byte was required for the beacon,
* then we are done.
*/
if (queue->qid != QID_BEACON ||
!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD))
return;
for (i = 0; i < queue->limit; i++) {
bcn_priv = queue->entries[i].priv_data;
usb_kill_urb(bcn_priv->guardian_urb);
usb_free_urb(bcn_priv->guardian_urb);
}
}
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
int status;
/*
* Find endpoints for each queue
*/
status = rt2x00usb_find_endpoints(rt2x00dev);
if (status)
goto exit;
/*
* Allocate DMA
*/
queue_for_each(rt2x00dev, queue) {
status = rt2x00usb_alloc_entries(queue);
if (status)
goto exit;
}
return 0;
exit:
rt2x00usb_uninitialize(rt2x00dev);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_initialize);
void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
usb_kill_anchored_urbs(rt2x00dev->anchor);
hrtimer_cancel(&rt2x00dev->txstatus_timer);
cancel_work_sync(&rt2x00dev->rxdone_work);
cancel_work_sync(&rt2x00dev->txdone_work);
queue_for_each(rt2x00dev, queue)
rt2x00usb_free_entries(queue);
}
EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize);
/*
* USB driver handlers.
*/
static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev)
{
kfree(rt2x00dev->rf);
rt2x00dev->rf = NULL;
kfree(rt2x00dev->eeprom);
rt2x00dev->eeprom = NULL;
kfree(rt2x00dev->csr.cache);
rt2x00dev->csr.cache = NULL;
}
static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
rt2x00dev->csr.cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL);
if (!rt2x00dev->csr.cache)
goto exit;
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
if (!rt2x00dev->eeprom)
goto exit;
rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
if (!rt2x00dev->rf)
goto exit;
return 0;
exit:
rt2x00_probe_err("Failed to allocate registers\n");
rt2x00usb_free_reg(rt2x00dev);
return -ENOMEM;
}
int rt2x00usb_probe(struct usb_interface *usb_intf,
const struct rt2x00_ops *ops)
{
struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
usb_reset_device(usb_dev);
hw = ieee80211_alloc_hw(struct_size(rt2x00dev, anchor, 1), ops->hw);
if (!hw) {
rt2x00_probe_err("Failed to allocate hardware\n");
return -ENOMEM;
}
usb_set_intfdata(usb_intf, hw);
rt2x00dev = hw->priv;
rt2x00dev->dev = &usb_intf->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);
retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
init_usb_anchor(rt2x00dev->anchor);
retval = rt2x00lib_probe_dev(rt2x00dev);
if (retval)
goto exit_free_anchor;
return 0;
exit_free_anchor:
usb_kill_anchored_urbs(rt2x00dev->anchor);
rt2x00usb_free_reg(rt2x00dev);
exit_free_device:
ieee80211_free_hw(hw);
usb_set_intfdata(usb_intf, NULL);
return retval;
}
EXPORT_SYMBOL_GPL(rt2x00usb_probe);
void rt2x00usb_disconnect(struct usb_interface *usb_intf)
{
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
* Free all allocated data.
*/
rt2x00lib_remove_dev(rt2x00dev);
rt2x00usb_free_reg(rt2x00dev);
ieee80211_free_hw(hw);
usb_set_intfdata(usb_intf, NULL);
}
EXPORT_SYMBOL_GPL(rt2x00usb_disconnect);
#ifdef CONFIG_PM
int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state)
{
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
return rt2x00lib_suspend(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00usb_suspend);
int rt2x00usb_resume(struct usb_interface *usb_intf)
{
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00usb_resume);
#endif /* CONFIG_PM */
/*
* rt2x00usb module information.
*/
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("rt2x00 usb library");
MODULE_LICENSE("GPL");
@@ -0,0 +1,409 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
*/
/*
Module: rt2x00usb
Abstract: Data structures for the rt2x00usb module.
*/
#ifndef RT2X00USB_H
#define RT2X00USB_H
#include <linux/usb.h>
#define to_usb_device_intf(d) \
({ \
struct usb_interface *intf = to_usb_interface(d); \
interface_to_usbdev(intf); \
})
/*
* For USB vendor requests we need to pass a timeout time in ms, for this we
* use the REGISTER_TIMEOUT, however when loading firmware or read EEPROM
* a higher value is required. In that case we use the REGISTER_TIMEOUT_FIRMWARE
* and EEPROM_TIMEOUT.
*/
#define REGISTER_TIMEOUT 100
#define REGISTER_TIMEOUT_FIRMWARE 1000
#define EEPROM_TIMEOUT 2000
/*
* Cache size
*/
#define CSR_CACHE_SIZE 64
/*
* USB request types.
*/
#define USB_VENDOR_REQUEST ( USB_TYPE_VENDOR | USB_RECIP_DEVICE )
#define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST )
#define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST )
/**
* enum rt2x00usb_vendor_request: USB vendor commands.
*/
enum rt2x00usb_vendor_request {
USB_DEVICE_MODE = 1,
USB_SINGLE_WRITE = 2,
USB_SINGLE_READ = 3,
USB_MULTI_WRITE = 6,
USB_MULTI_READ = 7,
USB_EEPROM_WRITE = 8,
USB_EEPROM_READ = 9,
USB_LED_CONTROL = 10, /* RT73USB */
USB_RX_CONTROL = 12,
};
/**
* enum rt2x00usb_mode_offset: Device modes offset.
*/
enum rt2x00usb_mode_offset {
USB_MODE_RESET = 1,
USB_MODE_UNPLUG = 2,
USB_MODE_FUNCTION = 3,
USB_MODE_TEST = 4,
USB_MODE_SLEEP = 7, /* RT73USB */
USB_MODE_FIRMWARE = 8, /* RT73USB */
USB_MODE_WAKEUP = 9, /* RT73USB */
USB_MODE_AUTORUN = 17, /* RT2800USB */
};
/**
* rt2x00usb_vendor_request - Send register command to device
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
* @requesttype: Request type &USB_VENDOR_REQUEST_*
* @offset: Register offset to perform action on
* @value: Value to write to device
* @buffer: Buffer where information will be read/written to by device
* @buffer_length: Size of &buffer
* @timeout: Operation timeout
*
* This is the main function to communicate with the device,
* the &buffer argument _must_ either be NULL or point to
* a buffer allocated by kmalloc. Failure to do so can lead
* to unexpected behavior depending on the architecture.
*/
int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, const u16 value,
void *buffer, const u16 buffer_length,
const int timeout);
/**
* rt2x00usb_vendor_request_buff - Send register command to device (buffered)
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
* @requesttype: Request type &USB_VENDOR_REQUEST_*
* @offset: Register offset to perform action on
* @buffer: Buffer where information will be read/written to by device
* @buffer_length: Size of &buffer
*
* This function will use a previously with kmalloc allocated cache
* to communicate with the device. The contents of the buffer pointer
* will be copied to this cache when writing, or read from the cache
* when reading.
* Buffers send to &rt2x00usb_vendor_request _must_ be allocated with
* kmalloc. Hence the reason for using a previously allocated cache
* which has been allocated properly.
*/
int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
const u16 buffer_length);
/**
* rt2x00usb_vendor_request_buff - Send register command to device (buffered)
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
* @requesttype: Request type &USB_VENDOR_REQUEST_*
* @offset: Register offset to perform action on
* @buffer: Buffer where information will be read/written to by device
* @buffer_length: Size of &buffer
* @timeout: Operation timeout
*
* A version of &rt2x00usb_vendor_request_buff which must be called
* if the usb_cache_mutex is already held.
*/
int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
const u8 request, const u8 requesttype,
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout);
/**
* rt2x00usb_vendor_request_sw - Send single register command to device
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
* @offset: Register offset to perform action on
* @value: Value to write to device
* @timeout: Operation timeout
*
* Simple wrapper around rt2x00usb_vendor_request to write a single
* command to the device. Since we don't use the buffer argument we
* don't have to worry about kmalloc here.
*/
static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev,
const u8 request,
const u16 offset,
const u16 value,
const int timeout)
{
return rt2x00usb_vendor_request(rt2x00dev, request,
USB_VENDOR_REQUEST_OUT, offset,
value, NULL, 0, timeout);
}
/**
* rt2x00usb_eeprom_read - Read eeprom from device
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @eeprom: Pointer to eeprom array to store the information in
* @length: Number of bytes to read from the eeprom
*
* Simple wrapper around rt2x00usb_vendor_request to read the eeprom
* from the device. Note that the eeprom argument _must_ be allocated using
* kmalloc for correct handling inside the kernel USB layer.
*/
static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
__le16 *eeprom, const u16 length)
{
return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ,
USB_VENDOR_REQUEST_IN, 0, 0,
eeprom, length, EEPROM_TIMEOUT);
}
/**
* rt2x00usb_register_read - Read 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_request_buff().
*/
static inline u32 rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset)
{
__le32 reg = 0;
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
&reg, sizeof(reg));
return le32_to_cpu(reg);
}
/**
* rt2x00usb_register_read_lock - Read 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_req_buff_lock().
*/
static inline u32 rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset)
{
__le32 reg = 0;
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
&reg, sizeof(reg), REGISTER_TIMEOUT);
return le32_to_cpu(reg);
}
/**
* rt2x00usb_register_multiread - Read 32bit register words
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Pointer to where register contents should be stored
* @length: Length of the data
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_request_buff().
*/
static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u32 length)
{
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
value, length);
}
/**
* rt2x00usb_register_write - Write 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Data which should be written
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_request_buff().
*/
static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
__le32 reg = cpu_to_le32(value);
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
&reg, sizeof(reg));
}
/**
* rt2x00usb_register_write_lock - Write 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Data which should be written
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_req_buff_lock().
*/
static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
{
__le32 reg = cpu_to_le32(value);
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
&reg, sizeof(reg), REGISTER_TIMEOUT);
}
/**
* rt2x00usb_register_multiwrite - Write 32bit register words
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @value: Data which should be written
* @length: Length of the data
*
* This function is a simple wrapper for 32bit register access
* through rt2x00usb_vendor_request_buff().
*/
static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const void *value,
const u32 length)
{
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
(void *)value, length);
}
/**
* rt2x00usb_regbusy_read - Read from register with busy check
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @field: Field to check if register is busy
* @reg: Pointer to where register contents should be stored
*
* This function will read the given register, and checks if the
* register is busy. If it is, it will sleep for a couple of
* microseconds before reading the register again. If the register
* is not read after a certain timeout, this function will return
* FALSE.
*/
int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field,
u32 *reg);
/**
* rt2x00usb_register_read_async - Asynchronously read 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset
* @callback: Functon to call when read completes.
*
* Submit a control URB to read a 32bit register. This safe to
* be called from atomic context. The callback will be called
* when the URB completes. Otherwise the function is similar
* to rt2x00usb_register_read().
* When the callback function returns false, the memory will be cleaned up,
* when it returns true, the urb will be fired again.
*/
void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
bool (*callback)(struct rt2x00_dev*, int, u32));
/*
* Radio handlers
*/
void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
/**
* struct queue_entry_priv_usb: Per entry USB specific information
*
* @urb: Urb structure used for device communication.
*/
struct queue_entry_priv_usb {
struct urb *urb;
};
/**
* struct queue_entry_priv_usb_bcn: Per TX entry USB specific information
*
* The first section should match &struct queue_entry_priv_usb exactly.
* rt2500usb can use this structure to send a guardian byte when working
* with beacons.
*
* @urb: Urb structure used for device communication.
* @guardian_data: Set to 0, used for sending the guardian data.
* @guardian_urb: Urb structure used to send the guardian data.
*/
struct queue_entry_priv_usb_bcn {
struct urb *urb;
unsigned int guardian_data;
struct urb *guardian_urb;
};
/**
* rt2x00usb_kick_queue - Kick data queue
* @queue: Data queue to kick
*
* This will walk through all entries of the queue and push all pending
* frames to the hardware as a single burst.
*/
void rt2x00usb_kick_queue(struct data_queue *queue);
/**
* rt2x00usb_flush_queue - Flush data queue
* @queue: Data queue to stop
* @drop: True to drop all pending frames.
*
* This will walk through all entries of the queue and will optionally
* kill all URB's which were send to the device, or at least wait until
* they have been returned from the device..
*/
void rt2x00usb_flush_queue(struct data_queue *queue, bool drop);
/**
* rt2x00usb_watchdog - Watchdog for USB communication
* @rt2x00dev: Pointer to &struct rt2x00_dev
*
* Check the health of the USB communication and determine
* if timeouts have occurred. If this is the case, this function
* will reset all communication to restore functionality again.
*/
void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev);
/*
* Device initialization handlers.
*/
void rt2x00usb_clear_entry(struct queue_entry *entry);
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
/*
* USB driver handlers.
*/
int rt2x00usb_probe(struct usb_interface *usb_intf,
const struct rt2x00_ops *ops);
void rt2x00usb_disconnect(struct usb_interface *usb_intf);
#ifdef CONFIG_PM
int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state);
int rt2x00usb_resume(struct usb_interface *usb_intf);
#else
#define rt2x00usb_suspend NULL
#define rt2x00usb_resume NULL
#endif /* CONFIG_PM */
#endif /* RT2X00USB_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff