mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
John W. Linville says: ==================== For the mac80211 bits, Johannes says: "This time, I have a number of small fixes and improvements, and those are fairly straight-forward. More interesting changes come from Luca with some preparations for the CSA work, mostly around interface/channel combinations checking. One other possibly interesting change is a small one by myself to add NAPI support back to mac80211, which can help improve TCP behaviour through GRO." For the Bluetooth bits, Gustavo says: "This is our first pull request for 3.15, the main feature here is the addition of the privacy feature for low energy devices. Other than that we have a bunch of small improvements, fixes, and clean ups all over the tree." And... "Another pull request to 3.15. Here we have the second part of the LE private feature, the LE auto-connect feature and improvements to the power off procedures. The rest are small improvements, clean up, and fixes." For the iwlwifi bits, Emmanuel says: "I have here a whole bunch of various things. Trivial cleanups, debugfs handlers and new stuff for the new generation of devices along with new capabilities for monitor mode. We also have support for power save for dual interface mode, but that is not supported by the firmware currently available." And for the Atheros bits, Kalle says: "For ath10k Alexander did some cleanup to PCI error cases and switched ath10k to use pci_enable_msi_range(). Michal implemented AP CSA support and sta_rc_update() operation. I enabled firmware "STA quick kickout" functionality for faster detection of disappeared clients. Also there are lots of small fixes to everywhere from various people." I pulled the wireless tree to avoid some merge conflicts, and I reverted the staging patch that I had mistakenly merged previously. Along with that, mwifiex, brcmfmac, wil6210, ath9k, and a few other drivers get their usual round of updates. Also notable is the addition of yet another driver in the rtlwifi family. ... I have amended this commit request to correct the build problems in staging, including a warning added to one of the staging drivers by the wireless-next tree. I also included a fix from Larry Finger to address an issue found in rtl8723be by Dan Carpenter and smatch. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
ca30be8057
|
@ -98,6 +98,8 @@
|
|||
!Finclude/net/cfg80211.h priv_to_wiphy
|
||||
!Finclude/net/cfg80211.h set_wiphy_dev
|
||||
!Finclude/net/cfg80211.h wdev_priv
|
||||
!Finclude/net/cfg80211.h ieee80211_iface_limit
|
||||
!Finclude/net/cfg80211.h ieee80211_iface_combination
|
||||
</chapter>
|
||||
<chapter>
|
||||
<title>Actions and configuration</title>
|
||||
|
|
|
@ -353,6 +353,7 @@ Your cooperation is appreciated.
|
|||
133 = /dev/exttrp External device trap
|
||||
134 = /dev/apm_bios Advanced Power Management BIOS
|
||||
135 = /dev/rtc Real Time Clock
|
||||
137 = /dev/vhci Bluetooth virtual HCI driver
|
||||
139 = /dev/openprom SPARC OpenBoot PROM
|
||||
140 = /dev/relay8 Berkshire Products Octal relay card
|
||||
141 = /dev/relay16 Berkshire Products ISO-16 relay card
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
* Texas Instruments wl1251 wireless lan controller
|
||||
|
||||
The wl1251 chip can be connected via SPI or via SDIO. This
|
||||
document describes the binding for the SPI connected chip.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "ti,wl1251"
|
||||
- reg : Chip select address of device
|
||||
- spi-max-frequency : Maximum SPI clocking speed of device in Hz
|
||||
- interrupts : Should contain interrupt line
|
||||
- interrupt-parent : Should be the phandle for the interrupt controller
|
||||
that services interrupts for this device
|
||||
- vio-supply : phandle to regulator providing VIO
|
||||
- ti,power-gpio : GPIO connected to chip's PMEN pin
|
||||
|
||||
Optional properties:
|
||||
- ti,wl1251-has-eeprom : boolean, the wl1251 has an eeprom connected, which
|
||||
provides configuration data (calibration, MAC, ...)
|
||||
- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
for optional SPI connection related properties,
|
||||
|
||||
Examples:
|
||||
|
||||
&spi1 {
|
||||
wl1251@0 {
|
||||
compatible = "ti,wl1251";
|
||||
|
||||
reg = <0>;
|
||||
spi-max-frequency = <48000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <10 IRQ_TYPE_NONE>; /* gpio line 42 */
|
||||
|
||||
vio-supply = <&vio>;
|
||||
ti,power-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */
|
||||
};
|
||||
};
|
|
@ -536,11 +536,13 @@ static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
|
|||
|
||||
static void __init pandora_wl1251_init(void)
|
||||
{
|
||||
struct wl12xx_platform_data pandora_wl1251_pdata;
|
||||
struct wl1251_platform_data pandora_wl1251_pdata;
|
||||
int ret;
|
||||
|
||||
memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata));
|
||||
|
||||
pandora_wl1251_pdata.power_gpio = -1;
|
||||
|
||||
ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq");
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
@ -550,7 +552,7 @@ static void __init pandora_wl1251_init(void)
|
|||
goto fail_irq;
|
||||
|
||||
pandora_wl1251_pdata.use_eeprom = true;
|
||||
ret = wl12xx_set_platform_data(&pandora_wl1251_pdata);
|
||||
ret = wl1251_set_platform_data(&pandora_wl1251_pdata);
|
||||
if (ret < 0)
|
||||
goto fail_irq;
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ enum {
|
|||
RX51_SPI_MIPID, /* LCD panel */
|
||||
};
|
||||
|
||||
static struct wl12xx_platform_data wl1251_pdata;
|
||||
static struct wl1251_platform_data wl1251_pdata;
|
||||
static struct tsc2005_platform_data tsc2005_pdata;
|
||||
|
||||
#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
|
||||
|
@ -1173,13 +1173,7 @@ static inline void board_smc91x_init(void)
|
|||
|
||||
#endif
|
||||
|
||||
static void rx51_wl1251_set_power(bool enable)
|
||||
{
|
||||
gpio_set_value(RX51_WL1251_POWER_GPIO, enable);
|
||||
}
|
||||
|
||||
static struct gpio rx51_wl1251_gpios[] __initdata = {
|
||||
{ RX51_WL1251_POWER_GPIO, GPIOF_OUT_INIT_LOW, "wl1251 power" },
|
||||
{ RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" },
|
||||
};
|
||||
|
||||
|
@ -1196,17 +1190,16 @@ static void __init rx51_init_wl1251(void)
|
|||
if (irq < 0)
|
||||
goto err_irq;
|
||||
|
||||
wl1251_pdata.set_power = rx51_wl1251_set_power;
|
||||
wl1251_pdata.power_gpio = RX51_WL1251_POWER_GPIO;
|
||||
rx51_peripherals_spi_board_info[RX51_SPI_WL1251].irq = irq;
|
||||
|
||||
return;
|
||||
|
||||
err_irq:
|
||||
gpio_free(RX51_WL1251_IRQ_GPIO);
|
||||
gpio_free(RX51_WL1251_POWER_GPIO);
|
||||
error:
|
||||
printk(KERN_ERR "wl1251 board initialisation failed\n");
|
||||
wl1251_pdata.set_power = NULL;
|
||||
wl1251_pdata.power_gpio = -1;
|
||||
|
||||
/*
|
||||
* Now rx51_peripherals_spi_board_info[1].irq is zero and
|
||||
|
|
|
@ -62,50 +62,53 @@ static const struct usb_device_id ath3k_table[] = {
|
|||
{ USB_DEVICE(0x0CF3, 0x3000) },
|
||||
|
||||
/* Atheros AR3011 with sflash firmware*/
|
||||
{ USB_DEVICE(0x0489, 0xE027) },
|
||||
{ USB_DEVICE(0x0489, 0xE03D) },
|
||||
{ USB_DEVICE(0x0930, 0x0215) },
|
||||
{ USB_DEVICE(0x0CF3, 0x3002) },
|
||||
{ USB_DEVICE(0x0CF3, 0xE019) },
|
||||
{ USB_DEVICE(0x13d3, 0x3304) },
|
||||
{ USB_DEVICE(0x0930, 0x0215) },
|
||||
{ USB_DEVICE(0x0489, 0xE03D) },
|
||||
{ USB_DEVICE(0x0489, 0xE027) },
|
||||
|
||||
/* Atheros AR9285 Malbec with sflash firmware */
|
||||
{ USB_DEVICE(0x03F0, 0x311D) },
|
||||
|
||||
/* Atheros AR3012 with sflash firmware*/
|
||||
{ USB_DEVICE(0x0CF3, 0x0036) },
|
||||
{ USB_DEVICE(0x0CF3, 0x3004) },
|
||||
{ USB_DEVICE(0x0CF3, 0x3008) },
|
||||
{ USB_DEVICE(0x0CF3, 0x311D) },
|
||||
{ USB_DEVICE(0x0CF3, 0x817a) },
|
||||
{ USB_DEVICE(0x13d3, 0x3375) },
|
||||
{ USB_DEVICE(0x0489, 0xe04d) },
|
||||
{ USB_DEVICE(0x0489, 0xe04e) },
|
||||
{ USB_DEVICE(0x0489, 0xe057) },
|
||||
{ USB_DEVICE(0x0489, 0xe056) },
|
||||
{ USB_DEVICE(0x0489, 0xe05f) },
|
||||
{ USB_DEVICE(0x04c5, 0x1330) },
|
||||
{ USB_DEVICE(0x04CA, 0x3004) },
|
||||
{ USB_DEVICE(0x04CA, 0x3005) },
|
||||
{ USB_DEVICE(0x04CA, 0x3006) },
|
||||
{ USB_DEVICE(0x04CA, 0x3008) },
|
||||
{ USB_DEVICE(0x04CA, 0x300b) },
|
||||
{ USB_DEVICE(0x13d3, 0x3362) },
|
||||
{ USB_DEVICE(0x0CF3, 0xE004) },
|
||||
{ USB_DEVICE(0x0CF3, 0xE005) },
|
||||
{ USB_DEVICE(0x0930, 0x0219) },
|
||||
{ USB_DEVICE(0x0930, 0x0220) },
|
||||
{ USB_DEVICE(0x0489, 0xe057) },
|
||||
{ USB_DEVICE(0x13d3, 0x3393) },
|
||||
{ USB_DEVICE(0x0489, 0xe04e) },
|
||||
{ USB_DEVICE(0x0489, 0xe056) },
|
||||
{ USB_DEVICE(0x0489, 0xe04d) },
|
||||
{ USB_DEVICE(0x04c5, 0x1330) },
|
||||
{ USB_DEVICE(0x13d3, 0x3402) },
|
||||
{ USB_DEVICE(0x0b05, 0x17d0) },
|
||||
{ USB_DEVICE(0x0CF3, 0x0036) },
|
||||
{ USB_DEVICE(0x0CF3, 0x3004) },
|
||||
{ USB_DEVICE(0x0CF3, 0x3008) },
|
||||
{ USB_DEVICE(0x0CF3, 0x311D) },
|
||||
{ USB_DEVICE(0x0CF3, 0x311E) },
|
||||
{ USB_DEVICE(0x0CF3, 0x311F) },
|
||||
{ USB_DEVICE(0x0cf3, 0x3121) },
|
||||
{ USB_DEVICE(0x0CF3, 0x817a) },
|
||||
{ USB_DEVICE(0x0cf3, 0xe003) },
|
||||
{ USB_DEVICE(0x0489, 0xe05f) },
|
||||
{ USB_DEVICE(0x0CF3, 0xE004) },
|
||||
{ USB_DEVICE(0x0CF3, 0xE005) },
|
||||
{ USB_DEVICE(0x13d3, 0x3362) },
|
||||
{ USB_DEVICE(0x13d3, 0x3375) },
|
||||
{ USB_DEVICE(0x13d3, 0x3393) },
|
||||
{ USB_DEVICE(0x13d3, 0x3402) },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE02C) },
|
||||
|
||||
/* Atheros AR5BBU22 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE03C) },
|
||||
{ USB_DEVICE(0x0489, 0xE036) },
|
||||
{ USB_DEVICE(0x0489, 0xE03C) },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
@ -118,36 +121,39 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
|
|||
static const struct usb_device_id ath3k_blist_tbl[] = {
|
||||
|
||||
/* Atheros AR3012 with sflash firmware*/
|
||||
{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Atheros AR5BBU22 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
|
|
@ -101,21 +101,24 @@ static const struct usb_device_id btusb_table[] = {
|
|||
{ USB_DEVICE(0x0c10, 0x0000) },
|
||||
|
||||
/* Broadcom BCM20702A0 */
|
||||
{ USB_DEVICE(0x0489, 0xe042) },
|
||||
{ USB_DEVICE(0x04ca, 0x2003) },
|
||||
{ USB_DEVICE(0x0b05, 0x17b5) },
|
||||
{ USB_DEVICE(0x0b05, 0x17cb) },
|
||||
{ USB_DEVICE(0x04ca, 0x2003) },
|
||||
{ USB_DEVICE(0x0489, 0xe042) },
|
||||
{ USB_DEVICE(0x413c, 0x8197) },
|
||||
|
||||
/* Foxconn - Hon Hai */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
|
||||
|
||||
/*Broadcom devices with vendor specific id */
|
||||
/* Broadcom devices with vendor specific id */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
|
||||
|
||||
/* Belkin F8065bf - Broadcom based */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
|
||||
|
||||
/* IMC Networks - Broadcom based */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
|
@ -129,55 +132,58 @@ static const struct usb_device_id blacklist_table[] = {
|
|||
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Atheros 3011 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Atheros AR9285 Malbec with sflash firmware */
|
||||
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Atheros 3012 with sflash firmware */
|
||||
{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Broadcom BCM2035 */
|
||||
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
|
||||
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
|
||||
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
|
||||
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
|
||||
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
|
||||
|
||||
/* Broadcom BCM2045 */
|
||||
{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },
|
||||
|
|
|
@ -359,7 +359,7 @@ static const struct file_operations vhci_fops = {
|
|||
static struct miscdevice vhci_miscdev= {
|
||||
.name = "vhci",
|
||||
.fops = &vhci_fops,
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.minor = VHCI_MINOR,
|
||||
};
|
||||
|
||||
static int __init vhci_init(void)
|
||||
|
@ -385,3 +385,4 @@ MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
|
|||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("devname:vhci");
|
||||
MODULE_ALIAS_MISCDEV(VHCI_MINOR);
|
||||
|
|
|
@ -53,7 +53,7 @@ config LIBERTAS_THINFIRM_USB
|
|||
|
||||
config AIRO
|
||||
tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
|
||||
depends on ISA_DMA_API && (PCI || BROKEN)
|
||||
depends on CFG80211 && ISA_DMA_API && (PCI || BROKEN)
|
||||
select WIRELESS_EXT
|
||||
select CRYPTO
|
||||
select WEXT_SPY
|
||||
|
@ -73,7 +73,7 @@ config AIRO
|
|||
|
||||
config ATMEL
|
||||
tristate "Atmel at76c50x chipset 802.11b support"
|
||||
depends on (PCI || PCMCIA)
|
||||
depends on CFG80211 && (PCI || PCMCIA)
|
||||
select WIRELESS_EXT
|
||||
select WEXT_PRIV
|
||||
select FW_LOADER
|
||||
|
@ -138,7 +138,7 @@ config AIRO_CS
|
|||
|
||||
config PCMCIA_WL3501
|
||||
tristate "Planet WL3501 PCMCIA cards"
|
||||
depends on PCMCIA
|
||||
depends on CFG80211 && PCMCIA
|
||||
select WIRELESS_EXT
|
||||
select WEXT_SPY
|
||||
help
|
||||
|
@ -168,7 +168,7 @@ config PRISM54
|
|||
|
||||
config USB_ZD1201
|
||||
tristate "USB ZD1201 based Wireless device support"
|
||||
depends on USB
|
||||
depends on CFG80211 && USB
|
||||
select WIRELESS_EXT
|
||||
select WEXT_PRIV
|
||||
select FW_LOADER
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
@ -45,11 +45,11 @@
|
|||
#include <linux/if_arp.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include "airo.h"
|
||||
|
@ -5797,7 +5797,7 @@ static int airo_set_freq(struct net_device *dev,
|
|||
|
||||
/* Hack to fall through... */
|
||||
fwrq->e = 0;
|
||||
fwrq->m = ieee80211_freq_to_dsss_chan(f);
|
||||
fwrq->m = ieee80211_frequency_to_channel(f);
|
||||
}
|
||||
/* Setting by channel number */
|
||||
if((fwrq->m > 1000) || (fwrq->e > 0))
|
||||
|
@ -5841,7 +5841,8 @@ static int airo_get_freq(struct net_device *dev,
|
|||
|
||||
ch = le16_to_cpu(status_rid.channel);
|
||||
if((ch > 0) && (ch < 15)) {
|
||||
fwrq->m = ieee80211_dsss_chan_to_freq(ch) * 100000;
|
||||
fwrq->m = 100000 *
|
||||
ieee80211_channel_to_frequency(ch, IEEE80211_BAND_2GHZ);
|
||||
fwrq->e = 1;
|
||||
} else {
|
||||
fwrq->m = ch;
|
||||
|
@ -6898,7 +6899,8 @@ static int airo_get_range(struct net_device *dev,
|
|||
k = 0;
|
||||
for(i = 0; i < 14; i++) {
|
||||
range->freq[k].i = i + 1; /* List index */
|
||||
range->freq[k].m = ieee80211_dsss_chan_to_freq(i + 1) * 100000;
|
||||
range->freq[k].m = 100000 *
|
||||
ieee80211_channel_to_frequency(i + 1, IEEE80211_BAND_2GHZ);
|
||||
range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */
|
||||
}
|
||||
range->num_frequency = k;
|
||||
|
@ -7297,7 +7299,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
|
|||
/* Add frequency */
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
|
||||
iwe.u.freq.m = ieee80211_dsss_chan_to_freq(iwe.u.freq.m) * 100000;
|
||||
iwe.u.freq.m = 100000 *
|
||||
ieee80211_channel_to_frequency(iwe.u.freq.m, IEEE80211_BAND_2GHZ);
|
||||
iwe.u.freq.e = 1;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_FREQ_LEN);
|
||||
|
|
|
@ -63,7 +63,7 @@ enum ath_bus_type {
|
|||
};
|
||||
|
||||
struct reg_dmn_pair_mapping {
|
||||
u16 regDmnEnum;
|
||||
u16 reg_domain;
|
||||
u16 reg_5ghz_ctl;
|
||||
u16 reg_2ghz_ctl;
|
||||
};
|
||||
|
@ -163,6 +163,7 @@ struct ath_common {
|
|||
bool bt_ant_diversity;
|
||||
|
||||
int last_rssi;
|
||||
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
|
||||
};
|
||||
|
||||
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
|
||||
|
|
|
@ -55,8 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
|
|||
{
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
|
||||
|
||||
ar->is_target_paused = true;
|
||||
wake_up(&ar->event_queue);
|
||||
complete(&ar->target_suspend);
|
||||
}
|
||||
|
||||
static int ath10k_init_connect_htc(struct ath10k *ar)
|
||||
|
@ -470,8 +469,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
|
|||
if (index == ie_len)
|
||||
break;
|
||||
|
||||
if (data[index] & (1 << bit))
|
||||
if (data[index] & (1 << bit)) {
|
||||
ath10k_dbg(ATH10K_DBG_BOOT,
|
||||
"Enabling feature bit: %i\n",
|
||||
i);
|
||||
__set_bit(i, ar->fw_features);
|
||||
}
|
||||
}
|
||||
|
||||
ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
|
||||
|
@ -699,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
|||
init_completion(&ar->scan.started);
|
||||
init_completion(&ar->scan.completed);
|
||||
init_completion(&ar->scan.on_channel);
|
||||
init_completion(&ar->target_suspend);
|
||||
|
||||
init_completion(&ar->install_key_done);
|
||||
init_completion(&ar->vdev_setup_done);
|
||||
|
@ -722,8 +726,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
|||
INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
|
||||
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
|
||||
|
||||
init_waitqueue_head(&ar->event_queue);
|
||||
|
||||
INIT_WORK(&ar->restart_work, ath10k_core_restart);
|
||||
|
||||
return ar;
|
||||
|
@ -856,10 +858,34 @@ int ath10k_core_start(struct ath10k *ar)
|
|||
}
|
||||
EXPORT_SYMBOL(ath10k_core_start);
|
||||
|
||||
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
reinit_completion(&ar->target_suspend);
|
||||
|
||||
ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);
|
||||
if (ret) {
|
||||
ath10k_warn("could not suspend target (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
|
||||
|
||||
if (ret == 0) {
|
||||
ath10k_warn("suspend timed out - target pause event never came\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_core_stop(struct ath10k *ar)
|
||||
{
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
/* try to suspend target */
|
||||
ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
|
||||
ath10k_debug_stop(ar);
|
||||
ath10k_htc_stop(&ar->htc);
|
||||
ath10k_htt_detach(&ar->htt);
|
||||
|
|
|
@ -46,6 +46,18 @@
|
|||
|
||||
#define ATH10K_MAX_NUM_MGMT_PENDING 128
|
||||
|
||||
/* number of failed packets */
|
||||
#define ATH10K_KICKOUT_THRESHOLD 50
|
||||
|
||||
/*
|
||||
* Use insanely high numbers to make sure that the firmware implementation
|
||||
* won't start, we have the same functionality already in hostapd. Unit
|
||||
* is seconds.
|
||||
*/
|
||||
#define ATH10K_KEEPALIVE_MIN_IDLE 3747
|
||||
#define ATH10K_KEEPALIVE_MAX_IDLE 3895
|
||||
#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900
|
||||
|
||||
struct ath10k;
|
||||
|
||||
struct ath10k_skb_cb {
|
||||
|
@ -61,6 +73,11 @@ struct ath10k_skb_cb {
|
|||
u8 frag_len;
|
||||
u8 pad_len;
|
||||
} __packed htt;
|
||||
|
||||
struct {
|
||||
bool dtim_zero;
|
||||
bool deliver_cab;
|
||||
} bcn;
|
||||
} __packed;
|
||||
|
||||
static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
|
||||
|
@ -211,6 +228,18 @@ struct ath10k_peer {
|
|||
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
|
||||
};
|
||||
|
||||
struct ath10k_sta {
|
||||
struct ath10k_vif *arvif;
|
||||
|
||||
/* the following are protected by ar->data_lock */
|
||||
u32 changed; /* IEEE80211_RC_* */
|
||||
u32 bw;
|
||||
u32 nss;
|
||||
u32 smps;
|
||||
|
||||
struct work_struct update_wk;
|
||||
};
|
||||
|
||||
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
|
||||
|
||||
struct ath10k_vif {
|
||||
|
@ -222,10 +251,17 @@ struct ath10k_vif {
|
|||
u32 beacon_interval;
|
||||
u32 dtim_period;
|
||||
struct sk_buff *beacon;
|
||||
/* protected by data_lock */
|
||||
bool beacon_sent;
|
||||
|
||||
struct ath10k *ar;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
bool is_started;
|
||||
bool is_up;
|
||||
u32 aid;
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
||||
struct work_struct wep_key_work;
|
||||
struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
|
||||
u8 def_wep_key_idx;
|
||||
|
@ -235,7 +271,6 @@ struct ath10k_vif {
|
|||
|
||||
union {
|
||||
struct {
|
||||
u8 bssid[ETH_ALEN];
|
||||
u32 uapsd;
|
||||
} sta;
|
||||
struct {
|
||||
|
@ -249,9 +284,6 @@ struct ath10k_vif {
|
|||
u32 noa_len;
|
||||
u8 *noa_data;
|
||||
} ap;
|
||||
struct {
|
||||
u8 bssid[ETH_ALEN];
|
||||
} ibss;
|
||||
} u;
|
||||
|
||||
u8 fixed_rate;
|
||||
|
@ -355,8 +387,7 @@ struct ath10k {
|
|||
const struct ath10k_hif_ops *ops;
|
||||
} hif;
|
||||
|
||||
wait_queue_head_t event_queue;
|
||||
bool is_target_paused;
|
||||
struct completion target_suspend;
|
||||
|
||||
struct ath10k_bmi bmi;
|
||||
struct ath10k_wmi wmi;
|
||||
|
@ -412,6 +443,9 @@ struct ath10k {
|
|||
/* valid during scan; needed for mgmt rx during scan */
|
||||
struct ieee80211_channel *scan_channel;
|
||||
|
||||
/* current operating channel definition */
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
||||
int free_vdev_map;
|
||||
int monitor_vdev_id;
|
||||
bool monitor_enabled;
|
||||
|
@ -470,6 +504,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
|||
void ath10k_core_destroy(struct ath10k *ar);
|
||||
|
||||
int ath10k_core_start(struct ath10k *ar);
|
||||
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
|
||||
void ath10k_core_stop(struct ath10k *ar);
|
||||
int ath10k_core_register(struct ath10k *ar, u32 chip_id);
|
||||
void ath10k_core_unregister(struct ath10k *ar);
|
||||
|
|
|
@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
|
|||
|
||||
#ifdef CONFIG_ATH10K_DEBUG
|
||||
__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
|
||||
const char *fmt, ...);
|
||||
const char *fmt, ...);
|
||||
void ath10k_dbg_dump(enum ath10k_debug_mask mask,
|
||||
const char *msg, const char *prefix,
|
||||
const void *buf, size_t len);
|
||||
|
|
|
@ -324,7 +324,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
|||
msdu->len + skb_tailroom(msdu),
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ",
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
|
||||
msdu->data, msdu->len + skb_tailroom(msdu));
|
||||
|
||||
rx_desc = (struct htt_rx_desc *)msdu->data;
|
||||
|
@ -417,8 +417,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
|||
next->len + skb_tailroom(next),
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ",
|
||||
next->data,
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
|
||||
"htt rx chained: ", next->data,
|
||||
next->len + skb_tailroom(next));
|
||||
|
||||
skb_trim(next, 0);
|
||||
|
@ -430,12 +430,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
|||
msdu_chaining = 1;
|
||||
}
|
||||
|
||||
if (msdu_len > 0) {
|
||||
/* This may suggest FW bug? */
|
||||
ath10k_warn("htt rx msdu len not consumed (%d)\n",
|
||||
msdu_len);
|
||||
}
|
||||
|
||||
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
|
||||
RX_MSDU_END_INFO0_LAST_MSDU;
|
||||
|
||||
|
@ -751,7 +745,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
|
|||
|
||||
/* This shouldn't happen. If it does than it may be a FW bug. */
|
||||
if (skb->next) {
|
||||
ath10k_warn("received chained non A-MSDU frame\n");
|
||||
ath10k_warn("htt rx received chained non A-MSDU frame\n");
|
||||
ath10k_htt_rx_free_msdu_chain(skb->next);
|
||||
skb->next = NULL;
|
||||
}
|
||||
|
@ -937,6 +931,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
|||
}
|
||||
|
||||
if (ath10k_htt_rx_has_decrypt_err(msdu_head)) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx dropping due to decrypt-err\n");
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
|
@ -945,12 +941,14 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
|||
|
||||
/* Skip mgmt frames while we handle this in WMI */
|
||||
if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status != HTT_RX_IND_MPDU_STATUS_OK &&
|
||||
status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
|
||||
status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
|
||||
!htt->ar->monitor_enabled) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx ignoring frame w/ status %d\n",
|
||||
|
@ -960,6 +958,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
|||
}
|
||||
|
||||
if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx CAC running\n");
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
|
@ -967,7 +967,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
|||
/* FIXME: we do not support chaining yet.
|
||||
* this needs investigation */
|
||||
if (msdu_chaining) {
|
||||
ath10k_warn("msdu_chaining is true\n");
|
||||
ath10k_warn("htt rx msdu_chaining is true\n");
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
|
@ -975,6 +975,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
|||
info.skb = msdu_head;
|
||||
info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
|
||||
info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head);
|
||||
|
||||
if (info.fcs_err)
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx has FCS err\n");
|
||||
|
||||
if (info.mic_err)
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx has MIC err\n");
|
||||
|
||||
info.signal = ATH10K_DEFAULT_NOISE_FLOOR;
|
||||
info.signal += rx->ppdu.combined_rssi;
|
||||
|
||||
|
@ -1095,7 +1104,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
|||
|
||||
skb_trim(info.skb, info.skb->len - trim);
|
||||
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt frag mpdu: ",
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
|
||||
info.skb->data, info.skb->len);
|
||||
ath10k_process_rx(htt->ar, &info);
|
||||
|
||||
|
@ -1116,7 +1125,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
|||
if (!IS_ALIGNED((unsigned long)skb->data, 4))
|
||||
ath10k_warn("unaligned htt message, expect trouble\n");
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "HTT RX, msg_type: 0x%0X\n",
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
|
||||
resp->hdr.msg_type);
|
||||
switch (resp->hdr.msg_type) {
|
||||
case HTT_T2H_MSG_TYPE_VERSION_CONF: {
|
||||
|
|
|
@ -460,9 +460,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
|||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n",
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "tx-msdu 0x%llx\n",
|
||||
(unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ",
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "tx-msdu: ",
|
||||
msdu->data, msdu->len);
|
||||
|
||||
skb_put(txdesc, desc_len);
|
||||
|
|
|
@ -205,8 +205,11 @@ enum ath10k_mcast2ucast_mode {
|
|||
#define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000
|
||||
#define PCIE_LOCAL_BASE_ADDRESS 0x00080000
|
||||
|
||||
#define SOC_RESET_CONTROL_ADDRESS 0x00000000
|
||||
#define SOC_RESET_CONTROL_OFFSET 0x00000000
|
||||
#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001
|
||||
#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000
|
||||
#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040
|
||||
#define SOC_CPU_CLOCK_OFFSET 0x00000020
|
||||
#define SOC_CPU_CLOCK_STANDARD_LSB 0
|
||||
#define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003
|
||||
|
@ -216,6 +219,8 @@ enum ath10k_mcast2ucast_mode {
|
|||
#define SOC_LPO_CAL_OFFSET 0x000000e0
|
||||
#define SOC_LPO_CAL_ENABLE_LSB 20
|
||||
#define SOC_LPO_CAL_ENABLE_MASK 0x00100000
|
||||
#define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050
|
||||
#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004
|
||||
|
||||
#define SOC_CHIP_ID_ADDRESS 0x000000ec
|
||||
#define SOC_CHIP_ID_REV_LSB 8
|
||||
|
@ -273,6 +278,7 @@ enum ath10k_mcast2ucast_mode {
|
|||
#define PCIE_INTR_CAUSE_ADDRESS 0x000c
|
||||
#define PCIE_INTR_CLR_ADDRESS 0x0014
|
||||
#define SCRATCH_3_ADDRESS 0x0030
|
||||
#define CPU_INTR_ADDRESS 0x0010
|
||||
|
||||
/* Firmware indications to the Host via SCRATCH_3 register. */
|
||||
#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS)
|
||||
|
|
|
@ -339,6 +339,50 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
u32 param;
|
||||
int ret;
|
||||
|
||||
param = ar->wmi.pdev_param->sta_kickout_th;
|
||||
ret = ath10k_wmi_pdev_set_param(ar, param,
|
||||
ATH10K_KICKOUT_THRESHOLD);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set kickout threshold: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
|
||||
ATH10K_KEEPALIVE_MIN_IDLE);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set keepalive minimum idle time : %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
|
||||
ATH10K_KEEPALIVE_MAX_IDLE);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set keepalive maximum idle time: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
|
||||
ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set keepalive maximum unresponsive time: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
|
@ -444,8 +488,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
|
|||
static int ath10k_vdev_start(struct ath10k_vif *arvif)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
struct ieee80211_conf *conf = &ar->hw->conf;
|
||||
struct ieee80211_channel *channel = conf->chandef.chan;
|
||||
struct cfg80211_chan_def *chandef = &ar->chandef;
|
||||
struct wmi_vdev_start_request_arg arg = {};
|
||||
int ret = 0;
|
||||
|
||||
|
@ -457,16 +500,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
|
|||
arg.dtim_period = arvif->dtim_period;
|
||||
arg.bcn_intval = arvif->beacon_interval;
|
||||
|
||||
arg.channel.freq = channel->center_freq;
|
||||
|
||||
arg.channel.band_center_freq1 = conf->chandef.center_freq1;
|
||||
|
||||
arg.channel.mode = chan_to_phymode(&conf->chandef);
|
||||
arg.channel.freq = chandef->chan->center_freq;
|
||||
arg.channel.band_center_freq1 = chandef->center_freq1;
|
||||
arg.channel.mode = chan_to_phymode(chandef);
|
||||
|
||||
arg.channel.min_power = 0;
|
||||
arg.channel.max_power = channel->max_power * 2;
|
||||
arg.channel.max_reg_power = channel->max_reg_power * 2;
|
||||
arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
|
||||
arg.channel.max_power = chandef->chan->max_power * 2;
|
||||
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
|
||||
arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||
arg.ssid = arvif->u.ap.ssid;
|
||||
|
@ -475,7 +516,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
|
|||
|
||||
/* For now allow DFS for AP mode */
|
||||
arg.channel.chan_radar =
|
||||
!!(channel->flags & IEEE80211_CHAN_RADAR);
|
||||
!!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
|
||||
} else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
|
||||
arg.ssid = arvif->vif->bss_conf.ssid;
|
||||
arg.ssid_len = arvif->vif->bss_conf.ssid_len;
|
||||
|
@ -527,7 +568,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
|
|||
|
||||
static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
|
||||
{
|
||||
struct ieee80211_channel *channel = ar->hw->conf.chandef.chan;
|
||||
struct cfg80211_chan_def *chandef = &ar->chandef;
|
||||
struct ieee80211_channel *channel = chandef->chan;
|
||||
struct wmi_vdev_start_request_arg arg = {};
|
||||
int ret = 0;
|
||||
|
||||
|
@ -540,11 +582,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
|
|||
|
||||
arg.vdev_id = vdev_id;
|
||||
arg.channel.freq = channel->center_freq;
|
||||
arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1;
|
||||
arg.channel.band_center_freq1 = chandef->center_freq1;
|
||||
|
||||
/* TODO setup this dynamically, what in case we
|
||||
don't have any vifs? */
|
||||
arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef);
|
||||
arg.channel.mode = chan_to_phymode(chandef);
|
||||
arg.channel.chan_radar =
|
||||
!!(channel->flags & IEEE80211_CHAN_RADAR);
|
||||
|
||||
|
@ -791,6 +833,20 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
|
|||
|
||||
if (!info->enable_beacon) {
|
||||
ath10k_vdev_stop(arvif);
|
||||
|
||||
arvif->is_started = false;
|
||||
arvif->is_up = false;
|
||||
|
||||
spin_lock_bh(&arvif->ar->data_lock);
|
||||
if (arvif->beacon) {
|
||||
ath10k_skb_unmap(arvif->ar->dev, arvif->beacon);
|
||||
dev_kfree_skb_any(arvif->beacon);
|
||||
|
||||
arvif->beacon = NULL;
|
||||
arvif->beacon_sent = false;
|
||||
}
|
||||
spin_unlock_bh(&arvif->ar->data_lock);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -800,12 +856,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
|
|||
if (ret)
|
||||
return;
|
||||
|
||||
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid);
|
||||
arvif->aid = 0;
|
||||
memcpy(arvif->bssid, info->bssid, ETH_ALEN);
|
||||
|
||||
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
||||
arvif->bssid);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to bring up VDEV: %d\n",
|
||||
arvif->vdev_id);
|
||||
ath10k_vdev_stop(arvif);
|
||||
return;
|
||||
}
|
||||
|
||||
arvif->is_started = true;
|
||||
arvif->is_up = true;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
|
||||
}
|
||||
|
||||
|
@ -824,18 +889,18 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
|
|||
ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n",
|
||||
self_peer, arvif->vdev_id, ret);
|
||||
|
||||
if (is_zero_ether_addr(arvif->u.ibss.bssid))
|
||||
if (is_zero_ether_addr(arvif->bssid))
|
||||
return;
|
||||
|
||||
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
|
||||
arvif->u.ibss.bssid);
|
||||
arvif->bssid);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n",
|
||||
arvif->u.ibss.bssid, arvif->vdev_id, ret);
|
||||
arvif->bssid, arvif->vdev_id, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(arvif->u.ibss.bssid, 0, ETH_ALEN);
|
||||
memset(arvif->bssid, 0, ETH_ALEN);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1017,7 +1082,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
|||
struct wmi_peer_assoc_complete_arg *arg)
|
||||
{
|
||||
const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
|
||||
int smps;
|
||||
int i, n;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
@ -1063,17 +1127,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
|||
arg->peer_flags |= WMI_PEER_STBC;
|
||||
}
|
||||
|
||||
smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
|
||||
smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
|
||||
|
||||
if (smps == WLAN_HT_CAP_SM_PS_STATIC) {
|
||||
arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
|
||||
arg->peer_flags |= WMI_PEER_STATIC_MIMOPS;
|
||||
} else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) {
|
||||
arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
|
||||
arg->peer_flags |= WMI_PEER_DYN_MIMOPS;
|
||||
}
|
||||
|
||||
if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
|
||||
arg->peer_rate_caps |= WMI_RC_TS_FLAG;
|
||||
else if (ht_cap->mcs.rx_mask[1])
|
||||
|
@ -1083,8 +1136,23 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
|||
if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8))
|
||||
arg->peer_ht_rates.rates[n++] = i;
|
||||
|
||||
arg->peer_ht_rates.num_rates = n;
|
||||
arg->peer_num_spatial_streams = max((n+7) / 8, 1);
|
||||
/*
|
||||
* This is a workaround for HT-enabled STAs which break the spec
|
||||
* and have no HT capabilities RX mask (no HT RX MCS map).
|
||||
*
|
||||
* As per spec, in section 20.3.5 Modulation and coding scheme (MCS),
|
||||
* MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs.
|
||||
*
|
||||
* Firmware asserts if such situation occurs.
|
||||
*/
|
||||
if (n == 0) {
|
||||
arg->peer_ht_rates.num_rates = 8;
|
||||
for (i = 0; i < arg->peer_ht_rates.num_rates; i++)
|
||||
arg->peer_ht_rates.rates[i] = i;
|
||||
} else {
|
||||
arg->peer_ht_rates.num_rates = n;
|
||||
arg->peer_num_spatial_streams = sta->rx_nss;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
|
||||
arg->addr,
|
||||
|
@ -1092,27 +1160,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
|
|||
arg->peer_num_spatial_streams);
|
||||
}
|
||||
|
||||
static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
|
||||
struct ath10k_vif *arvif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
struct wmi_peer_assoc_complete_arg *arg)
|
||||
static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
|
||||
struct ath10k_vif *arvif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
u32 uapsd = 0;
|
||||
u32 max_sp = 0;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
if (sta->wme)
|
||||
arg->peer_flags |= WMI_PEER_QOS;
|
||||
|
||||
if (sta->wme && sta->uapsd_queues) {
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
|
||||
sta->uapsd_queues, sta->max_sp);
|
||||
|
||||
arg->peer_flags |= WMI_PEER_APSD;
|
||||
arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
|
||||
|
||||
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
|
||||
uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
|
||||
WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
|
||||
|
@ -1130,35 +1191,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
|
|||
if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
|
||||
max_sp = sta->max_sp;
|
||||
|
||||
ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
|
||||
sta->addr,
|
||||
WMI_AP_PS_PEER_PARAM_UAPSD,
|
||||
uapsd);
|
||||
ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
|
||||
sta->addr,
|
||||
WMI_AP_PS_PEER_PARAM_UAPSD,
|
||||
uapsd);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to set ap ps peer param uapsd: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
|
||||
sta->addr,
|
||||
WMI_AP_PS_PEER_PARAM_MAX_SP,
|
||||
max_sp);
|
||||
ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
|
||||
sta->addr,
|
||||
WMI_AP_PS_PEER_PARAM_MAX_SP,
|
||||
max_sp);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to set ap ps peer param max sp: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO setup this based on STA listen interval and
|
||||
beacon interval. Currently we don't know
|
||||
sta->listen_interval - mac80211 patch required.
|
||||
Currently use 10 seconds */
|
||||
ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
|
||||
sta->addr,
|
||||
WMI_AP_PS_PEER_PARAM_AGEOUT_TIME,
|
||||
10);
|
||||
ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
|
||||
WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to set ap ps peer param ageout time: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar,
|
||||
struct ath10k_vif *arvif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
struct wmi_peer_assoc_complete_arg *arg)
|
||||
{
|
||||
if (bss_conf->qos)
|
||||
arg->peer_flags |= WMI_PEER_QOS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
|
||||
|
@ -1211,10 +1277,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
|
|||
{
|
||||
switch (arvif->vdev_type) {
|
||||
case WMI_VDEV_TYPE_AP:
|
||||
ath10k_peer_assoc_h_qos_ap(ar, arvif, sta, bss_conf, arg);
|
||||
if (sta->wme)
|
||||
arg->peer_flags |= WMI_PEER_QOS;
|
||||
|
||||
if (sta->wme && sta->uapsd_queues) {
|
||||
arg->peer_flags |= WMI_PEER_APSD;
|
||||
arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
|
||||
}
|
||||
break;
|
||||
case WMI_VDEV_TYPE_STA:
|
||||
ath10k_peer_assoc_h_qos_sta(ar, arvif, sta, bss_conf, arg);
|
||||
if (bss_conf->qos)
|
||||
arg->peer_flags |= WMI_PEER_QOS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1293,6 +1366,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const u32 ath10k_smps_map[] = {
|
||||
[WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC,
|
||||
[WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC,
|
||||
[WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE,
|
||||
[WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
|
||||
};
|
||||
|
||||
static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif,
|
||||
const u8 *addr,
|
||||
const struct ieee80211_sta_ht_cap *ht_cap)
|
||||
{
|
||||
int smps;
|
||||
|
||||
if (!ht_cap->ht_supported)
|
||||
return 0;
|
||||
|
||||
smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
|
||||
smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
|
||||
|
||||
if (smps >= ARRAY_SIZE(ath10k_smps_map))
|
||||
return -EINVAL;
|
||||
|
||||
return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr,
|
||||
WMI_PEER_SMPS_STATE,
|
||||
ath10k_smps_map[smps]);
|
||||
}
|
||||
|
||||
/* can be called only in mac80211 callbacks due to `key_count` usage */
|
||||
static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
|
@ -1300,6 +1400,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct ieee80211_sta_ht_cap ht_cap;
|
||||
struct wmi_peer_assoc_complete_arg peer_arg;
|
||||
struct ieee80211_sta *ap_sta;
|
||||
int ret;
|
||||
|
@ -1316,6 +1417,10 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
|||
return;
|
||||
}
|
||||
|
||||
/* ap_sta must be accessed only within rcu section which must be left
|
||||
* before calling ath10k_setup_peer_smps() which might sleep. */
|
||||
ht_cap = ap_sta->ht_cap;
|
||||
|
||||
ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
|
||||
bss_conf, &peer_arg);
|
||||
if (ret) {
|
||||
|
@ -1334,15 +1439,27 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
|||
return;
|
||||
}
|
||||
|
||||
ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to setup peer SMPS: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac vdev %d up (associated) bssid %pM aid %d\n",
|
||||
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
|
||||
|
||||
ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid,
|
||||
bss_conf->bssid);
|
||||
if (ret)
|
||||
arvif->aid = bss_conf->aid;
|
||||
memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
|
||||
|
||||
ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
|
||||
if (ret) {
|
||||
ath10k_warn("VDEV: %d up failed: ret %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
arvif->is_up = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1382,6 +1499,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
|
|||
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
||||
|
||||
arvif->def_wep_key_idx = 0;
|
||||
|
||||
arvif->is_started = false;
|
||||
arvif->is_up = false;
|
||||
}
|
||||
|
||||
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
|
||||
|
@ -1406,12 +1526,25 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to setup peer SMPS: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
|
||||
if (ret) {
|
||||
ath10k_warn("could not install peer wep keys (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
|
||||
if (ret) {
|
||||
ath10k_warn("could not set qos params for STA %pM, %d\n",
|
||||
sta->addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1547,9 +1680,9 @@ static void ath10k_regd_update(struct ath10k *ar)
|
|||
/* Target allows setting up per-band regdomain but ath_common provides
|
||||
* a combined one only */
|
||||
ret = ath10k_wmi_pdev_set_regdomain(ar,
|
||||
regpair->regDmnEnum,
|
||||
regpair->regDmnEnum, /* 2ghz */
|
||||
regpair->regDmnEnum, /* 5ghz */
|
||||
regpair->reg_domain,
|
||||
regpair->reg_domain, /* 2ghz */
|
||||
regpair->reg_domain, /* 5ghz */
|
||||
regpair->reg_2ghz_ctl,
|
||||
regpair->reg_5ghz_ctl);
|
||||
if (ret)
|
||||
|
@ -2100,11 +2233,29 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
|||
ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
|
||||
ret);
|
||||
|
||||
/*
|
||||
* By default FW set ARP frames ac to voice (6). In that case ARP
|
||||
* exchange is not working properly for UAPSD enabled AP. ARP requests
|
||||
* which arrives with access category 0 are processed by network stack
|
||||
* and send back with access category 0, but FW changes access category
|
||||
* to 6. Set ARP frames access category to best effort (0) solves
|
||||
* this problem.
|
||||
*/
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar,
|
||||
ar->wmi.pdev_param->arp_ac_override, 0);
|
||||
if (ret) {
|
||||
ath10k_warn("could not set arp ac override parameter: %d\n",
|
||||
ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ath10k_regd_update(ar);
|
||||
ret = 0;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_stop(struct ieee80211_hw *hw)
|
||||
|
@ -2145,6 +2296,98 @@ static int ath10k_config_ps(struct ath10k *ar)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const char *chandef_get_width(enum nl80211_chan_width width)
|
||||
{
|
||||
switch (width) {
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
return "20 (noht)";
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
return "20";
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
return "40";
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
return "80";
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
return "80+80";
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
return "160";
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
return "5";
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
return "10";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
static void ath10k_config_chan(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
bool monitor_was_enabled;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
|
||||
ar->chandef.chan->center_freq,
|
||||
ar->chandef.center_freq1,
|
||||
ar->chandef.center_freq2,
|
||||
chandef_get_width(ar->chandef.width));
|
||||
|
||||
/* First stop monitor interface. Some FW versions crash if there's a
|
||||
* lone monitor interface. */
|
||||
monitor_was_enabled = ar->monitor_enabled;
|
||||
|
||||
if (ar->monitor_enabled)
|
||||
ath10k_monitor_stop(ar);
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
if (!arvif->is_started)
|
||||
continue;
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
|
||||
continue;
|
||||
|
||||
ret = ath10k_vdev_stop(arvif);
|
||||
if (ret) {
|
||||
ath10k_warn("could not stop vdev %d (%d)\n",
|
||||
arvif->vdev_id, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* all vdevs are now stopped - now attempt to restart them */
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
if (!arvif->is_started)
|
||||
continue;
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
|
||||
continue;
|
||||
|
||||
ret = ath10k_vdev_start(arvif);
|
||||
if (ret) {
|
||||
ath10k_warn("could not start vdev %d (%d)\n",
|
||||
arvif->vdev_id, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!arvif->is_up)
|
||||
continue;
|
||||
|
||||
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
||||
arvif->bssid);
|
||||
if (ret) {
|
||||
ath10k_warn("could not bring vdev up %d (%d)\n",
|
||||
arvif->vdev_id, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (monitor_was_enabled)
|
||||
ath10k_monitor_start(ar, ar->monitor_vdev_id);
|
||||
}
|
||||
|
||||
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
|
@ -2165,6 +2408,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
|
|||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ath10k_config_radar_detection(ar);
|
||||
|
||||
if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) {
|
||||
ar->chandef = conf->chandef;
|
||||
ath10k_config_chan(ar);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_POWER) {
|
||||
|
@ -2214,7 +2462,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
enum wmi_sta_powersave_param param;
|
||||
int ret = 0;
|
||||
u32 value, param_id;
|
||||
u32 value;
|
||||
int bit;
|
||||
u32 vdev_param;
|
||||
|
||||
|
@ -2307,12 +2555,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|||
goto err_vdev_delete;
|
||||
}
|
||||
|
||||
param_id = ar->wmi.pdev_param->sta_kickout_th;
|
||||
|
||||
/* Disable STA KICKOUT functionality in FW */
|
||||
ret = ath10k_wmi_pdev_set_param(ar, param_id, 0);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to disable STA KICKOUT\n");
|
||||
ret = ath10k_mac_set_kickout(arvif);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set kickout parameters: %d\n",
|
||||
ret);
|
||||
goto err_peer_delete;
|
||||
}
|
||||
}
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
|
||||
|
@ -2559,15 +2807,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
* this is never erased as we it for crypto key
|
||||
* clearing; this is FW requirement
|
||||
*/
|
||||
memcpy(arvif->u.sta.bssid, info->bssid,
|
||||
ETH_ALEN);
|
||||
memcpy(arvif->bssid, info->bssid, ETH_ALEN);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac vdev %d start %pM\n",
|
||||
arvif->vdev_id, info->bssid);
|
||||
|
||||
/* FIXME: check return value */
|
||||
ret = ath10k_vdev_start(arvif);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to start vdev: %d\n",
|
||||
ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arvif->is_started = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2576,7 +2829,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
* IBSS in order to remove BSSID peer.
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC)
|
||||
memcpy(arvif->u.ibss.bssid, info->bssid,
|
||||
memcpy(arvif->bssid, info->bssid,
|
||||
ETH_ALEN);
|
||||
}
|
||||
}
|
||||
|
@ -2645,6 +2898,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
ath10k_bss_assoc(hw, vif, info);
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
||||
|
||||
|
@ -2850,6 +3104,69 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_sta_rc_update_wk(struct work_struct *wk)
|
||||
{
|
||||
struct ath10k *ar;
|
||||
struct ath10k_vif *arvif;
|
||||
struct ath10k_sta *arsta;
|
||||
struct ieee80211_sta *sta;
|
||||
u32 changed, bw, nss, smps;
|
||||
int err;
|
||||
|
||||
arsta = container_of(wk, struct ath10k_sta, update_wk);
|
||||
sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
|
||||
arvif = arsta->arvif;
|
||||
ar = arvif->ar;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
changed = arsta->changed;
|
||||
arsta->changed = 0;
|
||||
|
||||
bw = arsta->bw;
|
||||
nss = arsta->nss;
|
||||
smps = arsta->smps;
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (changed & IEEE80211_RC_BW_CHANGED) {
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
|
||||
sta->addr, bw);
|
||||
|
||||
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
|
||||
WMI_PEER_CHAN_WIDTH, bw);
|
||||
if (err)
|
||||
ath10k_warn("failed to update STA %pM peer bw %d: %d\n",
|
||||
sta->addr, bw, err);
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_RC_NSS_CHANGED) {
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
|
||||
sta->addr, nss);
|
||||
|
||||
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
|
||||
WMI_PEER_NSS, nss);
|
||||
if (err)
|
||||
ath10k_warn("failed to update STA %pM nss %d: %d\n",
|
||||
sta->addr, nss, err);
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_RC_SMPS_CHANGED) {
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
|
||||
sta->addr, smps);
|
||||
|
||||
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
|
||||
WMI_PEER_SMPS_STATE, smps);
|
||||
if (err)
|
||||
ath10k_warn("failed to update STA %pM smps %d: %d\n",
|
||||
sta->addr, smps, err);
|
||||
}
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
||||
|
||||
static int ath10k_sta_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
|
@ -2858,9 +3175,15 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
int max_num_peers;
|
||||
int ret = 0;
|
||||
|
||||
/* cancel must be done outside the mutex to avoid deadlock */
|
||||
if ((old_state == IEEE80211_STA_NONE &&
|
||||
new_state == IEEE80211_STA_NOTEXIST))
|
||||
cancel_work_sync(&arsta->update_wk);
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (old_state == IEEE80211_STA_NOTEXIST &&
|
||||
|
@ -2885,6 +3208,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
|||
"mac vdev %d peer create %pM (new sta) num_peers %d\n",
|
||||
arvif->vdev_id, sta->addr, ar->num_peers);
|
||||
|
||||
memset(arsta, 0, sizeof(*arsta));
|
||||
arsta->arvif = arvif;
|
||||
INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);
|
||||
|
||||
ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n",
|
||||
|
@ -3234,23 +3561,14 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
|
|||
struct ath10k *ar = hw->priv;
|
||||
int ret;
|
||||
|
||||
ar->is_target_paused = false;
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
ret = ath10k_wmi_pdev_suspend_target(ar);
|
||||
ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND);
|
||||
if (ret) {
|
||||
ath10k_warn("could not suspend target (%d)\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = wait_event_interruptible_timeout(ar->event_queue,
|
||||
ar->is_target_paused == true,
|
||||
1 * HZ);
|
||||
if (ret < 0) {
|
||||
ath10k_warn("suspend interrupted (%d)\n", ret);
|
||||
goto resume;
|
||||
} else if (ret == 0) {
|
||||
ath10k_warn("suspend timed out - target pause event never came\n");
|
||||
goto resume;
|
||||
if (ret == -ETIMEDOUT)
|
||||
goto resume;
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_hif_suspend(ar);
|
||||
|
@ -3259,12 +3577,17 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
|
|||
goto resume;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto exit;
|
||||
resume:
|
||||
ret = ath10k_wmi_pdev_resume_target(ar);
|
||||
if (ret)
|
||||
ath10k_warn("could not resume target (%d)\n", ret);
|
||||
return 1;
|
||||
|
||||
ret = 1;
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_resume(struct ieee80211_hw *hw)
|
||||
|
@ -3272,19 +3595,26 @@ static int ath10k_resume(struct ieee80211_hw *hw)
|
|||
struct ath10k *ar = hw->priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
ret = ath10k_hif_resume(ar);
|
||||
if (ret) {
|
||||
ath10k_warn("could not resume hif (%d)\n", ret);
|
||||
return 1;
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_pdev_resume_target(ar);
|
||||
if (ret) {
|
||||
ath10k_warn("could not resume target (%d)\n", ret);
|
||||
return 1;
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3640,6 +3970,96 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
|
|||
return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss);
|
||||
}
|
||||
|
||||
static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
/* there's no need to do anything here. vif->csa_active is enough */
|
||||
return;
|
||||
}
|
||||
|
||||
static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
u32 changed)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
u32 bw, smps;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
|
||||
sta->addr, changed, sta->bandwidth, sta->rx_nss,
|
||||
sta->smps_mode);
|
||||
|
||||
if (changed & IEEE80211_RC_BW_CHANGED) {
|
||||
bw = WMI_PEER_CHWIDTH_20MHZ;
|
||||
|
||||
switch (sta->bandwidth) {
|
||||
case IEEE80211_STA_RX_BW_20:
|
||||
bw = WMI_PEER_CHWIDTH_20MHZ;
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_40:
|
||||
bw = WMI_PEER_CHWIDTH_40MHZ;
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_80:
|
||||
bw = WMI_PEER_CHWIDTH_80MHZ;
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
ath10k_warn("mac sta rc update for %pM: invalid bw %d\n",
|
||||
sta->addr, sta->bandwidth);
|
||||
bw = WMI_PEER_CHWIDTH_20MHZ;
|
||||
break;
|
||||
}
|
||||
|
||||
arsta->bw = bw;
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_RC_NSS_CHANGED)
|
||||
arsta->nss = sta->rx_nss;
|
||||
|
||||
if (changed & IEEE80211_RC_SMPS_CHANGED) {
|
||||
smps = WMI_PEER_SMPS_PS_NONE;
|
||||
|
||||
switch (sta->smps_mode) {
|
||||
case IEEE80211_SMPS_AUTOMATIC:
|
||||
case IEEE80211_SMPS_OFF:
|
||||
smps = WMI_PEER_SMPS_PS_NONE;
|
||||
break;
|
||||
case IEEE80211_SMPS_STATIC:
|
||||
smps = WMI_PEER_SMPS_STATIC;
|
||||
break;
|
||||
case IEEE80211_SMPS_DYNAMIC:
|
||||
smps = WMI_PEER_SMPS_DYNAMIC;
|
||||
break;
|
||||
case IEEE80211_SMPS_NUM_MODES:
|
||||
ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n",
|
||||
sta->addr, sta->smps_mode);
|
||||
smps = WMI_PEER_SMPS_PS_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
arsta->smps = smps;
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
|
||||
/* FIXME: Not implemented. Probably the only way to do it would
|
||||
* be to re-assoc the peer. */
|
||||
changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED;
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac sta rc update for %pM: changing supported rates not implemented\n",
|
||||
sta->addr);
|
||||
}
|
||||
|
||||
arsta->changed |= changed;
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ieee80211_queue_work(hw, &arsta->update_wk);
|
||||
}
|
||||
|
||||
static const struct ieee80211_ops ath10k_ops = {
|
||||
.tx = ath10k_tx,
|
||||
.start = ath10k_start,
|
||||
|
@ -3663,6 +4083,8 @@ static const struct ieee80211_ops ath10k_ops = {
|
|||
.restart_complete = ath10k_restart_complete,
|
||||
.get_survey = ath10k_get_survey,
|
||||
.set_bitrate_mask = ath10k_set_bitrate_mask,
|
||||
.channel_switch_beacon = ath10k_channel_switch_beacon,
|
||||
.sta_rc_update = ath10k_sta_rc_update,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ath10k_suspend,
|
||||
.resume = ath10k_resume,
|
||||
|
@ -4038,10 +4460,12 @@ int ath10k_mac_register(struct ath10k *ar)
|
|||
ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
|
||||
|
||||
ar->hw->vif_data_size = sizeof(struct ath10k_vif);
|
||||
ar->hw->sta_data_size = sizeof(struct ath10k_sta);
|
||||
|
||||
ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
|
||||
|
||||
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
|
||||
ar->hw->wiphy->max_remain_on_channel_duration = 5000;
|
||||
|
||||
ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||
|
|
|
@ -64,7 +64,8 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
|
|||
int num);
|
||||
static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
|
||||
static void ath10k_pci_stop_ce(struct ath10k *ar);
|
||||
static int ath10k_pci_device_reset(struct ath10k *ar);
|
||||
static int ath10k_pci_cold_reset(struct ath10k *ar);
|
||||
static int ath10k_pci_warm_reset(struct ath10k *ar);
|
||||
static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
|
||||
static int ath10k_pci_init_irq(struct ath10k *ar);
|
||||
static int ath10k_pci_deinit_irq(struct ath10k *ar);
|
||||
|
@ -833,9 +834,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
|
|||
ath10k_err("firmware crashed!\n");
|
||||
ath10k_err("hardware name %s version 0x%x\n",
|
||||
ar->hw_params.name, ar->target_version);
|
||||
ath10k_err("firmware version: %u.%u.%u.%u\n", ar->fw_version_major,
|
||||
ar->fw_version_minor, ar->fw_version_release,
|
||||
ar->fw_version_build);
|
||||
ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
|
||||
|
||||
host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
|
||||
ret = ath10k_pci_diag_read_mem(ar, host_addr,
|
||||
|
@ -1502,7 +1501,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
|
|||
* configuration during init. If ringbuffers are freed and the device
|
||||
* were to access them this could lead to memory corruption on the
|
||||
* host. */
|
||||
ath10k_pci_device_reset(ar);
|
||||
ath10k_pci_warm_reset(ar);
|
||||
|
||||
ar_pci->started = 0;
|
||||
}
|
||||
|
@ -1993,7 +1992,94 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
|
|||
ath10k_pci_sleep(ar);
|
||||
}
|
||||
|
||||
static int ath10k_pci_hif_power_up(struct ath10k *ar)
|
||||
static int ath10k_pci_warm_reset(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret = 0;
|
||||
u32 val;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot performing warm chip reset\n");
|
||||
|
||||
ret = ath10k_do_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_err("failed to wake up target: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* debug */
|
||||
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
|
||||
PCIE_INTR_CAUSE_ADDRESS);
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
|
||||
|
||||
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
|
||||
CPU_INTR_ADDRESS);
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
|
||||
val);
|
||||
|
||||
/* disable pending irqs */
|
||||
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
|
||||
PCIE_INTR_ENABLE_ADDRESS, 0);
|
||||
|
||||
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
|
||||
PCIE_INTR_CLR_ADDRESS, ~0);
|
||||
|
||||
msleep(100);
|
||||
|
||||
/* clear fw indicator */
|
||||
ath10k_pci_write32(ar, ar_pci->fw_indicator_address, 0);
|
||||
|
||||
/* clear target LF timer interrupts */
|
||||
val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
|
||||
SOC_LF_TIMER_CONTROL0_ADDRESS);
|
||||
ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS +
|
||||
SOC_LF_TIMER_CONTROL0_ADDRESS,
|
||||
val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK);
|
||||
|
||||
/* reset CE */
|
||||
val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
|
||||
SOC_RESET_CONTROL_ADDRESS);
|
||||
ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
|
||||
val | SOC_RESET_CONTROL_CE_RST_MASK);
|
||||
val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
|
||||
SOC_RESET_CONTROL_ADDRESS);
|
||||
msleep(10);
|
||||
|
||||
/* unreset CE */
|
||||
ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
|
||||
val & ~SOC_RESET_CONTROL_CE_RST_MASK);
|
||||
val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
|
||||
SOC_RESET_CONTROL_ADDRESS);
|
||||
msleep(10);
|
||||
|
||||
/* debug */
|
||||
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
|
||||
PCIE_INTR_CAUSE_ADDRESS);
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
|
||||
|
||||
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
|
||||
CPU_INTR_ADDRESS);
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
|
||||
val);
|
||||
|
||||
/* CPU warm reset */
|
||||
val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
|
||||
SOC_RESET_CONTROL_ADDRESS);
|
||||
ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
|
||||
val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK);
|
||||
|
||||
val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
|
||||
SOC_RESET_CONTROL_ADDRESS);
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val);
|
||||
|
||||
msleep(100);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n");
|
||||
|
||||
ath10k_do_pci_sleep(ar);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
const char *irq_mode;
|
||||
|
@ -2009,7 +2095,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
|
|||
* is in an unexpected state. We try to catch that here in order to
|
||||
* reset the Target and retry the probe.
|
||||
*/
|
||||
ret = ath10k_pci_device_reset(ar);
|
||||
if (cold_reset)
|
||||
ret = ath10k_pci_cold_reset(ar);
|
||||
else
|
||||
ret = ath10k_pci_warm_reset(ar);
|
||||
|
||||
if (ret) {
|
||||
ath10k_err("failed to reset target: %d\n", ret);
|
||||
goto err;
|
||||
|
@ -2079,7 +2169,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
|
|||
ath10k_pci_deinit_irq(ar);
|
||||
err_ce:
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
ath10k_pci_device_reset(ar);
|
||||
ath10k_pci_warm_reset(ar);
|
||||
err_ps:
|
||||
if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
|
||||
ath10k_do_pci_sleep(ar);
|
||||
|
@ -2087,6 +2177,34 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_pci_hif_power_up(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Hardware CUS232 version 2 has some issues with cold reset and the
|
||||
* preferred (and safer) way to perform a device reset is through a
|
||||
* warm reset.
|
||||
*
|
||||
* Warm reset doesn't always work though (notably after a firmware
|
||||
* crash) so fall back to cold reset if necessary.
|
||||
*/
|
||||
ret = __ath10k_pci_hif_power_up(ar, false);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to power up target using warm reset (%d), trying cold reset\n",
|
||||
ret);
|
||||
|
||||
ret = __ath10k_pci_hif_power_up(ar, true);
|
||||
if (ret) {
|
||||
ath10k_err("failed to power up target using cold reset too (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_pci_hif_power_down(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
@ -2094,7 +2212,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
|
|||
ath10k_pci_free_early_irq(ar);
|
||||
ath10k_pci_kill_tasklet(ar);
|
||||
ath10k_pci_deinit_irq(ar);
|
||||
ath10k_pci_device_reset(ar);
|
||||
ath10k_pci_warm_reset(ar);
|
||||
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
|
||||
|
@ -2411,11 +2529,10 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
|
|||
/* Try MSI-X */
|
||||
if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
|
||||
ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
|
||||
ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
|
||||
ar_pci->num_msi_intrs);
|
||||
if (ret > 0)
|
||||
pci_disable_msi(ar_pci->pdev);
|
||||
return 0;
|
||||
|
||||
/* fall-through */
|
||||
}
|
||||
|
@ -2482,6 +2599,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
|
|||
case MSI_NUM_REQUEST:
|
||||
pci_disable_msi(ar_pci->pdev);
|
||||
return 0;
|
||||
default:
|
||||
pci_disable_msi(ar_pci->pdev);
|
||||
}
|
||||
|
||||
ath10k_warn("unknown irq configuration upon deinit\n");
|
||||
|
@ -2523,7 +2642,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_pci_device_reset(struct ath10k *ar)
|
||||
static int ath10k_pci_cold_reset(struct ath10k *ar)
|
||||
{
|
||||
int i, ret;
|
||||
u32 val;
|
||||
|
|
|
@ -259,7 +259,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
|
|||
status->freq = ch->center_freq;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_DATA,
|
||||
"rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u\n",
|
||||
"rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i\n",
|
||||
info->skb,
|
||||
info->skb->len,
|
||||
status->flag == 0 ? "legacy" : "",
|
||||
|
@ -271,7 +271,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
|
|||
status->rate_idx,
|
||||
status->vht_nss,
|
||||
status->freq,
|
||||
status->band);
|
||||
status->band, status->flag, info->fcs_err);
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
|
||||
info->skb->data, info->skb->len);
|
||||
|
||||
|
|
|
@ -213,7 +213,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
|
|||
.p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE,
|
||||
.p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE,
|
||||
.p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.ap_ps_peer_param_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.ap_ps_peer_param_cmdid = WMI_10X_AP_PS_PEER_PARAM_CMDID,
|
||||
.ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID,
|
||||
.wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID,
|
||||
|
@ -420,7 +420,6 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = {
|
|||
.bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
|
||||
.pmf_qos = WMI_PDEV_PARAM_PMF_QOS,
|
||||
.arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
|
||||
.arpdhcp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
|
||||
.dcs = WMI_PDEV_PARAM_DCS,
|
||||
.ani_enable = WMI_PDEV_PARAM_ANI_ENABLE,
|
||||
.ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD,
|
||||
|
@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
|
|||
.bcnflt_stats_update_period =
|
||||
WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
|
||||
.pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS,
|
||||
.arp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
|
||||
.arpdhcp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
|
||||
.arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
|
||||
.dcs = WMI_10X_PDEV_PARAM_DCS,
|
||||
.ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE,
|
||||
.ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD,
|
||||
|
@ -561,7 +559,6 @@ static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
|
|||
|
||||
static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
|
||||
{
|
||||
struct wmi_bcn_tx_arg arg = {0};
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&arvif->ar->data_lock);
|
||||
|
@ -569,18 +566,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
|
|||
if (arvif->beacon == NULL)
|
||||
return;
|
||||
|
||||
arg.vdev_id = arvif->vdev_id;
|
||||
arg.tx_rate = 0;
|
||||
arg.tx_power = 0;
|
||||
arg.bcn = arvif->beacon->data;
|
||||
arg.bcn_len = arvif->beacon->len;
|
||||
if (arvif->beacon_sent)
|
||||
return;
|
||||
|
||||
ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg);
|
||||
ret = ath10k_wmi_beacon_send_ref_nowait(arvif);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
dev_kfree_skb_any(arvif->beacon);
|
||||
arvif->beacon = NULL;
|
||||
/* We need to retain the arvif->beacon reference for DMA unmapping and
|
||||
* freeing the skbuff later. */
|
||||
arvif->beacon_sent = true;
|
||||
}
|
||||
|
||||
static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
|
||||
|
@ -1116,7 +1111,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
|
|||
static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n");
|
||||
struct wmi_peer_sta_kickout_event *ev;
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
ev = (struct wmi_peer_sta_kickout_event *)skb->data;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
|
||||
ev->peer_macaddr.addr);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
|
||||
if (!sta) {
|
||||
ath10k_warn("Spurious quick kickout for STA %pM\n",
|
||||
ev->peer_macaddr.addr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ieee80211_report_low_ack(sta, 10);
|
||||
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1217,6 +1232,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
|
|||
tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);
|
||||
memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
|
||||
|
||||
if (tim->dtim_count == 0) {
|
||||
ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true;
|
||||
|
||||
if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1)
|
||||
ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
|
||||
tim->dtim_count, tim->dtim_period,
|
||||
tim->bitmap_ctrl, pvm_len);
|
||||
|
@ -1385,6 +1407,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* There are no completions for beacons so wait for next SWBA
|
||||
* before telling mac80211 to decrement CSA counter
|
||||
*
|
||||
* Once CSA counter is completed stop sending beacons until
|
||||
* actual channel switch is done */
|
||||
if (arvif->vif->csa_active &&
|
||||
ieee80211_csa_is_complete(arvif->vif)) {
|
||||
ieee80211_csa_finish(arvif->vif);
|
||||
continue;
|
||||
}
|
||||
|
||||
bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
|
||||
if (!bcn) {
|
||||
ath10k_warn("could not get mac80211 beacon\n");
|
||||
|
@ -1396,13 +1429,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
|
|||
ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
if (arvif->beacon) {
|
||||
ath10k_warn("SWBA overrun on vdev %d\n",
|
||||
arvif->vdev_id);
|
||||
if (!arvif->beacon_sent)
|
||||
ath10k_warn("SWBA overrun on vdev %d\n",
|
||||
arvif->vdev_id);
|
||||
|
||||
ath10k_skb_unmap(ar->dev, arvif->beacon);
|
||||
dev_kfree_skb_any(arvif->beacon);
|
||||
}
|
||||
|
||||
ath10k_skb_map(ar->dev, bcn);
|
||||
|
||||
arvif->beacon = bcn;
|
||||
arvif->beacon_sent = false;
|
||||
|
||||
ath10k_wmi_tx_beacon_nowait(arvif);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
@ -2031,11 +2071,11 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_WMI,
|
||||
"wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n",
|
||||
"wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
|
||||
__le32_to_cpu(ev->sw_version),
|
||||
__le32_to_cpu(ev->abi_version),
|
||||
ev->mac_addr.addr,
|
||||
__le32_to_cpu(ev->status));
|
||||
__le32_to_cpu(ev->status), skb->len, sizeof(*ev));
|
||||
|
||||
complete(&ar->wmi.unified_ready);
|
||||
return 0;
|
||||
|
@ -2403,7 +2443,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
|
|||
ar->wmi.cmd->pdev_set_channel_cmdid);
|
||||
}
|
||||
|
||||
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar)
|
||||
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
|
||||
{
|
||||
struct wmi_pdev_suspend_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
|
@ -2413,7 +2453,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar)
|
|||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_pdev_suspend_cmd *)skb->data;
|
||||
cmd->suspend_opt = WMI_PDEV_SUSPEND;
|
||||
cmd->suspend_opt = __cpu_to_le32(suspend_opt);
|
||||
|
||||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
|
||||
}
|
||||
|
@ -3411,25 +3451,41 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
|
|||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
|
||||
}
|
||||
|
||||
int ath10k_wmi_beacon_send_nowait(struct ath10k *ar,
|
||||
const struct wmi_bcn_tx_arg *arg)
|
||||
/* This function assumes the beacon is already DMA mapped */
|
||||
int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
|
||||
{
|
||||
struct wmi_bcn_tx_cmd *cmd;
|
||||
struct wmi_bcn_tx_ref_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff *beacon = arvif->beacon;
|
||||
struct ath10k *ar = arvif->ar;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int ret;
|
||||
u16 fc;
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len);
|
||||
skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_bcn_tx_cmd *)skb->data;
|
||||
cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id);
|
||||
cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate);
|
||||
cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power);
|
||||
cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len);
|
||||
memcpy(cmd->bcn, arg->bcn, arg->bcn_len);
|
||||
hdr = (struct ieee80211_hdr *)beacon->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
|
||||
cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data;
|
||||
cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
|
||||
cmd->data_len = __cpu_to_le32(beacon->len);
|
||||
cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr);
|
||||
cmd->msdu_id = 0;
|
||||
cmd->frame_control = __cpu_to_le32(fc);
|
||||
cmd->flags = 0;
|
||||
|
||||
if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
|
||||
cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
|
||||
|
||||
if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab)
|
||||
cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
|
||||
|
||||
ret = ath10k_wmi_cmd_send_nowait(ar, skb,
|
||||
ar->wmi.cmd->pdev_send_bcn_cmdid);
|
||||
|
||||
ret = ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid);
|
||||
if (ret)
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
|
|
|
@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map {
|
|||
u32 bcnflt_stats_update_period;
|
||||
u32 pmf_qos;
|
||||
u32 arp_ac_override;
|
||||
u32 arpdhcp_ac_override;
|
||||
u32 dcs;
|
||||
u32 ani_enable;
|
||||
u32 ani_poll_period;
|
||||
|
@ -3403,6 +3402,24 @@ struct wmi_bcn_tx_arg {
|
|||
const void *bcn;
|
||||
};
|
||||
|
||||
enum wmi_bcn_tx_ref_flags {
|
||||
WMI_BCN_TX_REF_FLAG_DTIM_ZERO = 0x1,
|
||||
WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
|
||||
};
|
||||
|
||||
struct wmi_bcn_tx_ref_cmd {
|
||||
__le32 vdev_id;
|
||||
__le32 data_len;
|
||||
/* physical address of the frame - dma pointer */
|
||||
__le32 data_ptr;
|
||||
/* id for host to track */
|
||||
__le32 msdu_id;
|
||||
/* frame ctrl to setup PPDU desc */
|
||||
__le32 frame_control;
|
||||
/* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
|
||||
__le32 flags;
|
||||
} __packed;
|
||||
|
||||
/* Beacon filter */
|
||||
#define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */
|
||||
#define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */
|
||||
|
@ -3859,6 +3876,12 @@ enum wmi_peer_smps_state {
|
|||
WMI_PEER_SMPS_DYNAMIC = 0x2
|
||||
};
|
||||
|
||||
enum wmi_peer_chwidth {
|
||||
WMI_PEER_CHWIDTH_20MHZ = 0,
|
||||
WMI_PEER_CHWIDTH_40MHZ = 1,
|
||||
WMI_PEER_CHWIDTH_80MHZ = 2,
|
||||
};
|
||||
|
||||
enum wmi_peer_param {
|
||||
WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */
|
||||
WMI_PEER_AMPDU = 0x2,
|
||||
|
@ -4039,6 +4062,10 @@ struct wmi_chan_info_event {
|
|||
__le32 cycle_count;
|
||||
} __packed;
|
||||
|
||||
struct wmi_peer_sta_kickout_event {
|
||||
struct wmi_mac_addr peer_macaddr;
|
||||
} __packed;
|
||||
|
||||
#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
|
||||
|
||||
/* FIXME: empirically extrapolated */
|
||||
|
@ -4172,7 +4199,7 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
|
|||
int ath10k_wmi_connect_htc_service(struct ath10k *ar);
|
||||
int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
|
||||
const struct wmi_channel_arg *);
|
||||
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar);
|
||||
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
|
||||
int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
|
||||
int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
|
||||
u16 rd5g, u16 ctl2g, u16 ctl5g);
|
||||
|
@ -4219,8 +4246,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
|
|||
enum wmi_ap_ps_peer_param param_id, u32 value);
|
||||
int ath10k_wmi_scan_chan_list(struct ath10k *ar,
|
||||
const struct wmi_scan_chan_list_arg *arg);
|
||||
int ath10k_wmi_beacon_send_nowait(struct ath10k *ar,
|
||||
const struct wmi_bcn_tx_arg *arg);
|
||||
int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
|
||||
int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
|
||||
const struct wmi_pdev_set_wmm_params_arg *arg);
|
||||
int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
|
||||
|
|
|
@ -681,6 +681,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
|
|||
survey->channel = conf->chandef.chan;
|
||||
survey->noise = ah->ah_noise_floor;
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM |
|
||||
SURVEY_INFO_IN_USE |
|
||||
SURVEY_INFO_CHANNEL_TIME |
|
||||
SURVEY_INFO_CHANNEL_TIME_BUSY |
|
||||
SURVEY_INFO_CHANNEL_TIME_RX |
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
/* constants */
|
||||
#define TX_URB_COUNT 32
|
||||
#define RX_URB_COUNT 32
|
||||
#define ATH6KL_USB_RX_BUFFER_SIZE 1700
|
||||
#define ATH6KL_USB_RX_BUFFER_SIZE 4096
|
||||
|
||||
/* tx/rx pipes for usb */
|
||||
enum ATH6KL_USB_PIPE_ID {
|
||||
|
@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb)
|
|||
* ATH6KL_USB_RX_BUFFER_SIZE);
|
||||
*/
|
||||
|
||||
ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh =
|
||||
ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2;
|
||||
ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 1;
|
||||
|
||||
ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA],
|
||||
ATH6KL_USB_RX_BUFFER_SIZE);
|
||||
}
|
||||
|
|
|
@ -914,7 +914,7 @@ ath6kl_get_regpair(u16 regdmn)
|
|||
return NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
|
||||
if (regDomainPairs[i].regDmnEnum == regdmn)
|
||||
if (regDomainPairs[i].reg_domain == regdmn)
|
||||
return ®DomainPairs[i];
|
||||
}
|
||||
|
||||
|
@ -954,7 +954,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
|
|||
country = ath6kl_regd_find_country_by_rd((u16) reg_code);
|
||||
if (regpair)
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
|
||||
regpair->regDmnEnum);
|
||||
regpair->reg_domain);
|
||||
else
|
||||
ath6kl_warn("Regpair not found reg_code 0x%0x\n",
|
||||
reg_code);
|
||||
|
|
|
@ -51,7 +51,8 @@ ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
|
|||
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
|
||||
|
||||
obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o
|
||||
ath9k_common-y:= common.o
|
||||
ath9k_common-y:= common.o \
|
||||
common-init.o
|
||||
|
||||
ath9k_htc-y += htc_hst.o \
|
||||
hif_usb.o \
|
||||
|
|
|
@ -176,16 +176,26 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
|
|||
if (ah->opmode == NL80211_IFTYPE_STATION &&
|
||||
BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
|
||||
weak_sig = true;
|
||||
|
||||
/*
|
||||
* OFDM Weak signal detection is always enabled for AP mode.
|
||||
* Newer chipsets are better at dealing with high PHY error counts -
|
||||
* keep weak signal detection enabled when no RSSI threshold is
|
||||
* available to determine if it is needed (mode != STA)
|
||||
*/
|
||||
if (ah->opmode != NL80211_IFTYPE_AP &&
|
||||
aniState->ofdmWeakSigDetect != weak_sig) {
|
||||
ath9k_hw_ani_control(ah,
|
||||
ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
|
||||
entry_ofdm->ofdm_weak_signal_on);
|
||||
}
|
||||
else if (AR_SREV_9300_20_OR_LATER(ah) &&
|
||||
ah->opmode != NL80211_IFTYPE_STATION)
|
||||
weak_sig = true;
|
||||
|
||||
/* Older chipsets are more sensitive to high PHY error counts */
|
||||
else if (!AR_SREV_9300_20_OR_LATER(ah) &&
|
||||
aniState->ofdmNoiseImmunityLevel >= 8)
|
||||
weak_sig = false;
|
||||
|
||||
if (aniState->ofdmWeakSigDetect != weak_sig)
|
||||
ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
|
||||
weak_sig);
|
||||
|
||||
if (!AR_SREV_9300_20_OR_LATER(ah))
|
||||
return;
|
||||
|
||||
if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
|
||||
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
|
||||
|
@ -483,10 +493,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
|
|||
|
||||
ath_dbg(common, ANI, "Initialize ANI\n");
|
||||
|
||||
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
|
||||
ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
|
||||
ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
|
||||
ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
|
||||
if (AR_SREV_9300_20_OR_LATER(ah)) {
|
||||
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
|
||||
ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
|
||||
ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
|
||||
ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
|
||||
} else {
|
||||
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
|
||||
ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
|
||||
ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
|
||||
ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
|
||||
}
|
||||
|
||||
ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
|
||||
ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
|
||||
|
|
|
@ -22,12 +22,16 @@
|
|||
/* units are errors per second */
|
||||
#define ATH9K_ANI_OFDM_TRIG_HIGH 3500
|
||||
#define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000
|
||||
#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500
|
||||
|
||||
#define ATH9K_ANI_OFDM_TRIG_LOW 400
|
||||
#define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900
|
||||
#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200
|
||||
|
||||
#define ATH9K_ANI_CCK_TRIG_HIGH 600
|
||||
#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200
|
||||
#define ATH9K_ANI_CCK_TRIG_LOW 300
|
||||
#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100
|
||||
|
||||
#define ATH9K_ANI_SPUR_IMMUNE_LVL 3
|
||||
#define ATH9K_ANI_FIRSTEP_LVL 2
|
||||
|
|
|
@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah,
|
|||
|
||||
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
|
||||
rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
|
||||
if (IS_CHAN_QUARTER_RATE(chan))
|
||||
rfMode |= AR_PHY_MODE_QUARTER;
|
||||
if (IS_CHAN_HALF_RATE(chan))
|
||||
rfMode |= AR_PHY_MODE_HALF;
|
||||
|
||||
if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
|
||||
REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
|
||||
|
|
|
@ -410,7 +410,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
|
|||
|
||||
struct ath_beacon_config {
|
||||
int beacon_interval;
|
||||
u16 listen_interval;
|
||||
u16 dtim_period;
|
||||
u16 bmiss_timeout;
|
||||
u8 dtim_count;
|
||||
|
@ -753,7 +752,6 @@ struct ath_softc {
|
|||
struct ath_rx rx;
|
||||
struct ath_tx tx;
|
||||
struct ath_beacon beacon;
|
||||
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
bool led_registered;
|
||||
|
|
|
@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|||
u8 chainmask = ah->txchainmask;
|
||||
u8 rate = 0;
|
||||
|
||||
sband = &sc->sbands[common->hw->conf.chandef.chan->band];
|
||||
sband = &common->sbands[common->hw->conf.chandef.chan->band];
|
||||
rate = sband->bitrates[rateidx].hw_value;
|
||||
if (vif->bss_conf.use_short_preamble)
|
||||
rate |= sband->bitrates[rateidx].hw_value_short;
|
||||
|
@ -519,7 +519,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
|
|||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_beacon_state bs;
|
||||
int dtim_intval, sleepduration;
|
||||
int dtim_intval;
|
||||
u32 nexttbtt = 0, intval;
|
||||
u64 tsf;
|
||||
|
||||
|
@ -538,7 +538,6 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
|
|||
* last beacon we received (which may be none).
|
||||
*/
|
||||
dtim_intval = intval * conf->dtim_period;
|
||||
sleepduration = conf->listen_interval * intval;
|
||||
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current
|
||||
|
@ -560,16 +559,11 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
|
|||
* need calculate based on the beacon interval. Note that we clamp the
|
||||
* result to at most 15 beacons.
|
||||
*/
|
||||
if (sleepduration > intval) {
|
||||
bs.bs_bmissthreshold = conf->listen_interval *
|
||||
ATH_DEFAULT_BMISS_LIMIT / 2;
|
||||
} else {
|
||||
bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
|
||||
if (bs.bs_bmissthreshold > 15)
|
||||
bs.bs_bmissthreshold = 15;
|
||||
else if (bs.bs_bmissthreshold <= 0)
|
||||
bs.bs_bmissthreshold = 1;
|
||||
}
|
||||
bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
|
||||
if (bs.bs_bmissthreshold > 15)
|
||||
bs.bs_bmissthreshold = 15;
|
||||
else if (bs.bs_bmissthreshold <= 0)
|
||||
bs.bs_bmissthreshold = 1;
|
||||
|
||||
/*
|
||||
* Calculate sleep duration. The configuration is given in ms.
|
||||
|
@ -581,7 +575,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
|
|||
*/
|
||||
|
||||
bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
|
||||
sleepduration));
|
||||
intval));
|
||||
if (bs.bs_sleepduration > bs.bs_dtimperiod)
|
||||
bs.bs_sleepduration = bs.bs_dtimperiod;
|
||||
|
||||
|
@ -677,7 +671,6 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
|
|||
|
||||
cur_conf->beacon_interval = bss_conf->beacon_int;
|
||||
cur_conf->dtim_period = bss_conf->dtim_period;
|
||||
cur_conf->listen_interval = 1;
|
||||
cur_conf->dtim_count = 1;
|
||||
cur_conf->ibss_creator = bss_conf->ibss_creator;
|
||||
cur_conf->bmiss_timeout =
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2011 Atheros Communications Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* We use the hw_value as an index into our private channel structure */
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define CHAN2G(_freq, _idx) { \
|
||||
.band = IEEE80211_BAND_2GHZ, \
|
||||
.center_freq = (_freq), \
|
||||
.hw_value = (_idx), \
|
||||
.max_power = 20, \
|
||||
}
|
||||
|
||||
#define CHAN5G(_freq, _idx) { \
|
||||
.band = IEEE80211_BAND_5GHZ, \
|
||||
.center_freq = (_freq), \
|
||||
.hw_value = (_idx), \
|
||||
.max_power = 20, \
|
||||
}
|
||||
|
||||
/* Some 2 GHz radios are actually tunable on 2312-2732
|
||||
* on 5 MHz steps, we support the channels which we know
|
||||
* we have calibration data for all cards though to make
|
||||
* this static */
|
||||
static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
|
||||
CHAN2G(2412, 0), /* Channel 1 */
|
||||
CHAN2G(2417, 1), /* Channel 2 */
|
||||
CHAN2G(2422, 2), /* Channel 3 */
|
||||
CHAN2G(2427, 3), /* Channel 4 */
|
||||
CHAN2G(2432, 4), /* Channel 5 */
|
||||
CHAN2G(2437, 5), /* Channel 6 */
|
||||
CHAN2G(2442, 6), /* Channel 7 */
|
||||
CHAN2G(2447, 7), /* Channel 8 */
|
||||
CHAN2G(2452, 8), /* Channel 9 */
|
||||
CHAN2G(2457, 9), /* Channel 10 */
|
||||
CHAN2G(2462, 10), /* Channel 11 */
|
||||
CHAN2G(2467, 11), /* Channel 12 */
|
||||
CHAN2G(2472, 12), /* Channel 13 */
|
||||
CHAN2G(2484, 13), /* Channel 14 */
|
||||
};
|
||||
|
||||
/* Some 5 GHz radios are actually tunable on XXXX-YYYY
|
||||
* on 5 MHz steps, we support the channels which we know
|
||||
* we have calibration data for all cards though to make
|
||||
* this static */
|
||||
static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
|
||||
/* _We_ call this UNII 1 */
|
||||
CHAN5G(5180, 14), /* Channel 36 */
|
||||
CHAN5G(5200, 15), /* Channel 40 */
|
||||
CHAN5G(5220, 16), /* Channel 44 */
|
||||
CHAN5G(5240, 17), /* Channel 48 */
|
||||
/* _We_ call this UNII 2 */
|
||||
CHAN5G(5260, 18), /* Channel 52 */
|
||||
CHAN5G(5280, 19), /* Channel 56 */
|
||||
CHAN5G(5300, 20), /* Channel 60 */
|
||||
CHAN5G(5320, 21), /* Channel 64 */
|
||||
/* _We_ call this "Middle band" */
|
||||
CHAN5G(5500, 22), /* Channel 100 */
|
||||
CHAN5G(5520, 23), /* Channel 104 */
|
||||
CHAN5G(5540, 24), /* Channel 108 */
|
||||
CHAN5G(5560, 25), /* Channel 112 */
|
||||
CHAN5G(5580, 26), /* Channel 116 */
|
||||
CHAN5G(5600, 27), /* Channel 120 */
|
||||
CHAN5G(5620, 28), /* Channel 124 */
|
||||
CHAN5G(5640, 29), /* Channel 128 */
|
||||
CHAN5G(5660, 30), /* Channel 132 */
|
||||
CHAN5G(5680, 31), /* Channel 136 */
|
||||
CHAN5G(5700, 32), /* Channel 140 */
|
||||
/* _We_ call this UNII 3 */
|
||||
CHAN5G(5745, 33), /* Channel 149 */
|
||||
CHAN5G(5765, 34), /* Channel 153 */
|
||||
CHAN5G(5785, 35), /* Channel 157 */
|
||||
CHAN5G(5805, 36), /* Channel 161 */
|
||||
CHAN5G(5825, 37), /* Channel 165 */
|
||||
};
|
||||
|
||||
/* Atheros hardware rate code addition for short premble */
|
||||
#define SHPCHECK(__hw_rate, __flags) \
|
||||
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
|
||||
|
||||
#define RATE(_bitrate, _hw_rate, _flags) { \
|
||||
.bitrate = (_bitrate), \
|
||||
.flags = (_flags), \
|
||||
.hw_value = (_hw_rate), \
|
||||
.hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
|
||||
}
|
||||
|
||||
static struct ieee80211_rate ath9k_legacy_rates[] = {
|
||||
RATE(10, 0x1b, 0),
|
||||
RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
|
||||
RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
|
||||
RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
|
||||
RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
};
|
||||
|
||||
int ath9k_cmn_init_channels_rates(struct ath_common *common)
|
||||
{
|
||||
struct ath_hw *ah = (struct ath_hw *)common->ah;
|
||||
void *channels;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
|
||||
ARRAY_SIZE(ath9k_5ghz_chantable) !=
|
||||
ATH9K_NUM_CHANNELS);
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
|
||||
channels = devm_kzalloc(ah->dev,
|
||||
sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(channels, ath9k_2ghz_chantable,
|
||||
sizeof(ath9k_2ghz_chantable));
|
||||
common->sbands[IEEE80211_BAND_2GHZ].channels = channels;
|
||||
common->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
|
||||
common->sbands[IEEE80211_BAND_2GHZ].n_channels =
|
||||
ARRAY_SIZE(ath9k_2ghz_chantable);
|
||||
common->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
|
||||
common->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
|
||||
ARRAY_SIZE(ath9k_legacy_rates);
|
||||
}
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
|
||||
channels = devm_kzalloc(ah->dev,
|
||||
sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(channels, ath9k_5ghz_chantable,
|
||||
sizeof(ath9k_5ghz_chantable));
|
||||
common->sbands[IEEE80211_BAND_5GHZ].channels = channels;
|
||||
common->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
|
||||
common->sbands[IEEE80211_BAND_5GHZ].n_channels =
|
||||
ARRAY_SIZE(ath9k_5ghz_chantable);
|
||||
common->sbands[IEEE80211_BAND_5GHZ].bitrates =
|
||||
ath9k_legacy_rates + 4;
|
||||
common->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
|
||||
ARRAY_SIZE(ath9k_legacy_rates) - 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_cmn_init_channels_rates);
|
||||
|
||||
void ath9k_cmn_setup_ht_cap(struct ath_hw *ah,
|
||||
struct ieee80211_sta_ht_cap *ht_info)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u8 tx_streams, rx_streams;
|
||||
int i, max_streams;
|
||||
|
||||
ht_info->ht_supported = true;
|
||||
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
||||
IEEE80211_HT_CAP_SM_PS |
|
||||
IEEE80211_HT_CAP_SGI_40 |
|
||||
IEEE80211_HT_CAP_DSSSCCK40;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
||||
|
||||
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
||||
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
|
||||
|
||||
if (AR_SREV_9271(ah) || AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah))
|
||||
max_streams = 1;
|
||||
else if (AR_SREV_9462(ah))
|
||||
max_streams = 2;
|
||||
else if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
max_streams = 3;
|
||||
else
|
||||
max_streams = 2;
|
||||
|
||||
if (AR_SREV_9280_20_OR_LATER(ah)) {
|
||||
if (max_streams >= 2)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
|
||||
ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
|
||||
}
|
||||
|
||||
/* set up supported mcs set */
|
||||
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
|
||||
tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams);
|
||||
rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams);
|
||||
|
||||
ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
|
||||
tx_streams, rx_streams);
|
||||
|
||||
if (tx_streams != rx_streams) {
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
|
||||
ht_info->mcs.tx_params |= ((tx_streams - 1) <<
|
||||
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
|
||||
}
|
||||
|
||||
for (i = 0; i < rx_streams; i++)
|
||||
ht_info->mcs.rx_mask[i] = 0xff;
|
||||
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap);
|
||||
|
||||
void ath9k_cmn_reload_chainmask(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT))
|
||||
return;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
|
||||
ath9k_cmn_setup_ht_cap(ah,
|
||||
&common->sbands[IEEE80211_BAND_2GHZ].ht_cap);
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
|
||||
ath9k_cmn_setup_ht_cap(ah,
|
||||
&common->sbands[IEEE80211_BAND_5GHZ].ht_cap);
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_cmn_reload_chainmask);
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2009-2011 Atheros Communications Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
int ath9k_cmn_init_channels_rates(struct ath_common *common);
|
||||
void ath9k_cmn_setup_ht_cap(struct ath_hw *ah,
|
||||
struct ieee80211_sta_ht_cap *ht_info);
|
||||
void ath9k_cmn_reload_chainmask(struct ath_hw *ah);
|
|
@ -21,6 +21,8 @@
|
|||
#include "hw.h"
|
||||
#include "hw-ops.h"
|
||||
|
||||
#include "common-init.h"
|
||||
|
||||
/* Common header for Atheros 802.11n base driver cores */
|
||||
|
||||
#define WME_BA_BMP_SIZE 64
|
||||
|
|
|
@ -135,7 +135,8 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,
|
|||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
unsigned int len = 0, size = 1024;
|
||||
unsigned int len = 0;
|
||||
const unsigned int size = 1024;
|
||||
ssize_t retval = 0;
|
||||
char *buf;
|
||||
|
||||
|
@ -307,13 +308,13 @@ static ssize_t read_file_antenna_diversity(struct file *file,
|
|||
struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];
|
||||
struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
|
||||
struct ath_hw_antcomb_conf div_ant_conf;
|
||||
unsigned int len = 0, size = 1024;
|
||||
unsigned int len = 0;
|
||||
const unsigned int size = 1024;
|
||||
ssize_t retval = 0;
|
||||
char *buf;
|
||||
char *lna_conf_str[4] = {"LNA1_MINUS_LNA2",
|
||||
"LNA2",
|
||||
"LNA1",
|
||||
"LNA1_PLUS_LNA2"};
|
||||
static const char *lna_conf_str[4] = {
|
||||
"LNA1_MINUS_LNA2", "LNA2", "LNA1", "LNA1_PLUS_LNA2"
|
||||
};
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
|
@ -716,10 +717,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf,
|
|||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_txq *txq;
|
||||
char *buf;
|
||||
unsigned int len = 0, size = 1024;
|
||||
unsigned int len = 0;
|
||||
const unsigned int size = 1024;
|
||||
ssize_t retval = 0;
|
||||
int i;
|
||||
char *qname[4] = {"VO", "VI", "BE", "BK"};
|
||||
static const char *qname[4] = {
|
||||
"VO", "VI", "BE", "BK"
|
||||
};
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
|
@ -865,6 +869,12 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
|
|||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
"%17s: %2d\n", "PLL RX Hang",
|
||||
sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
|
||||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
"%17s: %2d\n", "MAC Hang",
|
||||
sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
|
||||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
"%17s: %2d\n", "Stuck Beacon",
|
||||
sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
|
||||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||||
"%17s: %2d\n", "MCI Reset",
|
||||
sc->debug.stats.reset[RESET_TYPE_MCI]);
|
||||
|
|
|
@ -487,7 +487,6 @@ struct ath9k_htc_priv {
|
|||
unsigned long op_flags;
|
||||
|
||||
struct ath9k_hw_cal_data caldata;
|
||||
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
|
||||
|
||||
spinlock_t beacon_lock;
|
||||
struct htc_beacon_config cur_beacon_conf;
|
||||
|
|
|
@ -69,7 +69,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
|
|||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
struct ath9k_beacon_state bs;
|
||||
enum ath9k_int imask = 0;
|
||||
int dtimperiod, dtimcount, sleepduration;
|
||||
int dtimperiod, dtimcount;
|
||||
int bmiss_timeout;
|
||||
u32 nexttbtt = 0, intval, tsftu;
|
||||
__be32 htc_imask = 0;
|
||||
|
@ -94,10 +94,6 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
|
|||
if (dtimcount >= dtimperiod) /* NB: sanity check */
|
||||
dtimcount = 0;
|
||||
|
||||
sleepduration = intval;
|
||||
if (sleepduration <= 0)
|
||||
sleepduration = intval;
|
||||
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current
|
||||
* TSF and calculate dtim state for the result.
|
||||
|
@ -128,15 +124,11 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
|
|||
* need calculate based on the beacon interval. Note that we clamp the
|
||||
* result to at most 15 beacons.
|
||||
*/
|
||||
if (sleepduration > intval) {
|
||||
bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2;
|
||||
} else {
|
||||
bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
|
||||
if (bs.bs_bmissthreshold > 15)
|
||||
bs.bs_bmissthreshold = 15;
|
||||
else if (bs.bs_bmissthreshold <= 0)
|
||||
bs.bs_bmissthreshold = 1;
|
||||
}
|
||||
bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
|
||||
if (bs.bs_bmissthreshold > 15)
|
||||
bs.bs_bmissthreshold = 15;
|
||||
else if (bs.bs_bmissthreshold <= 0)
|
||||
bs.bs_bmissthreshold = 1;
|
||||
|
||||
/*
|
||||
* Calculate sleep duration. The configuration is given in ms.
|
||||
|
@ -148,7 +140,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
|
|||
*/
|
||||
|
||||
bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
|
||||
sleepduration));
|
||||
intval));
|
||||
if (bs.bs_sleepduration > bs.bs_dtimperiod)
|
||||
bs.bs_sleepduration = bs.bs_dtimperiod;
|
||||
|
||||
|
|
|
@ -38,93 +38,6 @@ static int ath9k_ps_enable;
|
|||
module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
|
||||
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
|
||||
|
||||
#define CHAN2G(_freq, _idx) { \
|
||||
.center_freq = (_freq), \
|
||||
.hw_value = (_idx), \
|
||||
.max_power = 20, \
|
||||
}
|
||||
|
||||
#define CHAN5G(_freq, _idx) { \
|
||||
.band = IEEE80211_BAND_5GHZ, \
|
||||
.center_freq = (_freq), \
|
||||
.hw_value = (_idx), \
|
||||
.max_power = 20, \
|
||||
}
|
||||
|
||||
static struct ieee80211_channel ath9k_2ghz_channels[] = {
|
||||
CHAN2G(2412, 0), /* Channel 1 */
|
||||
CHAN2G(2417, 1), /* Channel 2 */
|
||||
CHAN2G(2422, 2), /* Channel 3 */
|
||||
CHAN2G(2427, 3), /* Channel 4 */
|
||||
CHAN2G(2432, 4), /* Channel 5 */
|
||||
CHAN2G(2437, 5), /* Channel 6 */
|
||||
CHAN2G(2442, 6), /* Channel 7 */
|
||||
CHAN2G(2447, 7), /* Channel 8 */
|
||||
CHAN2G(2452, 8), /* Channel 9 */
|
||||
CHAN2G(2457, 9), /* Channel 10 */
|
||||
CHAN2G(2462, 10), /* Channel 11 */
|
||||
CHAN2G(2467, 11), /* Channel 12 */
|
||||
CHAN2G(2472, 12), /* Channel 13 */
|
||||
CHAN2G(2484, 13), /* Channel 14 */
|
||||
};
|
||||
|
||||
static struct ieee80211_channel ath9k_5ghz_channels[] = {
|
||||
/* _We_ call this UNII 1 */
|
||||
CHAN5G(5180, 14), /* Channel 36 */
|
||||
CHAN5G(5200, 15), /* Channel 40 */
|
||||
CHAN5G(5220, 16), /* Channel 44 */
|
||||
CHAN5G(5240, 17), /* Channel 48 */
|
||||
/* _We_ call this UNII 2 */
|
||||
CHAN5G(5260, 18), /* Channel 52 */
|
||||
CHAN5G(5280, 19), /* Channel 56 */
|
||||
CHAN5G(5300, 20), /* Channel 60 */
|
||||
CHAN5G(5320, 21), /* Channel 64 */
|
||||
/* _We_ call this "Middle band" */
|
||||
CHAN5G(5500, 22), /* Channel 100 */
|
||||
CHAN5G(5520, 23), /* Channel 104 */
|
||||
CHAN5G(5540, 24), /* Channel 108 */
|
||||
CHAN5G(5560, 25), /* Channel 112 */
|
||||
CHAN5G(5580, 26), /* Channel 116 */
|
||||
CHAN5G(5600, 27), /* Channel 120 */
|
||||
CHAN5G(5620, 28), /* Channel 124 */
|
||||
CHAN5G(5640, 29), /* Channel 128 */
|
||||
CHAN5G(5660, 30), /* Channel 132 */
|
||||
CHAN5G(5680, 31), /* Channel 136 */
|
||||
CHAN5G(5700, 32), /* Channel 140 */
|
||||
/* _We_ call this UNII 3 */
|
||||
CHAN5G(5745, 33), /* Channel 149 */
|
||||
CHAN5G(5765, 34), /* Channel 153 */
|
||||
CHAN5G(5785, 35), /* Channel 157 */
|
||||
CHAN5G(5805, 36), /* Channel 161 */
|
||||
CHAN5G(5825, 37), /* Channel 165 */
|
||||
};
|
||||
|
||||
/* Atheros hardware rate code addition for short premble */
|
||||
#define SHPCHECK(__hw_rate, __flags) \
|
||||
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
|
||||
|
||||
#define RATE(_bitrate, _hw_rate, _flags) { \
|
||||
.bitrate = (_bitrate), \
|
||||
.flags = (_flags), \
|
||||
.hw_value = (_hw_rate), \
|
||||
.hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
|
||||
}
|
||||
|
||||
static struct ieee80211_rate ath9k_legacy_rates[] = {
|
||||
RATE(10, 0x1b, 0),
|
||||
RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */
|
||||
RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */
|
||||
RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */
|
||||
RATE(60, 0x0b, 0),
|
||||
RATE(90, 0x0f, 0),
|
||||
RATE(120, 0x0a, 0),
|
||||
RATE(180, 0x0e, 0),
|
||||
RATE(240, 0x09, 0),
|
||||
RATE(360, 0x0d, 0),
|
||||
RATE(480, 0x08, 0),
|
||||
RATE(540, 0x0c, 0),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
|
||||
{ .throughput = 0 * 1024, .blink_time = 334 },
|
||||
|
@ -343,6 +256,25 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr,
|
|||
}
|
||||
}
|
||||
|
||||
static void ath9k_regwrite_multi(struct ath_common *common)
|
||||
{
|
||||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
u32 rsp_status;
|
||||
int r;
|
||||
|
||||
r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
|
||||
(u8 *) &priv->wmi->multi_write,
|
||||
sizeof(struct register_write) * priv->wmi->multi_write_idx,
|
||||
(u8 *) &rsp_status, sizeof(rsp_status),
|
||||
100);
|
||||
if (unlikely(r)) {
|
||||
ath_dbg(common, WMI,
|
||||
"REGISTER WRITE FAILED, multi len: %d\n",
|
||||
priv->wmi->multi_write_idx);
|
||||
}
|
||||
priv->wmi->multi_write_idx = 0;
|
||||
}
|
||||
|
||||
static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
|
||||
{
|
||||
struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
|
@ -369,8 +301,6 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
|
|||
struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
u32 rsp_status;
|
||||
int r;
|
||||
|
||||
mutex_lock(&priv->wmi->multi_write_mutex);
|
||||
|
||||
|
@ -383,19 +313,8 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
|
|||
priv->wmi->multi_write_idx++;
|
||||
|
||||
/* If the buffer is full, send it out. */
|
||||
if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
|
||||
r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
|
||||
(u8 *) &priv->wmi->multi_write,
|
||||
sizeof(struct register_write) * priv->wmi->multi_write_idx,
|
||||
(u8 *) &rsp_status, sizeof(rsp_status),
|
||||
100);
|
||||
if (unlikely(r)) {
|
||||
ath_dbg(common, WMI,
|
||||
"REGISTER WRITE FAILED, multi len: %d\n",
|
||||
priv->wmi->multi_write_idx);
|
||||
}
|
||||
priv->wmi->multi_write_idx = 0;
|
||||
}
|
||||
if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER)
|
||||
ath9k_regwrite_multi(common);
|
||||
|
||||
mutex_unlock(&priv->wmi->multi_write_mutex);
|
||||
}
|
||||
|
@ -426,26 +345,13 @@ static void ath9k_regwrite_flush(void *hw_priv)
|
|||
struct ath_hw *ah = (struct ath_hw *) hw_priv;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
|
||||
u32 rsp_status;
|
||||
int r;
|
||||
|
||||
atomic_dec(&priv->wmi->mwrite_cnt);
|
||||
|
||||
mutex_lock(&priv->wmi->multi_write_mutex);
|
||||
|
||||
if (priv->wmi->multi_write_idx) {
|
||||
r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
|
||||
(u8 *) &priv->wmi->multi_write,
|
||||
sizeof(struct register_write) * priv->wmi->multi_write_idx,
|
||||
(u8 *) &rsp_status, sizeof(rsp_status),
|
||||
100);
|
||||
if (unlikely(r)) {
|
||||
ath_dbg(common, WMI,
|
||||
"REGISTER WRITE FAILED, multi len: %d\n",
|
||||
priv->wmi->multi_write_idx);
|
||||
}
|
||||
priv->wmi->multi_write_idx = 0;
|
||||
}
|
||||
if (priv->wmi->multi_write_idx)
|
||||
ath9k_regwrite_multi(common);
|
||||
|
||||
mutex_unlock(&priv->wmi->multi_write_mutex);
|
||||
}
|
||||
|
@ -491,51 +397,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = {
|
|||
.eeprom_read = ath_usb_eeprom_read,
|
||||
};
|
||||
|
||||
static void setup_ht_cap(struct ath9k_htc_priv *priv,
|
||||
struct ieee80211_sta_ht_cap *ht_info)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
u8 tx_streams, rx_streams;
|
||||
int i;
|
||||
|
||||
ht_info->ht_supported = true;
|
||||
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
||||
IEEE80211_HT_CAP_SM_PS |
|
||||
IEEE80211_HT_CAP_SGI_40 |
|
||||
IEEE80211_HT_CAP_DSSSCCK40;
|
||||
|
||||
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
||||
|
||||
ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
|
||||
|
||||
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
||||
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
|
||||
|
||||
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
|
||||
|
||||
/* ath9k_htc supports only 1 or 2 stream devices */
|
||||
tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2);
|
||||
rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2);
|
||||
|
||||
ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
|
||||
tx_streams, rx_streams);
|
||||
|
||||
if (tx_streams >= 2)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
|
||||
|
||||
if (tx_streams != rx_streams) {
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
|
||||
ht_info->mcs.tx_params |= ((tx_streams - 1) <<
|
||||
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
|
||||
}
|
||||
|
||||
for (i = 0; i < rx_streams; i++)
|
||||
ht_info->mcs.rx_mask[i] = 0xff;
|
||||
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
|
||||
}
|
||||
|
||||
static int ath9k_init_queues(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
|
@ -580,31 +441,6 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
|
||||
priv->sbands[IEEE80211_BAND_2GHZ].channels =
|
||||
ath9k_2ghz_channels;
|
||||
priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
|
||||
priv->sbands[IEEE80211_BAND_2GHZ].n_channels =
|
||||
ARRAY_SIZE(ath9k_2ghz_channels);
|
||||
priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
|
||||
priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
|
||||
ARRAY_SIZE(ath9k_legacy_rates);
|
||||
}
|
||||
|
||||
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
|
||||
priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
|
||||
priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
|
||||
priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
|
||||
ARRAY_SIZE(ath9k_5ghz_channels);
|
||||
priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
|
||||
ath9k_legacy_rates + 4;
|
||||
priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
|
||||
ARRAY_SIZE(ath9k_legacy_rates) - 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_init_misc(struct ath9k_htc_priv *priv)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
|
@ -629,6 +465,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
|
|||
if (!ah)
|
||||
return -ENOMEM;
|
||||
|
||||
ah->dev = priv->dev;
|
||||
ah->hw_version.devid = devid;
|
||||
ah->hw_version.usbdev = drv_info;
|
||||
ah->ah_flags |= AH_USE_EEPROM;
|
||||
|
@ -685,8 +522,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
|
|||
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
|
||||
priv->cur_beacon_conf.bslot[i] = NULL;
|
||||
|
||||
ath9k_cmn_init_channels_rates(common);
|
||||
ath9k_cmn_init_crypto(ah);
|
||||
ath9k_init_channels_rates(priv);
|
||||
ath9k_init_misc(priv);
|
||||
ath9k_htc_init_btcoex(priv, product);
|
||||
|
||||
|
@ -722,6 +559,7 @@ static const struct ieee80211_iface_combination if_comb = {
|
|||
static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
|
||||
struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_hw *ah = priv->ah;
|
||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||
struct base_eep_header *pBase;
|
||||
|
||||
|
@ -766,19 +604,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
|
|||
|
||||
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
|
||||
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
|
||||
&priv->sbands[IEEE80211_BAND_2GHZ];
|
||||
&common->sbands[IEEE80211_BAND_2GHZ];
|
||||
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
|
||||
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
|
||||
&priv->sbands[IEEE80211_BAND_5GHZ];
|
||||
&common->sbands[IEEE80211_BAND_5GHZ];
|
||||
|
||||
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
|
||||
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
|
||||
setup_ht_cap(priv,
|
||||
&priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
|
||||
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
|
||||
setup_ht_cap(priv,
|
||||
&priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
|
||||
}
|
||||
ath9k_cmn_reload_chainmask(ah);
|
||||
|
||||
pBase = ath9k_htc_get_eeprom_base(priv);
|
||||
if (pBase) {
|
||||
|
|
|
@ -62,111 +62,6 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
|
|||
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
|
||||
|
||||
bool is_ath9k_unloaded;
|
||||
/* We use the hw_value as an index into our private channel structure */
|
||||
|
||||
#define CHAN2G(_freq, _idx) { \
|
||||
.band = IEEE80211_BAND_2GHZ, \
|
||||
.center_freq = (_freq), \
|
||||
.hw_value = (_idx), \
|
||||
.max_power = 20, \
|
||||
}
|
||||
|
||||
#define CHAN5G(_freq, _idx) { \
|
||||
.band = IEEE80211_BAND_5GHZ, \
|
||||
.center_freq = (_freq), \
|
||||
.hw_value = (_idx), \
|
||||
.max_power = 20, \
|
||||
}
|
||||
|
||||
/* Some 2 GHz radios are actually tunable on 2312-2732
|
||||
* on 5 MHz steps, we support the channels which we know
|
||||
* we have calibration data for all cards though to make
|
||||
* this static */
|
||||
static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
|
||||
CHAN2G(2412, 0), /* Channel 1 */
|
||||
CHAN2G(2417, 1), /* Channel 2 */
|
||||
CHAN2G(2422, 2), /* Channel 3 */
|
||||
CHAN2G(2427, 3), /* Channel 4 */
|
||||
CHAN2G(2432, 4), /* Channel 5 */
|
||||
CHAN2G(2437, 5), /* Channel 6 */
|
||||
CHAN2G(2442, 6), /* Channel 7 */
|
||||
CHAN2G(2447, 7), /* Channel 8 */
|
||||
CHAN2G(2452, 8), /* Channel 9 */
|
||||
CHAN2G(2457, 9), /* Channel 10 */
|
||||
CHAN2G(2462, 10), /* Channel 11 */
|
||||
CHAN2G(2467, 11), /* Channel 12 */
|
||||
CHAN2G(2472, 12), /* Channel 13 */
|
||||
CHAN2G(2484, 13), /* Channel 14 */
|
||||
};
|
||||
|
||||
/* Some 5 GHz radios are actually tunable on XXXX-YYYY
|
||||
* on 5 MHz steps, we support the channels which we know
|
||||
* we have calibration data for all cards though to make
|
||||
* this static */
|
||||
static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
|
||||
/* _We_ call this UNII 1 */
|
||||
CHAN5G(5180, 14), /* Channel 36 */
|
||||
CHAN5G(5200, 15), /* Channel 40 */
|
||||
CHAN5G(5220, 16), /* Channel 44 */
|
||||
CHAN5G(5240, 17), /* Channel 48 */
|
||||
/* _We_ call this UNII 2 */
|
||||
CHAN5G(5260, 18), /* Channel 52 */
|
||||
CHAN5G(5280, 19), /* Channel 56 */
|
||||
CHAN5G(5300, 20), /* Channel 60 */
|
||||
CHAN5G(5320, 21), /* Channel 64 */
|
||||
/* _We_ call this "Middle band" */
|
||||
CHAN5G(5500, 22), /* Channel 100 */
|
||||
CHAN5G(5520, 23), /* Channel 104 */
|
||||
CHAN5G(5540, 24), /* Channel 108 */
|
||||
CHAN5G(5560, 25), /* Channel 112 */
|
||||
CHAN5G(5580, 26), /* Channel 116 */
|
||||
CHAN5G(5600, 27), /* Channel 120 */
|
||||
CHAN5G(5620, 28), /* Channel 124 */
|
||||
CHAN5G(5640, 29), /* Channel 128 */
|
||||
CHAN5G(5660, 30), /* Channel 132 */
|
||||
CHAN5G(5680, 31), /* Channel 136 */
|
||||
CHAN5G(5700, 32), /* Channel 140 */
|
||||
/* _We_ call this UNII 3 */
|
||||
CHAN5G(5745, 33), /* Channel 149 */
|
||||
CHAN5G(5765, 34), /* Channel 153 */
|
||||
CHAN5G(5785, 35), /* Channel 157 */
|
||||
CHAN5G(5805, 36), /* Channel 161 */
|
||||
CHAN5G(5825, 37), /* Channel 165 */
|
||||
};
|
||||
|
||||
/* Atheros hardware rate code addition for short premble */
|
||||
#define SHPCHECK(__hw_rate, __flags) \
|
||||
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
|
||||
|
||||
#define RATE(_bitrate, _hw_rate, _flags) { \
|
||||
.bitrate = (_bitrate), \
|
||||
.flags = (_flags), \
|
||||
.hw_value = (_hw_rate), \
|
||||
.hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
|
||||
}
|
||||
|
||||
static struct ieee80211_rate ath9k_legacy_rates[] = {
|
||||
RATE(10, 0x1b, 0),
|
||||
RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
|
||||
RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
|
||||
RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
|
||||
RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ |
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ)),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = {
|
||||
|
@ -258,64 +153,6 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl
|
|||
/* Initialization */
|
||||
/**************************/
|
||||
|
||||
static void setup_ht_cap(struct ath_softc *sc,
|
||||
struct ieee80211_sta_ht_cap *ht_info)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u8 tx_streams, rx_streams;
|
||||
int i, max_streams;
|
||||
|
||||
ht_info->ht_supported = true;
|
||||
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
||||
IEEE80211_HT_CAP_SM_PS |
|
||||
IEEE80211_HT_CAP_SGI_40 |
|
||||
IEEE80211_HT_CAP_DSSSCCK40;
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
|
||||
|
||||
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
||||
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
|
||||
|
||||
if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah))
|
||||
max_streams = 1;
|
||||
else if (AR_SREV_9462(ah))
|
||||
max_streams = 2;
|
||||
else if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
max_streams = 3;
|
||||
else
|
||||
max_streams = 2;
|
||||
|
||||
if (AR_SREV_9280_20_OR_LATER(ah)) {
|
||||
if (max_streams >= 2)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
|
||||
ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
|
||||
}
|
||||
|
||||
/* set up supported mcs set */
|
||||
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
|
||||
tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams);
|
||||
rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams);
|
||||
|
||||
ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
|
||||
tx_streams, rx_streams);
|
||||
|
||||
if (tx_streams != rx_streams) {
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
|
||||
ht_info->mcs.tx_params |= ((tx_streams - 1) <<
|
||||
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
|
||||
}
|
||||
|
||||
for (i = 0; i < rx_streams; i++)
|
||||
ht_info->mcs.rx_mask[i] = 0xff;
|
||||
|
||||
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
|
||||
}
|
||||
|
||||
static void ath9k_reg_notifier(struct wiphy *wiphy,
|
||||
struct regulatory_request *request)
|
||||
{
|
||||
|
@ -486,51 +323,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ath9k_init_channels_rates(struct ath_softc *sc)
|
||||
{
|
||||
void *channels;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
|
||||
ARRAY_SIZE(ath9k_5ghz_chantable) !=
|
||||
ATH9K_NUM_CHANNELS);
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
|
||||
channels = devm_kzalloc(sc->dev,
|
||||
sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(channels, ath9k_2ghz_chantable,
|
||||
sizeof(ath9k_2ghz_chantable));
|
||||
sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
|
||||
sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
|
||||
sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
|
||||
ARRAY_SIZE(ath9k_2ghz_chantable);
|
||||
sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
|
||||
sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
|
||||
ARRAY_SIZE(ath9k_legacy_rates);
|
||||
}
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
|
||||
channels = devm_kzalloc(sc->dev,
|
||||
sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(channels, ath9k_5ghz_chantable,
|
||||
sizeof(ath9k_5ghz_chantable));
|
||||
sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
|
||||
sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
|
||||
sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
|
||||
ARRAY_SIZE(ath9k_5ghz_chantable);
|
||||
sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
|
||||
ath9k_legacy_rates + 4;
|
||||
sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
|
||||
ARRAY_SIZE(ath9k_legacy_rates) - 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath9k_init_misc(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
|
@ -793,7 +585,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
|||
if (ret)
|
||||
goto err_btcoex;
|
||||
|
||||
ret = ath9k_init_channels_rates(sc);
|
||||
ret = ath9k_cmn_init_channels_rates(common);
|
||||
if (ret)
|
||||
goto err_btcoex;
|
||||
|
||||
|
@ -823,10 +615,11 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
|
|||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *chan;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct cfg80211_chan_def chandef;
|
||||
int i;
|
||||
|
||||
sband = &sc->sbands[band];
|
||||
sband = &common->sbands[band];
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
chan = &sband->channels[i];
|
||||
ah->curchan = &ah->channels[chan->hw_value];
|
||||
|
@ -849,17 +642,6 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc)
|
|||
ah->curchan = curchan;
|
||||
}
|
||||
|
||||
void ath9k_reload_chainmask_settings(struct ath_softc *sc)
|
||||
{
|
||||
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT))
|
||||
return;
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
|
||||
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
|
||||
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
|
||||
}
|
||||
|
||||
static const struct ieee80211_iface_limit if_limits[] = {
|
||||
{ .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
|
@ -949,6 +731,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
|
||||
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||
|
||||
hw->queues = 4;
|
||||
hw->max_rates = 4;
|
||||
|
@ -969,13 +752,13 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
|
||||
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
|
||||
&sc->sbands[IEEE80211_BAND_2GHZ];
|
||||
&common->sbands[IEEE80211_BAND_2GHZ];
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
|
||||
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
|
||||
&sc->sbands[IEEE80211_BAND_5GHZ];
|
||||
&common->sbands[IEEE80211_BAND_5GHZ];
|
||||
|
||||
ath9k_init_wow(hw);
|
||||
ath9k_reload_chainmask_settings(sc);
|
||||
ath9k_cmn_reload_chainmask(ah);
|
||||
|
||||
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
|
||||
}
|
||||
|
|
|
@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data)
|
|||
* interrupts are enabled in the reset routine.
|
||||
*/
|
||||
atomic_inc(&ah->intr_ref_cnt);
|
||||
ath_dbg(common, ANY, "FATAL: Skipping interrupts\n");
|
||||
ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data)
|
|||
* interrupts are enabled in the reset routine.
|
||||
*/
|
||||
atomic_inc(&ah->intr_ref_cnt);
|
||||
ath_dbg(common, ANY,
|
||||
ath_dbg(common, RESET,
|
||||
"BB_WATCHDOG: Skipping interrupts\n");
|
||||
goto out;
|
||||
}
|
||||
|
@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data)
|
|||
type = RESET_TYPE_TX_GTT;
|
||||
ath9k_queue_reset(sc, type);
|
||||
atomic_inc(&ah->intr_ref_cnt);
|
||||
ath_dbg(common, ANY,
|
||||
ath_dbg(common, RESET,
|
||||
"GTT: Skipping interrupts\n");
|
||||
goto out;
|
||||
}
|
||||
|
@ -2053,7 +2053,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
|
|||
ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
|
||||
|
||||
ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
|
||||
ath9k_reload_chainmask_settings(sc);
|
||||
ath9k_cmn_reload_chainmask(ah);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -871,8 +871,16 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
|
|||
if (WARN_ON(!ah->curchan))
|
||||
return -EINVAL;
|
||||
|
||||
if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status))
|
||||
if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) {
|
||||
/*
|
||||
* No valid hardware bitrate found -- we should not get here
|
||||
* because hardware has already validated this frame as OK.
|
||||
*/
|
||||
ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
|
||||
rx_stats->rs_rate);
|
||||
RX_STAT_INC(rx_rate_err);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
|
||||
|
||||
|
|
|
@ -1040,11 +1040,11 @@ static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi)
|
|||
int symbols, bits;
|
||||
int bytes = 0;
|
||||
|
||||
usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
|
||||
symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec);
|
||||
bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams;
|
||||
bits -= OFDM_PLCP_BITS;
|
||||
bytes = bits / 8;
|
||||
bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
|
||||
if (bytes > 65532)
|
||||
bytes = 65532;
|
||||
|
||||
|
@ -1076,6 +1076,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
|
|||
struct ath_tx_info *info, int len, bool rts)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct ieee80211_tx_rate *rates;
|
||||
|
@ -1145,7 +1146,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
|
|||
}
|
||||
|
||||
/* legacy rates */
|
||||
rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
|
||||
rate = &common->sbands[tx_info->band].bitrates[rates[i].idx];
|
||||
if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
|
||||
!(rate->flags & IEEE80211_RATE_ERP_G))
|
||||
phy = WLAN_RC_PHY_CCK;
|
||||
|
|
|
@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
|
|||
static const struct
|
||||
ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
|
||||
{
|
||||
switch (reg->regpair->regDmnEnum) {
|
||||
switch (reg->regpair->reg_domain) {
|
||||
case 0x60:
|
||||
case 0x61:
|
||||
case 0x62:
|
||||
|
@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
|
|||
enum nl80211_reg_initiator initiator,
|
||||
struct ath_regulatory *reg)
|
||||
{
|
||||
switch (reg->regpair->regDmnEnum) {
|
||||
switch (reg->regpair->reg_domain) {
|
||||
case 0x60:
|
||||
case 0x63:
|
||||
case 0x66:
|
||||
|
@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
|
|||
printk(KERN_DEBUG "ath: EEPROM indicates we "
|
||||
"should expect a direct regpair map\n");
|
||||
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
|
||||
if (regDomainPairs[i].regDmnEnum == rd)
|
||||
if (regDomainPairs[i].reg_domain == rd)
|
||||
return true;
|
||||
}
|
||||
printk(KERN_DEBUG
|
||||
|
@ -617,7 +617,7 @@ ath_get_regpair(int regdmn)
|
|||
if (regdmn == NO_ENUMRD)
|
||||
return NULL;
|
||||
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
|
||||
if (regDomainPairs[i].regDmnEnum == regdmn)
|
||||
if (regDomainPairs[i].reg_domain == regdmn)
|
||||
return ®DomainPairs[i];
|
||||
}
|
||||
return NULL;
|
||||
|
@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
|
|||
printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
|
||||
reg->alpha2[0], reg->alpha2[1]);
|
||||
printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
|
||||
reg->regpair->regDmnEnum);
|
||||
reg->regpair->reg_domain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ wil6210-y += wmi.o
|
|||
wil6210-y += interrupt.o
|
||||
wil6210-y += txrx.o
|
||||
wil6210-y += debug.o
|
||||
wil6210-y += rx_reorder.o
|
||||
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
|
||||
|
||||
# for tracing framework to find trace.h
|
||||
|
|
|
@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
|
||||
struct station_info *sinfo)
|
||||
{
|
||||
struct wmi_notify_req_cmd cmd = {
|
||||
.cid = cid,
|
||||
.interval_usec = 0,
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_notify_req_done_event evt;
|
||||
} __packed reply;
|
||||
struct wil_net_stats *stats = &wil->sta[cid].stats;
|
||||
int rc;
|
||||
|
||||
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
wil_dbg_wmi(wil, "Link status for CID %d: {\n"
|
||||
" MCS %d TSF 0x%016llx\n"
|
||||
" BF status 0x%08x SNR 0x%08x SQI %d%%\n"
|
||||
" Tx Tpt %d goodput %d Rx goodput %d\n"
|
||||
" Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
|
||||
cid, le16_to_cpu(reply.evt.bf_mcs),
|
||||
le64_to_cpu(reply.evt.tsf), reply.evt.status,
|
||||
le32_to_cpu(reply.evt.snr_val),
|
||||
reply.evt.sqi,
|
||||
le32_to_cpu(reply.evt.tx_tpt),
|
||||
le32_to_cpu(reply.evt.tx_goodput),
|
||||
le32_to_cpu(reply.evt.rx_goodput),
|
||||
le16_to_cpu(reply.evt.my_rx_sector),
|
||||
le16_to_cpu(reply.evt.my_tx_sector),
|
||||
le16_to_cpu(reply.evt.other_rx_sector),
|
||||
le16_to_cpu(reply.evt.other_tx_sector));
|
||||
|
||||
sinfo->generation = wil->sinfo_gen;
|
||||
|
||||
sinfo->filled = STATION_INFO_RX_BYTES |
|
||||
STATION_INFO_TX_BYTES |
|
||||
STATION_INFO_RX_PACKETS |
|
||||
STATION_INFO_TX_PACKETS |
|
||||
STATION_INFO_RX_BITRATE |
|
||||
STATION_INFO_TX_BITRATE |
|
||||
STATION_INFO_RX_DROP_MISC |
|
||||
STATION_INFO_TX_FAILED;
|
||||
|
||||
sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
|
||||
sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
|
||||
sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
|
||||
sinfo->rxrate.mcs = stats->last_mcs_rx;
|
||||
sinfo->rx_bytes = stats->rx_bytes;
|
||||
sinfo->rx_packets = stats->rx_packets;
|
||||
sinfo->rx_dropped_misc = stats->rx_dropped;
|
||||
sinfo->tx_bytes = stats->tx_bytes;
|
||||
sinfo->tx_packets = stats->tx_packets;
|
||||
sinfo->tx_failed = stats->tx_errors;
|
||||
|
||||
if (test_bit(wil_status_fwconnected, &wil->status)) {
|
||||
sinfo->filled |= STATION_INFO_SIGNAL;
|
||||
sinfo->signal = reply.evt.sqi;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_get_station(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
u8 *mac, struct station_info *sinfo)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
struct wmi_notify_req_cmd cmd = {
|
||||
.cid = 0,
|
||||
.interval_usec = 0,
|
||||
};
|
||||
|
||||
if (memcmp(mac, wil->dst_addr[0], ETH_ALEN))
|
||||
return -ENOENT;
|
||||
int cid = wil_find_cid(wil, mac);
|
||||
|
||||
/* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
|
||||
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20);
|
||||
if (rc)
|
||||
return rc;
|
||||
wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
|
||||
if (cid < 0)
|
||||
return cid;
|
||||
|
||||
sinfo->generation = wil->sinfo_gen;
|
||||
rc = wil_cid_fill_sinfo(wil, cid, sinfo);
|
||||
|
||||
sinfo->filled |= STATION_INFO_TX_BITRATE;
|
||||
sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
|
||||
sinfo->txrate.mcs = wil->stats.bf_mcs;
|
||||
sinfo->filled |= STATION_INFO_RX_BITRATE;
|
||||
sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
|
||||
sinfo->rxrate.mcs = wil->stats.last_mcs_rx;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (test_bit(wil_status_fwconnected, &wil->status)) {
|
||||
sinfo->filled |= STATION_INFO_SIGNAL;
|
||||
sinfo->signal = 12; /* TODO: provide real value */
|
||||
/*
|
||||
* Find @idx-th active STA for station dump.
|
||||
*/
|
||||
static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
if (wil->sta[i].status == wil_sta_unused)
|
||||
continue;
|
||||
if (idx == 0)
|
||||
return i;
|
||||
idx--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_dump_station(struct wiphy *wiphy,
|
||||
struct net_device *dev, int idx,
|
||||
u8 *mac, struct station_info *sinfo)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
int cid = wil_find_cid_by_idx(wil, idx);
|
||||
|
||||
if (cid < 0)
|
||||
return -ENOENT;
|
||||
|
||||
memcpy(mac, wil->sta[cid].addr, ETH_ALEN);
|
||||
wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
|
||||
|
||||
rc = wil_cid_fill_sinfo(wil, cid, sinfo);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_change_iface(struct wiphy *wiphy,
|
||||
|
@ -352,6 +436,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params,
|
||||
u64 *cookie)
|
||||
{
|
||||
const u8 *buf = params->buf;
|
||||
size_t len = params->len;
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
struct ieee80211_mgmt *mgmt_frame = (void *)buf;
|
||||
struct wmi_sw_tx_req_cmd *cmd;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_sw_tx_complete_event evt;
|
||||
} __packed evt;
|
||||
|
||||
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
|
||||
cmd->len = cpu_to_le16(len);
|
||||
memcpy(cmd->payload, buf, len);
|
||||
|
||||
rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
|
||||
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
|
||||
if (rc == 0)
|
||||
rc = evt.evt.status;
|
||||
|
||||
kfree(cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_set_channel(struct wiphy *wiphy,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
|
@ -402,6 +520,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wil_remain_on_channel(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
unsigned int duration,
|
||||
u64 *cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
|
||||
/* TODO: handle duration */
|
||||
wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration);
|
||||
|
||||
rc = wmi_set_channel(wil, chan->hw_value);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = wmi_rxon(wil, true);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
u64 cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
|
||||
wil_info(wil, "%s()\n", __func__);
|
||||
|
||||
rc = wmi_rxon(wil, false);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_fix_bcon(struct wil6210_priv *wil,
|
||||
struct cfg80211_beacon_data *bcon)
|
||||
{
|
||||
|
@ -504,12 +657,24 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_del_station(struct wiphy *wiphy,
|
||||
struct net_device *dev, u8 *mac)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
wil6210_disconnect(wil, mac);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cfg80211_ops wil_cfg80211_ops = {
|
||||
.scan = wil_cfg80211_scan,
|
||||
.connect = wil_cfg80211_connect,
|
||||
.disconnect = wil_cfg80211_disconnect,
|
||||
.change_virtual_intf = wil_cfg80211_change_iface,
|
||||
.get_station = wil_cfg80211_get_station,
|
||||
.dump_station = wil_cfg80211_dump_station,
|
||||
.remain_on_channel = wil_remain_on_channel,
|
||||
.cancel_remain_on_channel = wil_cancel_remain_on_channel,
|
||||
.mgmt_tx = wil_cfg80211_mgmt_tx,
|
||||
.set_monitor_channel = wil_cfg80211_set_channel,
|
||||
.add_key = wil_cfg80211_add_key,
|
||||
.del_key = wil_cfg80211_del_key,
|
||||
|
@ -517,6 +682,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
|
|||
/* AP mode */
|
||||
.start_ap = wil_cfg80211_start_ap,
|
||||
.stop_ap = wil_cfg80211_stop_ap,
|
||||
.del_station = wil_cfg80211_del_station,
|
||||
};
|
||||
|
||||
static void wil_wiphy_init(struct wiphy *wiphy)
|
||||
|
@ -542,7 +708,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
|
|||
wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;
|
||||
|
||||
/* TODO: figure this out */
|
||||
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||
wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
|
||||
|
||||
wiphy->cipher_suites = wil_cipher_suites;
|
||||
wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
|
||||
|
|
|
@ -26,9 +26,11 @@
|
|||
/* Nasty hack. Better have per device instances */
|
||||
static u32 mem_addr;
|
||||
static u32 dbg_txdesc_index;
|
||||
static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
|
||||
|
||||
static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
|
||||
const char *name, struct vring *vring)
|
||||
const char *name, struct vring *vring,
|
||||
char _s, char _h)
|
||||
{
|
||||
void __iomem *x = wmi_addr(wil, vring->hwtail);
|
||||
|
||||
|
@ -50,8 +52,8 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
|
|||
volatile struct vring_tx_desc *d = &vring->va[i].tx;
|
||||
if ((i % 64) == 0 && (i != 0))
|
||||
seq_printf(s, "\n");
|
||||
seq_printf(s, "%s", (d->dma.status & BIT(0)) ?
|
||||
"S" : (vring->ctx[i].skb ? "H" : "h"));
|
||||
seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
|
||||
_s : (vring->ctx[i].skb ? _h : 'h'));
|
||||
}
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
|
@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
|
|||
uint i;
|
||||
struct wil6210_priv *wil = s->private;
|
||||
|
||||
wil_print_vring(s, wil, "rx", &wil->vring_rx);
|
||||
wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
|
||||
struct vring *vring = &(wil->vring_tx[i]);
|
||||
if (vring->va) {
|
||||
int cid = wil->vring2cid_tid[i][0];
|
||||
int tid = wil->vring2cid_tid[i][1];
|
||||
char name[10];
|
||||
snprintf(name, sizeof(name), "tx_%2d", i);
|
||||
wil_print_vring(s, wil, name, vring);
|
||||
|
||||
seq_printf(s, "\n%pM CID %d TID %d\n",
|
||||
wil->sta[cid].addr, cid, tid);
|
||||
wil_print_vring(s, wil, name, vring, '_', 'H');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,25 +397,40 @@ static const struct file_operations fops_reset = {
|
|||
.write = wil_write_file_reset,
|
||||
.open = simple_open,
|
||||
};
|
||||
/*---------Tx descriptor------------*/
|
||||
|
||||
/*---------Tx/Rx descriptor------------*/
|
||||
static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct vring *vring = &(wil->vring_tx[0]);
|
||||
struct vring *vring;
|
||||
bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
|
||||
if (tx)
|
||||
vring = &(wil->vring_tx[dbg_vring_index]);
|
||||
else
|
||||
vring = &wil->vring_rx;
|
||||
|
||||
if (!vring->va) {
|
||||
seq_printf(s, "No Tx VRING\n");
|
||||
if (tx)
|
||||
seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index);
|
||||
else
|
||||
seq_puts(s, "No Rx VRING\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dbg_txdesc_index < vring->size) {
|
||||
/* use struct vring_tx_desc for Rx as well,
|
||||
* only field used, .dma.length, is the same
|
||||
*/
|
||||
volatile struct vring_tx_desc *d =
|
||||
&(vring->va[dbg_txdesc_index].tx);
|
||||
volatile u32 *u = (volatile u32 *)d;
|
||||
struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
|
||||
|
||||
seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index);
|
||||
if (tx)
|
||||
seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index,
|
||||
dbg_txdesc_index);
|
||||
else
|
||||
seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index);
|
||||
seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
u[0], u[1], u[2], u[3]);
|
||||
seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
|
@ -439,8 +461,13 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
|
|||
}
|
||||
seq_printf(s, "}\n");
|
||||
} else {
|
||||
seq_printf(s, "TxDesc index (%d) >= size (%d)\n",
|
||||
dbg_txdesc_index, vring->size);
|
||||
if (tx)
|
||||
seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
|
||||
dbg_vring_index, dbg_txdesc_index,
|
||||
vring->size);
|
||||
else
|
||||
seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
|
||||
dbg_txdesc_index, vring->size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -570,6 +597,68 @@ static const struct file_operations fops_temp = {
|
|||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*---------Station matrix------------*/
|
||||
static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
|
||||
{
|
||||
int i;
|
||||
u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
|
||||
seq_printf(s, "0x%03x [", r->head_seq_num);
|
||||
for (i = 0; i < r->buf_size; i++) {
|
||||
if (i == index)
|
||||
seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
|
||||
else
|
||||
seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
|
||||
}
|
||||
seq_puts(s, "]\n");
|
||||
}
|
||||
|
||||
static int wil_sta_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
int i, tid;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
struct wil_sta_info *p = &wil->sta[i];
|
||||
char *status = "unknown";
|
||||
switch (p->status) {
|
||||
case wil_sta_unused:
|
||||
status = "unused ";
|
||||
break;
|
||||
case wil_sta_conn_pending:
|
||||
status = "pending ";
|
||||
break;
|
||||
case wil_sta_connected:
|
||||
status = "connected";
|
||||
break;
|
||||
}
|
||||
seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
|
||||
|
||||
if (p->status == wil_sta_connected) {
|
||||
for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
|
||||
struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
|
||||
if (r) {
|
||||
seq_printf(s, "[%2d] ", tid);
|
||||
wil_print_rxtid(s, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_sta_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_sta_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_sta = {
|
||||
.open = wil_sta_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*----------------*/
|
||||
int wil6210_debugfs_init(struct wil6210_priv *wil)
|
||||
{
|
||||
|
@ -581,9 +670,13 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
|
|||
|
||||
debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
|
||||
debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
|
||||
debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc);
|
||||
debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg,
|
||||
debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
|
||||
debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
|
||||
debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
|
||||
&dbg_txdesc_index);
|
||||
debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg,
|
||||
&dbg_vring_index);
|
||||
|
||||
debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
|
||||
debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
|
||||
debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "txrx.h"
|
||||
|
||||
/*
|
||||
* Due to a hardware issue,
|
||||
|
@ -52,29 +54,75 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
|
|||
__raw_writel(*s++, d++);
|
||||
}
|
||||
|
||||
static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
|
||||
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
|
||||
{
|
||||
uint i;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
wil_link_off(wil);
|
||||
if (test_bit(wil_status_fwconnected, &wil->status)) {
|
||||
clear_bit(wil_status_fwconnected, &wil->status);
|
||||
cfg80211_disconnected(ndev,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
NULL, 0, GFP_KERNEL);
|
||||
} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
|
||||
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
GFP_KERNEL);
|
||||
if (sta->status != wil_sta_unused) {
|
||||
wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
|
||||
sta->status = wil_sta_unused;
|
||||
}
|
||||
clear_bit(wil_status_fwconnecting, &wil->status);
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
|
||||
wil_vring_fini_tx(wil, i);
|
||||
|
||||
clear_bit(wil_status_dontscan, &wil->status);
|
||||
for (i = 0; i < WIL_STA_TID_NUM; i++) {
|
||||
struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
|
||||
sta->tid_rx[i] = NULL;
|
||||
wil_tid_ampdu_rx_free(wil, r);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
|
||||
if (wil->vring2cid_tid[i][0] == cid)
|
||||
wil_vring_fini_tx(wil, i);
|
||||
}
|
||||
memset(&sta->stats, 0, sizeof(sta->stats));
|
||||
}
|
||||
|
||||
static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
|
||||
{
|
||||
int cid = -ENOENT;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
|
||||
might_sleep();
|
||||
if (bssid) {
|
||||
cid = wil_find_cid(wil, bssid);
|
||||
wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
|
||||
} else {
|
||||
wil_dbg_misc(wil, "%s(all)\n", __func__);
|
||||
}
|
||||
|
||||
if (cid >= 0) /* disconnect 1 peer */
|
||||
wil_disconnect_cid(wil, cid);
|
||||
else /* disconnect all */
|
||||
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
|
||||
wil_disconnect_cid(wil, cid);
|
||||
|
||||
/* link state */
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
wil_link_off(wil);
|
||||
if (test_bit(wil_status_fwconnected, &wil->status)) {
|
||||
clear_bit(wil_status_fwconnected, &wil->status);
|
||||
cfg80211_disconnected(ndev,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
NULL, 0, GFP_KERNEL);
|
||||
} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
|
||||
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
clear_bit(wil_status_fwconnecting, &wil->status);
|
||||
wil_dbg_misc(wil, "clear_bit(wil_status_dontscan)\n");
|
||||
clear_bit(wil_status_dontscan, &wil->status);
|
||||
break;
|
||||
default:
|
||||
/* AP-like interface and monitor:
|
||||
* never scan, always connected
|
||||
*/
|
||||
if (bssid)
|
||||
cfg80211_del_sta(ndev, bssid, GFP_KERNEL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void wil_disconnect_worker(struct work_struct *work)
|
||||
|
@ -97,12 +145,23 @@ static void wil_connect_timer_fn(ulong x)
|
|||
schedule_work(&wil->disconnect_worker);
|
||||
}
|
||||
|
||||
static int wil_find_free_vring(struct wil6210_priv *wil)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
if (!wil->vring_tx[i].va)
|
||||
return i;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void wil_connect_worker(struct work_struct *work)
|
||||
{
|
||||
int rc;
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
connect_worker);
|
||||
int cid = wil->pending_connect_cid;
|
||||
int ringid = wil_find_free_vring(wil);
|
||||
|
||||
if (cid < 0) {
|
||||
wil_err(wil, "No connection pending\n");
|
||||
|
@ -111,16 +170,22 @@ static void wil_connect_worker(struct work_struct *work)
|
|||
|
||||
wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
|
||||
|
||||
rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0);
|
||||
rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);
|
||||
wil->pending_connect_cid = -1;
|
||||
if (rc == 0)
|
||||
if (rc == 0) {
|
||||
wil->sta[cid].status = wil_sta_connected;
|
||||
wil_link_on(wil);
|
||||
} else {
|
||||
wil->sta[cid].status = wil_sta_unused;
|
||||
}
|
||||
}
|
||||
|
||||
int wil_priv_init(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
memset(wil->sta, 0, sizeof(wil->sta));
|
||||
|
||||
mutex_init(&wil->mutex);
|
||||
mutex_init(&wil->wmi_mutex);
|
||||
|
||||
|
@ -370,3 +435,19 @@ int wil_down(struct wil6210_priv *wil)
|
|||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
|
||||
{
|
||||
int i;
|
||||
int rc = -ENOENT;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
if ((wil->sta[i].status != wil_sta_unused) &&
|
||||
ether_addr_equal(wil->sta[i].addr, mac)) {
|
||||
rc = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
#include "wil6210.h"
|
||||
#include "txrx.h"
|
||||
|
||||
#define SEQ_MODULO 0x1000
|
||||
#define SEQ_MASK 0xfff
|
||||
|
||||
static inline int seq_less(u16 sq1, u16 sq2)
|
||||
{
|
||||
return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
|
||||
}
|
||||
|
||||
static inline u16 seq_inc(u16 sq)
|
||||
{
|
||||
return (sq + 1) & SEQ_MASK;
|
||||
}
|
||||
|
||||
static inline u16 seq_sub(u16 sq1, u16 sq2)
|
||||
{
|
||||
return (sq1 - sq2) & SEQ_MASK;
|
||||
}
|
||||
|
||||
static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq)
|
||||
{
|
||||
return seq_sub(seq, r->ssn) % r->buf_size;
|
||||
}
|
||||
|
||||
static void wil_release_reorder_frame(struct wil6210_priv *wil,
|
||||
struct wil_tid_ampdu_rx *r,
|
||||
int index)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct sk_buff *skb = r->reorder_buf[index];
|
||||
|
||||
if (!skb)
|
||||
goto no_frame;
|
||||
|
||||
/* release the frame from the reorder ring buffer */
|
||||
r->stored_mpdu_num--;
|
||||
r->reorder_buf[index] = NULL;
|
||||
wil_netif_rx_any(skb, ndev);
|
||||
|
||||
no_frame:
|
||||
r->head_seq_num = seq_inc(r->head_seq_num);
|
||||
}
|
||||
|
||||
static void wil_release_reorder_frames(struct wil6210_priv *wil,
|
||||
struct wil_tid_ampdu_rx *r,
|
||||
u16 hseq)
|
||||
{
|
||||
int index;
|
||||
|
||||
while (seq_less(r->head_seq_num, hseq)) {
|
||||
index = reorder_index(r, r->head_seq_num);
|
||||
wil_release_reorder_frame(wil, r, index);
|
||||
}
|
||||
}
|
||||
|
||||
static void wil_reorder_release(struct wil6210_priv *wil,
|
||||
struct wil_tid_ampdu_rx *r)
|
||||
{
|
||||
int index = reorder_index(r, r->head_seq_num);
|
||||
|
||||
while (r->reorder_buf[index]) {
|
||||
wil_release_reorder_frame(wil, r, index);
|
||||
index = reorder_index(r, r->head_seq_num);
|
||||
}
|
||||
}
|
||||
|
||||
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
|
||||
int tid = wil_rxdesc_tid(d);
|
||||
int cid = wil_rxdesc_cid(d);
|
||||
int mid = wil_rxdesc_mid(d);
|
||||
u16 seq = wil_rxdesc_seq(d);
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
struct wil_tid_ampdu_rx *r = sta->tid_rx[tid];
|
||||
u16 hseq;
|
||||
int index;
|
||||
|
||||
wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
|
||||
mid, cid, tid, seq);
|
||||
|
||||
if (!r) {
|
||||
wil_netif_rx_any(skb, ndev);
|
||||
return;
|
||||
}
|
||||
|
||||
hseq = r->head_seq_num;
|
||||
|
||||
spin_lock(&r->reorder_lock);
|
||||
|
||||
/* frame with out of date sequence number */
|
||||
if (seq_less(seq, r->head_seq_num)) {
|
||||
dev_kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If frame the sequence number exceeds our buffering window
|
||||
* size release some previous frames to make room for this one.
|
||||
*/
|
||||
if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
|
||||
hseq = seq_inc(seq_sub(seq, r->buf_size));
|
||||
/* release stored frames up to new head to stack */
|
||||
wil_release_reorder_frames(wil, r, hseq);
|
||||
}
|
||||
|
||||
/* Now the new frame is always in the range of the reordering buffer */
|
||||
|
||||
index = reorder_index(r, seq);
|
||||
|
||||
/* check if we already stored this frame */
|
||||
if (r->reorder_buf[index]) {
|
||||
dev_kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the current MPDU is in the right order and nothing else
|
||||
* is stored we can process it directly, no need to buffer it.
|
||||
* If it is first but there's something stored, we may be able
|
||||
* to release frames after this one.
|
||||
*/
|
||||
if (seq == r->head_seq_num && r->stored_mpdu_num == 0) {
|
||||
r->head_seq_num = seq_inc(r->head_seq_num);
|
||||
wil_netif_rx_any(skb, ndev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* put the frame in the reordering buffer */
|
||||
r->reorder_buf[index] = skb;
|
||||
r->reorder_time[index] = jiffies;
|
||||
r->stored_mpdu_num++;
|
||||
wil_reorder_release(wil, r);
|
||||
|
||||
out:
|
||||
spin_unlock(&r->reorder_lock);
|
||||
}
|
||||
|
||||
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
|
||||
int size, u16 ssn)
|
||||
{
|
||||
struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
r->reorder_buf =
|
||||
kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL);
|
||||
r->reorder_time =
|
||||
kcalloc(size, sizeof(unsigned long), GFP_KERNEL);
|
||||
if (!r->reorder_buf || !r->reorder_time) {
|
||||
kfree(r->reorder_buf);
|
||||
kfree(r->reorder_time);
|
||||
kfree(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spin_lock_init(&r->reorder_lock);
|
||||
r->ssn = ssn;
|
||||
r->head_seq_num = ssn;
|
||||
r->buf_size = size;
|
||||
r->stored_mpdu_num = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
|
||||
struct wil_tid_ampdu_rx *r)
|
||||
{
|
||||
if (!r)
|
||||
return;
|
||||
wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size);
|
||||
kfree(r->reorder_buf);
|
||||
kfree(r->reorder_time);
|
||||
kfree(r);
|
||||
}
|
|
@ -344,6 +344,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
|||
u16 dmalen;
|
||||
u8 ftype;
|
||||
u8 ds_bits;
|
||||
int cid;
|
||||
struct wil_net_stats *stats;
|
||||
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
|
||||
|
||||
|
@ -383,8 +386,10 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
|||
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
skb->data, skb_headlen(skb), false);
|
||||
|
||||
|
||||
wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
|
||||
cid = wil_rxdesc_cid(d);
|
||||
stats = &wil->sta[cid].stats;
|
||||
stats->last_mcs_rx = wil_rxdesc_mcs(d);
|
||||
wil->stats.last_mcs_rx = stats->last_mcs_rx;
|
||||
|
||||
/* use radiotap header only if required */
|
||||
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
|
||||
|
@ -472,10 +477,14 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
|
|||
* Pass Rx packet to the netif. Update statistics.
|
||||
* Called in softirq context (NAPI poll).
|
||||
*/
|
||||
static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
int rc;
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
unsigned int len = skb->len;
|
||||
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
|
||||
int cid = wil_rxdesc_cid(d);
|
||||
struct wil_net_stats *stats = &wil->sta[cid].stats;
|
||||
|
||||
skb_orphan(skb);
|
||||
|
||||
|
@ -483,10 +492,13 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
|||
|
||||
if (likely(rc == NET_RX_SUCCESS)) {
|
||||
ndev->stats.rx_packets++;
|
||||
stats->rx_packets++;
|
||||
ndev->stats.rx_bytes += len;
|
||||
stats->rx_bytes += len;
|
||||
|
||||
} else {
|
||||
ndev->stats.rx_dropped++;
|
||||
stats->rx_dropped++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -515,12 +527,18 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
|
|||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
skb->protocol = htons(ETH_P_802_2);
|
||||
|
||||
wil_netif_rx_any(skb, ndev);
|
||||
} else {
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
|
||||
if (is_unicast_ether_addr(eth->h_dest))
|
||||
wil_rx_reorder(wil, skb);
|
||||
else
|
||||
wil_netif_rx_any(skb, ndev);
|
||||
}
|
||||
|
||||
wil_netif_rx_any(skb, ndev);
|
||||
}
|
||||
wil_rx_refill(wil, v->size);
|
||||
}
|
||||
|
@ -598,6 +616,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
|||
if (rc)
|
||||
goto out;
|
||||
|
||||
wil->vring2cid_tid[id][0] = cid;
|
||||
wil->vring2cid_tid[id][1] = tid;
|
||||
|
||||
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
|
||||
|
||||
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
|
||||
|
@ -634,14 +655,85 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
|
|||
static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct vring *v = &wil->vring_tx[0];
|
||||
int i;
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
int cid = wil_find_cid(wil, eth->h_dest);
|
||||
|
||||
if (v->va)
|
||||
return v;
|
||||
if (cid < 0)
|
||||
return NULL;
|
||||
|
||||
/* TODO: fix for multiple TID */
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
|
||||
if (wil->vring2cid_tid[i][0] == cid) {
|
||||
struct vring *v = &wil->vring_tx[i];
|
||||
wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
|
||||
__func__, eth->h_dest, i);
|
||||
if (v->va) {
|
||||
return v;
|
||||
} else {
|
||||
wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void wil_set_da_for_vring(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb, int vring_index)
|
||||
{
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
int cid = wil->vring2cid_tid[vring_index][0];
|
||||
memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
|
||||
}
|
||||
|
||||
static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
||||
struct sk_buff *skb);
|
||||
/*
|
||||
* Find 1-st vring and return it; set dest address for this vring in skb
|
||||
* duplicate skb and send it to other active vrings
|
||||
*/
|
||||
static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct vring *v, *v2;
|
||||
struct sk_buff *skb2;
|
||||
int i;
|
||||
|
||||
/* find 1-st vring */
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
v = &wil->vring_tx[i];
|
||||
if (v->va)
|
||||
goto found;
|
||||
}
|
||||
|
||||
wil_err(wil, "Tx while no vrings active?\n");
|
||||
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
wil_dbg_txrx(wil, "BCAST -> ring %d\n", i);
|
||||
wil_set_da_for_vring(wil, skb, i);
|
||||
|
||||
/* find other active vrings and duplicate skb for each */
|
||||
for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
v2 = &wil->vring_tx[i];
|
||||
if (!v2->va)
|
||||
continue;
|
||||
skb2 = skb_copy(skb, GFP_ATOMIC);
|
||||
if (skb2) {
|
||||
wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
|
||||
wil_set_da_for_vring(wil, skb2, i);
|
||||
wil_tx_vring(wil, v2, skb2);
|
||||
} else {
|
||||
wil_err(wil, "skb_copy failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
|
||||
int vring_index)
|
||||
{
|
||||
|
@ -740,9 +832,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
}
|
||||
_d = &(vring->va[i].tx);
|
||||
|
||||
/* FIXME FW can accept only unicast frames for the peer */
|
||||
memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
|
||||
|
||||
pa = dma_map_single(dev, skb->data,
|
||||
skb_headlen(skb), DMA_TO_DEVICE);
|
||||
|
||||
|
@ -836,6 +925,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
struct vring *vring;
|
||||
int rc;
|
||||
|
||||
|
@ -854,9 +944,13 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
}
|
||||
|
||||
/* find vring */
|
||||
vring = wil_find_tx_vring(wil, skb);
|
||||
if (is_unicast_ether_addr(eth->h_dest)) {
|
||||
vring = wil_find_tx_vring(wil, skb);
|
||||
} else {
|
||||
vring = wil_tx_bcast(wil, skb);
|
||||
}
|
||||
if (!vring) {
|
||||
wil_err(wil, "No Tx VRING available\n");
|
||||
wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest);
|
||||
goto drop;
|
||||
}
|
||||
/* set up vring entry */
|
||||
|
@ -892,6 +986,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
|
|||
struct device *dev = wil_to_dev(wil);
|
||||
struct vring *vring = &wil->vring_tx[ringid];
|
||||
int done = 0;
|
||||
int cid = wil->vring2cid_tid[ringid][0];
|
||||
struct wil_net_stats *stats = &wil->sta[cid].stats;
|
||||
|
||||
if (!vring->va) {
|
||||
wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);
|
||||
|
@ -933,9 +1029,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
|
|||
if (skb) {
|
||||
if (d->dma.error == 0) {
|
||||
ndev->stats.tx_packets++;
|
||||
stats->tx_packets++;
|
||||
ndev->stats.tx_bytes += skb->len;
|
||||
stats->tx_bytes += skb->len;
|
||||
} else {
|
||||
ndev->stats.tx_errors++;
|
||||
stats->tx_errors++;
|
||||
}
|
||||
|
||||
dev_kfree_skb_any(skb);
|
||||
|
|
|
@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
|
|||
return (void *)skb->cb;
|
||||
}
|
||||
|
||||
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
|
||||
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
|
||||
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
|
||||
int size, u16 ssn);
|
||||
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
|
||||
struct wil_tid_ampdu_rx *r);
|
||||
|
||||
#endif /* WIL6210_TXRX_H */
|
||||
|
|
|
@ -215,6 +215,46 @@ enum { /* for wil6210_priv.status */
|
|||
|
||||
struct pci_dev;
|
||||
|
||||
/**
|
||||
* struct tid_ampdu_rx - TID aggregation information (Rx).
|
||||
*
|
||||
* @reorder_buf: buffer to reorder incoming aggregated MPDUs
|
||||
* @reorder_time: jiffies when skb was added
|
||||
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
|
||||
* @reorder_timer: releases expired frames from the reorder buffer.
|
||||
* @last_rx: jiffies of last rx activity
|
||||
* @head_seq_num: head sequence number in reordering buffer.
|
||||
* @stored_mpdu_num: number of MPDUs in reordering buffer
|
||||
* @ssn: Starting Sequence Number expected to be aggregated.
|
||||
* @buf_size: buffer size for incoming A-MPDUs
|
||||
* @timeout: reset timer value (in TUs).
|
||||
* @dialog_token: dialog token for aggregation session
|
||||
* @rcu_head: RCU head used for freeing this struct
|
||||
* @reorder_lock: serializes access to reorder buffer, see below.
|
||||
*
|
||||
* This structure's lifetime is managed by RCU, assignments to
|
||||
* the array holding it must hold the aggregation mutex.
|
||||
*
|
||||
* The @reorder_lock is used to protect the members of this
|
||||
* struct, except for @timeout, @buf_size and @dialog_token,
|
||||
* which are constant across the lifetime of the struct (the
|
||||
* dialog token being used only for debugging).
|
||||
*/
|
||||
struct wil_tid_ampdu_rx {
|
||||
spinlock_t reorder_lock; /* see above */
|
||||
struct sk_buff **reorder_buf;
|
||||
unsigned long *reorder_time;
|
||||
struct timer_list session_timer;
|
||||
struct timer_list reorder_timer;
|
||||
unsigned long last_rx;
|
||||
u16 head_seq_num;
|
||||
u16 stored_mpdu_num;
|
||||
u16 ssn;
|
||||
u16 buf_size;
|
||||
u16 timeout;
|
||||
u8 dialog_token;
|
||||
};
|
||||
|
||||
struct wil6210_stats {
|
||||
u64 tsf;
|
||||
u32 snr;
|
||||
|
@ -226,6 +266,42 @@ struct wil6210_stats {
|
|||
u16 peer_tx_sector;
|
||||
};
|
||||
|
||||
enum wil_sta_status {
|
||||
wil_sta_unused = 0,
|
||||
wil_sta_conn_pending = 1,
|
||||
wil_sta_connected = 2,
|
||||
};
|
||||
|
||||
#define WIL_STA_TID_NUM (16)
|
||||
|
||||
struct wil_net_stats {
|
||||
unsigned long rx_packets;
|
||||
unsigned long tx_packets;
|
||||
unsigned long rx_bytes;
|
||||
unsigned long tx_bytes;
|
||||
unsigned long tx_errors;
|
||||
unsigned long rx_dropped;
|
||||
u16 last_mcs_rx;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wil_sta_info - data for peer
|
||||
*
|
||||
* Peer identified by its CID (connection ID)
|
||||
* NIC performs beam forming for each peer;
|
||||
* if no beam forming done, frame exchange is not
|
||||
* possible.
|
||||
*/
|
||||
struct wil_sta_info {
|
||||
u8 addr[ETH_ALEN];
|
||||
enum wil_sta_status status;
|
||||
struct wil_net_stats stats;
|
||||
/* Rx BACK */
|
||||
struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
|
||||
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
|
||||
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
|
||||
};
|
||||
|
||||
struct wil6210_priv {
|
||||
struct pci_dev *pdev;
|
||||
int n_msi;
|
||||
|
@ -267,7 +343,8 @@ struct wil6210_priv {
|
|||
/* DMA related */
|
||||
struct vring vring_rx;
|
||||
struct vring vring_tx[WIL6210_MAX_TX_RINGS];
|
||||
u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN];
|
||||
u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
|
||||
struct wil_sta_info sta[WIL6210_MAX_CID];
|
||||
/* scan */
|
||||
struct cfg80211_scan_request *scan_request;
|
||||
|
||||
|
@ -334,6 +411,7 @@ void wil_link_off(struct wil6210_priv *wil);
|
|||
int wil_up(struct wil6210_priv *wil);
|
||||
int wil_down(struct wil6210_priv *wil);
|
||||
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
|
||||
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
|
||||
|
||||
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
|
||||
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
|
||||
|
@ -357,7 +435,9 @@ int wmi_echo(struct wil6210_priv *wil);
|
|||
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
|
||||
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
|
||||
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
|
||||
int wmi_rxon(struct wil6210_priv *wil, bool on);
|
||||
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
|
||||
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
|
||||
|
||||
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
|
||||
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
|
||||
|
|
|
@ -307,14 +307,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
|
|||
u32 freq = ieee80211_channel_to_frequency(ch_no,
|
||||
IEEE80211_BAND_60GHZ);
|
||||
struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq);
|
||||
/* TODO convert LE to CPU */
|
||||
s32 signal = 0; /* TODO */
|
||||
s32 signal = data->info.sqi;
|
||||
__le16 fc = rx_mgmt_frame->frame_control;
|
||||
u32 d_len = le32_to_cpu(data->info.len);
|
||||
u16 d_status = le16_to_cpu(data->info.status);
|
||||
|
||||
wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n",
|
||||
data->info.channel, data->info.mcs, data->info.snr);
|
||||
wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n",
|
||||
data->info.channel, data->info.mcs, data->info.snr,
|
||||
data->info.sqi);
|
||||
wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
|
||||
le16_to_cpu(fc));
|
||||
wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
|
||||
|
@ -384,6 +384,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
|||
evt->assoc_req_len, evt->assoc_resp_len);
|
||||
return;
|
||||
}
|
||||
if (evt->cid >= WIL6210_MAX_CID) {
|
||||
wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
|
||||
return;
|
||||
}
|
||||
|
||||
ch = evt->channel + 1;
|
||||
wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
|
||||
evt->bssid, ch, evt->cid);
|
||||
|
@ -439,7 +444,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
|||
|
||||
/* FIXME FW can transmit only ucast frames to peer */
|
||||
/* FIXME real ring_id instead of hard coded 0 */
|
||||
memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
|
||||
memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN);
|
||||
wil->sta[evt->cid].status = wil_sta_conn_pending;
|
||||
|
||||
wil->pending_connect_cid = evt->cid;
|
||||
queue_work(wil->wmi_wq_conn, &wil->connect_worker);
|
||||
|
@ -476,11 +482,11 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
|
|||
wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
|
||||
wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
|
||||
wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
|
||||
"BF status 0x%08x SNR 0x%08x\n"
|
||||
"BF status 0x%08x SNR 0x%08x SQI %d%%\n"
|
||||
"Tx Tpt %d goodput %d Rx goodput %d\n"
|
||||
"Sectors(rx:tx) my %d:%d peer %d:%d\n",
|
||||
wil->stats.bf_mcs, wil->stats.tsf, evt->status,
|
||||
wil->stats.snr, le32_to_cpu(evt->tx_tpt),
|
||||
wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt),
|
||||
le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
|
||||
wil->stats.my_rx_sector, wil->stats.my_tx_sector,
|
||||
wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
|
||||
|
@ -499,10 +505,16 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
|
|||
int sz = eapol_len + ETH_HLEN;
|
||||
struct sk_buff *skb;
|
||||
struct ethhdr *eth;
|
||||
int cid;
|
||||
struct wil_net_stats *stats = NULL;
|
||||
|
||||
wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
|
||||
evt->src_mac);
|
||||
|
||||
cid = wil_find_cid(wil, evt->src_mac);
|
||||
if (cid >= 0)
|
||||
stats = &wil->sta[cid].stats;
|
||||
|
||||
if (eapol_len > 196) { /* TODO: revisit size limit */
|
||||
wil_err(wil, "EAPOL too large\n");
|
||||
return;
|
||||
|
@ -513,6 +525,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
|
|||
wil_err(wil, "Failed to allocate skb\n");
|
||||
return;
|
||||
}
|
||||
|
||||
eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);
|
||||
memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);
|
||||
memcpy(eth->h_source, evt->src_mac, ETH_ALEN);
|
||||
|
@ -521,9 +534,15 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
|
|||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
|
||||
ndev->stats.rx_packets++;
|
||||
ndev->stats.rx_bytes += skb->len;
|
||||
ndev->stats.rx_bytes += sz;
|
||||
if (stats) {
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += sz;
|
||||
}
|
||||
} else {
|
||||
ndev->stats.rx_dropped++;
|
||||
if (stats)
|
||||
stats->rx_dropped++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,10 +571,42 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
|
|||
int len)
|
||||
{
|
||||
struct wmi_vring_ba_status_event *evt = d;
|
||||
struct wil_sta_info *sta;
|
||||
uint i, cid;
|
||||
|
||||
/* TODO: use Rx BA status, not Tx one */
|
||||
|
||||
wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
|
||||
evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize,
|
||||
__le16_to_cpu(evt->ba_timeout));
|
||||
evt->ringid,
|
||||
evt->status == WMI_BA_AGREED ? "OK" : "N/A",
|
||||
evt->agg_wsize, __le16_to_cpu(evt->ba_timeout));
|
||||
|
||||
if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
|
||||
wil_err(wil, "invalid ring id %d\n", evt->ringid);
|
||||
return;
|
||||
}
|
||||
|
||||
cid = wil->vring2cid_tid[evt->ringid][0];
|
||||
if (cid >= WIL6210_MAX_CID) {
|
||||
wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
|
||||
return;
|
||||
}
|
||||
|
||||
sta = &wil->sta[cid];
|
||||
if (sta->status == wil_sta_unused) {
|
||||
wil_err(wil, "CID %d unused\n", cid);
|
||||
return;
|
||||
}
|
||||
|
||||
wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
|
||||
for (i = 0; i < WIL_STA_TID_NUM; i++) {
|
||||
struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
|
||||
sta->tid_rx[i] = NULL;
|
||||
wil_tid_ampdu_rx_free(wil, r);
|
||||
if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
|
||||
sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
|
||||
evt->agg_wsize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct {
|
||||
|
@ -893,6 +944,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* wmi_rxon - turn radio on/off
|
||||
* @on: turn on if true, off otherwise
|
||||
*
|
||||
* Only switch radio. Channel should be set separately.
|
||||
* No timeout for rxon - radio turned on forever unless some other call
|
||||
* turns it off
|
||||
*/
|
||||
int wmi_rxon(struct wil6210_priv *wil, bool on)
|
||||
{
|
||||
int rc;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_listen_started_event evt;
|
||||
} __packed reply;
|
||||
|
||||
wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off");
|
||||
|
||||
if (on) {
|
||||
rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
|
||||
WMI_LISTEN_STARTED_EVENTID,
|
||||
&reply, sizeof(reply), 100);
|
||||
if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
|
||||
rc = -EINVAL;
|
||||
} else {
|
||||
rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
|
||||
WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
|
||||
{
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
|
@ -906,6 +989,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
|
|||
},
|
||||
.mid = 0, /* TODO - what is it? */
|
||||
.decap_trans_type = WMI_DECAP_TYPE_802_3,
|
||||
.reorder_type = WMI_RX_SW_REORDER,
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
|
@ -973,6 +1057,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
|
||||
{
|
||||
struct wmi_disconnect_sta_cmd cmd = {
|
||||
.disconnect_reason = cpu_to_le16(reason),
|
||||
};
|
||||
memcpy(cmd.dst_mac, mac, ETH_ALEN);
|
||||
|
||||
wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason);
|
||||
|
||||
return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
void wmi_event_flush(struct wil6210_priv *wil)
|
||||
{
|
||||
struct pending_wmi_event *evt, *t;
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "atmel.h"
|
||||
|
||||
#define DRIVER_MAJOR 0
|
||||
|
@ -2273,7 +2273,7 @@ static int atmel_set_freq(struct net_device *dev,
|
|||
|
||||
/* Hack to fall through... */
|
||||
fwrq->e = 0;
|
||||
fwrq->m = ieee80211_freq_to_dsss_chan(f);
|
||||
fwrq->m = ieee80211_frequency_to_channel(f);
|
||||
}
|
||||
/* Setting by channel number */
|
||||
if ((fwrq->m > 1000) || (fwrq->e > 0))
|
||||
|
@ -2434,8 +2434,8 @@ static int atmel_get_range(struct net_device *dev,
|
|||
range->freq[k].i = i; /* List index */
|
||||
|
||||
/* Values in MHz -> * 10^5 * 10 */
|
||||
range->freq[k].m = (ieee80211_dsss_chan_to_freq(i) *
|
||||
100000);
|
||||
range->freq[k].m = 100000 *
|
||||
ieee80211_channel_to_frequency(i, IEEE80211_BAND_2GHZ);
|
||||
range->freq[k++].e = 1;
|
||||
}
|
||||
range->num_frequency = k;
|
||||
|
|
|
@ -92,7 +92,7 @@ config B43_SDIO
|
|||
# if we can do DMA.
|
||||
config B43_BCMA_PIO
|
||||
bool
|
||||
depends on B43_BCMA
|
||||
depends on B43 && B43_BCMA
|
||||
select BCMA_BLOCKIO
|
||||
default y
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev,
|
|||
|
||||
static inline bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void b43_debugfs_init(void)
|
||||
|
|
|
@ -1549,7 +1549,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
|
|||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
|
||||
|
||||
bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
|
||||
len = min((size_t) dev->wl->current_beacon->len,
|
||||
len = min_t(size_t, dev->wl->current_beacon->len,
|
||||
0x200 - sizeof(struct b43_plcp_hdr6));
|
||||
rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
|
||||
|
||||
|
|
|
@ -133,9 +133,9 @@ void b43_phy_exit(struct b43_wldev *dev)
|
|||
bool b43_has_hardware_pctl(struct b43_wldev *dev)
|
||||
{
|
||||
if (!dev->phy.hardware_power_control)
|
||||
return 0;
|
||||
return false;
|
||||
if (!dev->phy.ops->supports_hwpctl)
|
||||
return 0;
|
||||
return false;
|
||||
return dev->phy.ops->supports_hwpctl(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -637,7 +637,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
|
|||
|
||||
ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
|
||||
if (!(ctl & B43_PIO8_RXCTL_FRAMERDY))
|
||||
return 0;
|
||||
return false;
|
||||
b43_piorx_write32(q, B43_PIO8_RXCTL,
|
||||
B43_PIO8_RXCTL_FRAMERDY);
|
||||
for (i = 0; i < 10; i++) {
|
||||
|
@ -651,7 +651,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
|
|||
|
||||
ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
|
||||
if (!(ctl & B43_PIO_RXCTL_FRAMERDY))
|
||||
return 0;
|
||||
return false;
|
||||
b43_piorx_write16(q, B43_PIO_RXCTL,
|
||||
B43_PIO_RXCTL_FRAMERDY);
|
||||
for (i = 0; i < 10; i++) {
|
||||
|
@ -662,7 +662,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
|
|||
}
|
||||
}
|
||||
b43dbg(q->dev->wl, "PIO RX timed out\n");
|
||||
return 1;
|
||||
return true;
|
||||
data_ready:
|
||||
|
||||
/* Get the preamble (RX header) */
|
||||
|
@ -759,7 +759,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
|
|||
|
||||
b43_rx(q->dev, skb, rxhdr);
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
rx_error:
|
||||
if (err_msg)
|
||||
|
@ -769,7 +769,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
|
|||
else
|
||||
b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY);
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
void b43_pio_rx(struct b43_pio_rxqueue *q)
|
||||
|
|
|
@ -40,7 +40,7 @@ static int get_integer(const char *buf, size_t count)
|
|||
|
||||
if (count == 0)
|
||||
goto out;
|
||||
count = min(count, (size_t) 10);
|
||||
count = min_t(size_t, count, 10);
|
||||
memcpy(tmp, buf, count);
|
||||
ret = simple_strtol(tmp, NULL, 10);
|
||||
out:
|
||||
|
|
|
@ -337,7 +337,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
|
|||
/* iv16 */
|
||||
memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3);
|
||||
} else {
|
||||
iv_len = min((size_t) info->control.hw_key->iv_len,
|
||||
iv_len = min_t(size_t, info->control.hw_key->iv_len,
|
||||
ARRAY_SIZE(txhdr->iv));
|
||||
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
|
||||
}
|
||||
|
|
|
@ -978,7 +978,7 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
|
|||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
|
||||
|
||||
bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
|
||||
len = min((size_t)dev->wl->current_beacon->len,
|
||||
len = min_t(size_t, dev->wl->current_beacon->len,
|
||||
0x200 - sizeof(struct b43legacy_plcp_hdr6));
|
||||
rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
|
||||
|
||||
|
@ -1155,7 +1155,7 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
|
|||
b43legacy_write_probe_resp_plcp(dev, 0x350, size,
|
||||
&b43legacy_b_ratetable[3]);
|
||||
|
||||
size = min((size_t)size,
|
||||
size = min_t(size_t, size,
|
||||
0x200 - sizeof(struct b43legacy_plcp_hdr6));
|
||||
b43legacy_write_template_common(dev, probe_resp_data,
|
||||
size, ram_offset,
|
||||
|
|
|
@ -42,7 +42,7 @@ static int get_integer(const char *buf, size_t count)
|
|||
|
||||
if (count == 0)
|
||||
goto out;
|
||||
count = min(count, (size_t)10);
|
||||
count = min_t(size_t, count, 10);
|
||||
memcpy(tmp, buf, count);
|
||||
ret = simple_strtol(tmp, NULL, 10);
|
||||
out:
|
||||
|
|
|
@ -254,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
|
|||
B43legacy_TX4_MAC_KEYALG_SHIFT) &
|
||||
B43legacy_TX4_MAC_KEYALG;
|
||||
wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control);
|
||||
iv_len = min((size_t)info->control.hw_key->iv_len,
|
||||
iv_len = min_t(size_t, info->control.hw_key->iv_len,
|
||||
ARRAY_SIZE(txhdr->iv));
|
||||
memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
|
||||
} else {
|
||||
|
|
|
@ -53,6 +53,12 @@
|
|||
/* Maximum milliseconds to wait for F2 to come up */
|
||||
#define SDIO_WAIT_F2RDY 3000
|
||||
|
||||
#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
|
||||
#define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */
|
||||
|
||||
static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
|
||||
module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
|
||||
MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
|
||||
|
||||
static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
|
||||
{
|
||||
|
@ -487,7 +493,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
|
|||
struct mmc_request mmc_req;
|
||||
struct mmc_command mmc_cmd;
|
||||
struct mmc_data mmc_dat;
|
||||
struct sg_table st;
|
||||
struct scatterlist *sgl;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -532,16 +537,11 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
|
|||
pkt_offset = 0;
|
||||
pkt_next = target_list->next;
|
||||
|
||||
if (sg_alloc_table(&st, max_seg_cnt, GFP_KERNEL)) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(&mmc_req, 0, sizeof(struct mmc_request));
|
||||
memset(&mmc_cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&mmc_dat, 0, sizeof(struct mmc_data));
|
||||
|
||||
mmc_dat.sg = st.sgl;
|
||||
mmc_dat.sg = sdiodev->sgtable.sgl;
|
||||
mmc_dat.blksz = func_blk_sz;
|
||||
mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
|
||||
mmc_cmd.opcode = SD_IO_RW_EXTENDED;
|
||||
|
@ -557,7 +557,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
|
|||
while (seg_sz) {
|
||||
req_sz = 0;
|
||||
sg_cnt = 0;
|
||||
sgl = st.sgl;
|
||||
sgl = sdiodev->sgtable.sgl;
|
||||
/* prep sg table */
|
||||
while (pkt_next != (struct sk_buff *)target_list) {
|
||||
pkt_data = pkt_next->data + pkt_offset;
|
||||
|
@ -639,7 +639,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
|
|||
}
|
||||
|
||||
exit:
|
||||
sg_free_table(&st);
|
||||
sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents);
|
||||
while ((pkt_next = __skb_dequeue(&local_list)) != NULL)
|
||||
brcmu_pkt_buf_free_skb(pkt_next);
|
||||
|
||||
|
@ -863,6 +863,29 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
uint nents;
|
||||
int err;
|
||||
|
||||
if (!sdiodev->sg_support)
|
||||
return;
|
||||
|
||||
nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz);
|
||||
nents += (nents >> 4) + 1;
|
||||
|
||||
WARN_ON(nents > sdiodev->max_segment_count);
|
||||
|
||||
brcmf_dbg(TRACE, "nents=%d\n", nents);
|
||||
err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL);
|
||||
if (err < 0) {
|
||||
brcmf_err("allocation failed: disable scatter-gather");
|
||||
sdiodev->sg_support = false;
|
||||
}
|
||||
|
||||
sdiodev->txglomsz = brcmf_sdiod_txglomsz;
|
||||
}
|
||||
|
||||
static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
|
||||
{
|
||||
if (sdiodev->bus) {
|
||||
|
@ -880,6 +903,7 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
|
|||
sdio_disable_func(sdiodev->func[1]);
|
||||
sdio_release_host(sdiodev->func[1]);
|
||||
|
||||
sg_free_table(&sdiodev->sgtable);
|
||||
sdiodev->sbwad = 0;
|
||||
|
||||
return 0;
|
||||
|
@ -935,6 +959,11 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
|
|||
SG_MAX_SINGLE_ALLOC);
|
||||
sdiodev->max_segment_size = host->max_seg_size;
|
||||
|
||||
/* allocate scatter-gather table. sg support
|
||||
* will be disabled upon allocation failure.
|
||||
*/
|
||||
brcmf_sdiod_sgtable_alloc(sdiodev);
|
||||
|
||||
/* try to attach to the target device */
|
||||
sdiodev->bus = brcmf_sdio_probe(sdiodev);
|
||||
if (!sdiodev->bus) {
|
||||
|
@ -1072,9 +1101,7 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
|
|||
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
|
||||
int ret = 0;
|
||||
|
||||
brcmf_dbg(SDIO, "\n");
|
||||
|
||||
atomic_set(&sdiodev->suspend, true);
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
|
||||
sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
|
||||
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
|
||||
|
@ -1082,9 +1109,12 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
atomic_set(&sdiodev->suspend, true);
|
||||
|
||||
ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
|
||||
if (ret) {
|
||||
brcmf_err("Failed to set pm_flags\n");
|
||||
atomic_set(&sdiodev->suspend, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1098,6 +1128,7 @@ static int brcmf_ops_sdio_resume(struct device *dev)
|
|||
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
||||
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
|
||||
|
||||
brcmf_dbg(SDIO, "Enter\n");
|
||||
brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
|
||||
atomic_set(&sdiodev->suspend, false);
|
||||
return 0;
|
||||
|
|
|
@ -1040,12 +1040,12 @@ void brcmf_detach(struct device *dev)
|
|||
|
||||
brcmf_cfg80211_detach(drvr->config);
|
||||
|
||||
brcmf_fws_deinit(drvr);
|
||||
|
||||
brcmf_bus_detach(drvr);
|
||||
|
||||
brcmf_proto_detach(drvr);
|
||||
|
||||
brcmf_fws_deinit(drvr);
|
||||
|
||||
brcmf_debugfs_detach(drvr);
|
||||
bus_if->drvr = NULL;
|
||||
kfree(drvr);
|
||||
|
|
|
@ -113,8 +113,6 @@ struct rte_console {
|
|||
#define BRCMF_TXBOUND 20 /* Default for max tx frames in
|
||||
one scheduling */
|
||||
|
||||
#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */
|
||||
|
||||
#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */
|
||||
|
||||
#define MEMBLOCK 2048 /* Block size used for downloading
|
||||
|
@ -304,7 +302,6 @@ struct rte_console {
|
|||
/* Flags for SDH calls */
|
||||
#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
|
||||
|
||||
#define BRCMF_IDLE_IMMEDIATE (-1) /* Enter idle immediately */
|
||||
#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change
|
||||
* when idle
|
||||
*/
|
||||
|
@ -511,10 +508,6 @@ static const uint max_roundup = 512;
|
|||
|
||||
#define ALIGNMENT 4
|
||||
|
||||
static int brcmf_sdio_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
|
||||
module_param_named(txglomsz, brcmf_sdio_txglomsz, int, 0);
|
||||
MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
|
||||
|
||||
enum brcmf_sdio_frmtype {
|
||||
BRCMF_SDIO_FT_NORMAL,
|
||||
BRCMF_SDIO_FT_SUPER,
|
||||
|
@ -770,8 +763,6 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
|
|||
return err;
|
||||
}
|
||||
|
||||
#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
|
||||
|
||||
#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
|
||||
|
||||
/* Turn backplane clock on or off */
|
||||
|
@ -870,7 +861,6 @@ static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
|
|||
}
|
||||
#endif /* defined (DEBUG) */
|
||||
|
||||
bus->activity = true;
|
||||
} else {
|
||||
clkreq = 0;
|
||||
|
||||
|
@ -1240,6 +1230,28 @@ static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
|
|||
bus->cur_read.len = 0;
|
||||
}
|
||||
|
||||
static void brcmf_sdio_txfail(struct brcmf_sdio *bus)
|
||||
{
|
||||
struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
|
||||
u8 i, hi, lo;
|
||||
|
||||
/* On failure, abort the command and terminate the frame */
|
||||
brcmf_err("sdio error, abort command and terminate frame\n");
|
||||
bus->sdcnt.tx_sderrs++;
|
||||
|
||||
brcmf_sdiod_abort(sdiodev, SDIO_FUNC_2);
|
||||
brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL);
|
||||
bus->sdcnt.f1regdata++;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
hi = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL);
|
||||
lo = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL);
|
||||
bus->sdcnt.f1regdata += 2;
|
||||
if ((hi == 0) && (lo == 0))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* return total length of buffer chain */
|
||||
static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)
|
||||
{
|
||||
|
@ -2110,7 +2122,7 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
|
|||
memcpy(pkt_pad->data,
|
||||
pkt->data + pkt->len - tail_chop,
|
||||
tail_chop);
|
||||
*(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
|
||||
*(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
|
||||
skb_trim(pkt, pkt->len - tail_chop);
|
||||
skb_trim(pkt_pad, tail_pad + tail_chop);
|
||||
__skb_queue_after(pktq, pkt, pkt_pad);
|
||||
|
@ -2158,7 +2170,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
|
|||
* already properly aligned and does not
|
||||
* need an sdpcm header.
|
||||
*/
|
||||
if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
|
||||
if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
|
||||
continue;
|
||||
|
||||
/* align packet data pointer */
|
||||
|
@ -2192,10 +2204,10 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
|
|||
if (BRCMF_BYTES_ON() &&
|
||||
((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
|
||||
(BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
|
||||
brcmf_dbg_hex_dump(true, pkt_next, hd_info.len,
|
||||
brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len,
|
||||
"Tx Frame:\n");
|
||||
else if (BRCMF_HDRS_ON())
|
||||
brcmf_dbg_hex_dump(true, pkt_next,
|
||||
brcmf_dbg_hex_dump(true, pkt_next->data,
|
||||
head_pad + bus->tx_hdrlen,
|
||||
"Tx Header:\n");
|
||||
}
|
||||
|
@ -2222,11 +2234,11 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
|
|||
u8 *hdr;
|
||||
u32 dat_offset;
|
||||
u16 tail_pad;
|
||||
u32 dummy_flags, chop_len;
|
||||
u16 dummy_flags, chop_len;
|
||||
struct sk_buff *pkt_next, *tmp, *pkt_prev;
|
||||
|
||||
skb_queue_walk_safe(pktq, pkt_next, tmp) {
|
||||
dummy_flags = *(u32 *)(pkt_next->cb);
|
||||
dummy_flags = *(u16 *)(pkt_next->cb);
|
||||
if (dummy_flags & ALIGN_SKB_FLAG) {
|
||||
chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
|
||||
if (chop_len) {
|
||||
|
@ -2255,7 +2267,6 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
|
|||
uint chan)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
struct sk_buff *pkt_next, *tmp;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
@ -2268,28 +2279,9 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
|
|||
ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
|
||||
bus->sdcnt.f2txdata++;
|
||||
|
||||
if (ret < 0) {
|
||||
/* On failure, abort the command and terminate the frame */
|
||||
brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
|
||||
ret);
|
||||
bus->sdcnt.tx_sderrs++;
|
||||
if (ret < 0)
|
||||
brcmf_sdio_txfail(bus);
|
||||
|
||||
brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
|
||||
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
|
||||
SFC_WF_TERM, NULL);
|
||||
bus->sdcnt.f1regdata++;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
u8 hi, lo;
|
||||
hi = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_FUNC1_WFRAMEBCHI, NULL);
|
||||
lo = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_FUNC1_WFRAMEBCLO, NULL);
|
||||
bus->sdcnt.f1regdata += 2;
|
||||
if ((hi == 0) && (lo == 0))
|
||||
break;
|
||||
}
|
||||
}
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
|
||||
done:
|
||||
|
@ -2322,7 +2314,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
|
|||
__skb_queue_head_init(&pktq);
|
||||
if (bus->txglom)
|
||||
pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
|
||||
brcmf_sdio_txglomsz);
|
||||
bus->sdiodev->txglomsz);
|
||||
pkt_num = min_t(u32, pkt_num,
|
||||
brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol));
|
||||
spin_lock_bh(&bus->txqlock);
|
||||
|
@ -2341,7 +2333,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
|
|||
cnt += i;
|
||||
|
||||
/* In poll mode, need to check for other events */
|
||||
if (!bus->intr && cnt) {
|
||||
if (!bus->intr) {
|
||||
/* Check device status, signal pending interrupt */
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
ret = r_sdreg32(bus, &intstatus,
|
||||
|
@ -2447,12 +2439,21 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
|
|||
}
|
||||
}
|
||||
|
||||
static void atomic_orr(int val, atomic_t *v)
|
||||
{
|
||||
int old_val;
|
||||
|
||||
old_val = atomic_read(v);
|
||||
while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
|
||||
old_val = atomic_read(v);
|
||||
}
|
||||
|
||||
static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
|
||||
{
|
||||
struct brcmf_core *buscore;
|
||||
u32 addr;
|
||||
unsigned long val;
|
||||
int n, ret;
|
||||
int ret;
|
||||
|
||||
buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
|
||||
addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
|
||||
|
@ -2460,7 +2461,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
|
|||
val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
|
||||
bus->sdcnt.f1regdata++;
|
||||
if (ret != 0)
|
||||
val = 0;
|
||||
return ret;
|
||||
|
||||
val &= bus->hostintmask;
|
||||
atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
|
||||
|
@ -2469,13 +2470,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
|
|||
if (val) {
|
||||
brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
|
||||
bus->sdcnt.f1regdata++;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
atomic_set(&bus->intstatus, 0);
|
||||
} else if (val) {
|
||||
for_each_set_bit(n, &val, 32)
|
||||
set_bit(n, (unsigned long *)&bus->intstatus.counter);
|
||||
atomic_orr(val, &bus->intstatus);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -2485,10 +2480,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
|||
{
|
||||
u32 newstatus = 0;
|
||||
unsigned long intstatus;
|
||||
uint rxlimit = bus->rxbound; /* Rx frames to read before resched */
|
||||
uint txlimit = bus->txbound; /* Tx frames to send before resched */
|
||||
uint framecnt = 0; /* Temporary counter of tx/rx frames */
|
||||
int err = 0, n;
|
||||
uint framecnt; /* Temporary counter of tx/rx frames */
|
||||
int err = 0;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
|
@ -2585,58 +2579,30 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
|||
intstatus &= ~I_HMB_FRAME_IND;
|
||||
|
||||
/* On frame indication, read available frames */
|
||||
if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) {
|
||||
framecnt = brcmf_sdio_readframes(bus, rxlimit);
|
||||
if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) {
|
||||
brcmf_sdio_readframes(bus, bus->rxbound);
|
||||
if (!bus->rxpending)
|
||||
intstatus &= ~I_HMB_FRAME_IND;
|
||||
rxlimit -= min(framecnt, rxlimit);
|
||||
}
|
||||
|
||||
/* Keep still-pending events for next scheduling */
|
||||
if (intstatus) {
|
||||
for_each_set_bit(n, &intstatus, 32)
|
||||
set_bit(n, (unsigned long *)&bus->intstatus.counter);
|
||||
}
|
||||
if (intstatus)
|
||||
atomic_orr(intstatus, &bus->intstatus);
|
||||
|
||||
brcmf_sdio_clrintr(bus);
|
||||
|
||||
if (data_ok(bus) && bus->ctrl_frame_stat &&
|
||||
(bus->clkstate == CLK_AVAIL)) {
|
||||
int i;
|
||||
(bus->clkstate == CLK_AVAIL)) {
|
||||
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
err = brcmf_sdiod_send_buf(bus->sdiodev, bus->ctrl_frame_buf,
|
||||
(u32)bus->ctrl_frame_len);
|
||||
|
||||
if (err < 0) {
|
||||
/* On failure, abort the command and
|
||||
terminate the frame */
|
||||
brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
|
||||
err);
|
||||
bus->sdcnt.tx_sderrs++;
|
||||
|
||||
brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
|
||||
|
||||
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
|
||||
SFC_WF_TERM, &err);
|
||||
bus->sdcnt.f1regdata++;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
u8 hi, lo;
|
||||
hi = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_FUNC1_WFRAMEBCHI,
|
||||
&err);
|
||||
lo = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_FUNC1_WFRAMEBCLO,
|
||||
&err);
|
||||
bus->sdcnt.f1regdata += 2;
|
||||
if ((hi == 0) && (lo == 0))
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (err < 0)
|
||||
brcmf_sdio_txfail(bus);
|
||||
else
|
||||
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
|
||||
}
|
||||
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
bus->ctrl_frame_stat = false;
|
||||
brcmf_sdio_wait_event_wakeup(bus);
|
||||
|
@ -2647,8 +2613,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
|||
&& data_ok(bus)) {
|
||||
framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :
|
||||
txlimit;
|
||||
framecnt = brcmf_sdio_sendfromq(bus, framecnt);
|
||||
txlimit -= framecnt;
|
||||
brcmf_sdio_sendfromq(bus, framecnt);
|
||||
}
|
||||
|
||||
if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
|
||||
|
@ -2658,19 +2623,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
|
|||
atomic_read(&bus->ipend) > 0 ||
|
||||
(!atomic_read(&bus->fcstate) &&
|
||||
brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
|
||||
data_ok(bus)) || PKT_AVAILABLE()) {
|
||||
data_ok(bus))) {
|
||||
atomic_inc(&bus->dpc_tskcnt);
|
||||
}
|
||||
|
||||
/* If we're done for now, turn off clock request. */
|
||||
if ((bus->clkstate != CLK_PENDING)
|
||||
&& bus->idletime == BRCMF_IDLE_IMMEDIATE) {
|
||||
bus->activity = false;
|
||||
brcmf_dbg(SDIO, "idle state\n");
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
brcmf_sdio_bus_sleep(bus, true, false);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
|
||||
|
@ -2685,15 +2640,13 @@ static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
|
|||
static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
|
||||
{
|
||||
int ret = -EBADE;
|
||||
uint datalen, prec;
|
||||
uint prec;
|
||||
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
||||
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
|
||||
struct brcmf_sdio *bus = sdiodev->bus;
|
||||
ulong flags;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
datalen = pkt->len;
|
||||
brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
|
||||
|
||||
/* Add space for the header */
|
||||
skb_push(pkt, bus->tx_hdrlen);
|
||||
|
@ -2708,6 +2661,8 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
|
|||
|
||||
/* Priority based enq */
|
||||
spin_lock_irqsave(&bus->txqlock, flags);
|
||||
/* reset bus_flags in packet cb */
|
||||
*(u16 *)(pkt->cb) = 0;
|
||||
if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
|
||||
skb_pull(pkt, bus->tx_hdrlen);
|
||||
brcmf_err("out of bus->txq !!!\n");
|
||||
|
@ -2817,38 +2772,15 @@ static int brcmf_sdio_readconsole(struct brcmf_sdio *bus)
|
|||
|
||||
static int brcmf_sdio_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
bus->ctrl_frame_stat = false;
|
||||
ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len);
|
||||
|
||||
if (ret < 0) {
|
||||
/* On failure, abort the command and terminate the frame */
|
||||
brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
|
||||
ret);
|
||||
bus->sdcnt.tx_sderrs++;
|
||||
|
||||
brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
|
||||
|
||||
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
|
||||
SFC_WF_TERM, NULL);
|
||||
bus->sdcnt.f1regdata++;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
u8 hi, lo;
|
||||
hi = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_FUNC1_WFRAMEBCHI, NULL);
|
||||
lo = brcmf_sdiod_regrb(bus->sdiodev,
|
||||
SBSDIO_FUNC1_WFRAMEBCLO, NULL);
|
||||
bus->sdcnt.f1regdata += 2;
|
||||
if (hi == 0 && lo == 0)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
|
||||
if (ret < 0)
|
||||
brcmf_sdio_txfail(bus);
|
||||
else
|
||||
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -2947,15 +2879,6 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
|
|||
} while (ret < 0 && retries++ < TXRETRIES);
|
||||
}
|
||||
|
||||
if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) &&
|
||||
atomic_read(&bus->dpc_tskcnt) == 0) {
|
||||
bus->activity = false;
|
||||
sdio_claim_host(bus->sdiodev->func[1]);
|
||||
brcmf_dbg(INFO, "idle\n");
|
||||
brcmf_sdio_clkctl(bus, CLK_NONE, true);
|
||||
sdio_release_host(bus->sdiodev->func[1]);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
bus->sdcnt.tx_ctlerrs++;
|
||||
else
|
||||
|
@ -3753,8 +3676,8 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
|
|||
datawork);
|
||||
|
||||
while (atomic_read(&bus->dpc_tskcnt)) {
|
||||
atomic_set(&bus->dpc_tskcnt, 0);
|
||||
brcmf_sdio_dpc(bus);
|
||||
atomic_dec(&bus->dpc_tskcnt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -180,6 +180,8 @@ struct brcmf_sdio_dev {
|
|||
uint max_request_size;
|
||||
ushort max_segment_count;
|
||||
uint max_segment_size;
|
||||
uint txglomsz;
|
||||
struct sg_table sgtable;
|
||||
};
|
||||
|
||||
/* sdio core registers */
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
|
@ -251,6 +252,10 @@ struct parsed_vndr_ies {
|
|||
struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
|
||||
};
|
||||
|
||||
static int brcmf_roamoff;
|
||||
module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
|
||||
MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
|
||||
|
||||
/* Quarter dBm units to mW
|
||||
* Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
|
||||
* Table is offset so the last entry is largest mW value that fits in
|
||||
|
@ -4444,7 +4449,9 @@ static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
|
|||
u32 event = e->event_code;
|
||||
u16 flags = e->flags;
|
||||
|
||||
if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
|
||||
if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
|
||||
(event == BRCMF_E_DISASSOC_IND) ||
|
||||
((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
|
||||
brcmf_dbg(CONN, "Processing link down\n");
|
||||
return true;
|
||||
}
|
||||
|
@ -4688,6 +4695,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
|
|||
struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
|
||||
struct ieee80211_channel *chan;
|
||||
s32 err = 0;
|
||||
u16 reason;
|
||||
|
||||
if (ifp->vif->mode == WL_MODE_AP) {
|
||||
err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
|
||||
|
@ -4709,9 +4717,15 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
|
|||
if (!brcmf_is_ibssmode(ifp->vif)) {
|
||||
brcmf_bss_connect_done(cfg, ndev, e, false);
|
||||
if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
|
||||
&ifp->vif->sme_state))
|
||||
cfg80211_disconnected(ndev, 0, NULL, 0,
|
||||
&ifp->vif->sme_state)) {
|
||||
reason = 0;
|
||||
if (((e->event_code == BRCMF_E_DEAUTH_IND) ||
|
||||
(e->event_code == BRCMF_E_DISASSOC_IND)) &&
|
||||
(e->reason != WLAN_REASON_UNSPECIFIED))
|
||||
reason = e->reason;
|
||||
cfg80211_disconnected(ndev, reason, NULL, 0,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
brcmf_link_down(ifp->vif);
|
||||
brcmf_init_prof(ndev_to_prof(ndev));
|
||||
|
@ -4905,11 +4919,8 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
|
|||
|
||||
cfg->scan_request = NULL;
|
||||
cfg->pwr_save = true;
|
||||
cfg->roam_on = true; /* roam on & off switch.
|
||||
we enable roam per default */
|
||||
cfg->active_scan = true; /* we do active scan for
|
||||
specific scan per default */
|
||||
cfg->dongle_up = false; /* dongle is not up yet */
|
||||
cfg->active_scan = true; /* we do active scan per default */
|
||||
cfg->dongle_up = false; /* dongle is not up yet */
|
||||
err = brcmf_init_priv_mem(cfg);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -5029,7 +5040,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
|
|||
}
|
||||
|
||||
static s32
|
||||
brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
|
||||
brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
|
||||
{
|
||||
s32 err = 0;
|
||||
__le32 roamtrigger[2];
|
||||
|
@ -5039,7 +5050,7 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
|
|||
* Setup timeout if Beacons are lost and roam is
|
||||
* off to report link down
|
||||
*/
|
||||
if (roamvar) {
|
||||
if (brcmf_roamoff) {
|
||||
err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
|
||||
if (err) {
|
||||
brcmf_err("bcn_timeout error (%d)\n", err);
|
||||
|
@ -5051,8 +5062,9 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
|
|||
* Enable/Disable built-in roaming to allow supplicant
|
||||
* to take care of roaming
|
||||
*/
|
||||
brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
|
||||
err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
|
||||
brcmf_dbg(INFO, "Internal Roaming = %s\n",
|
||||
brcmf_roamoff ? "Off" : "On");
|
||||
err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
|
||||
if (err) {
|
||||
brcmf_err("roam_off error (%d)\n", err);
|
||||
goto dongle_rom_out;
|
||||
|
@ -5294,6 +5306,8 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
|
|||
u32 band_list[3];
|
||||
u32 nmode;
|
||||
u32 bw_cap[2] = { 0, 0 };
|
||||
u32 rxchain;
|
||||
u32 nchain;
|
||||
s8 phy;
|
||||
s32 err;
|
||||
u32 nband;
|
||||
|
@ -5330,6 +5344,16 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
|
|||
brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
|
||||
bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
|
||||
|
||||
err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
|
||||
if (err) {
|
||||
brcmf_err("rxchain error (%d)\n", err);
|
||||
nchain = 1;
|
||||
} else {
|
||||
for (nchain = 0; rxchain; nchain++)
|
||||
rxchain = rxchain & (rxchain - 1);
|
||||
}
|
||||
brcmf_dbg(INFO, "nchain=%d\n", nchain);
|
||||
|
||||
err = brcmf_construct_reginfo(cfg, bw_cap);
|
||||
if (err) {
|
||||
brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
|
||||
|
@ -5358,10 +5382,7 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
|
|||
band->ht_cap.ht_supported = true;
|
||||
band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
||||
band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
|
||||
/* An HT shall support all EQM rates for one spatial
|
||||
* stream
|
||||
*/
|
||||
band->ht_cap.mcs.rx_mask[0] = 0xff;
|
||||
memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
|
||||
band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
|
||||
bands[band->band] = band;
|
||||
}
|
||||
|
@ -5408,7 +5429,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
|
|||
brcmf_dbg(INFO, "power save set to %s\n",
|
||||
(power_mode ? "enabled" : "disabled"));
|
||||
|
||||
err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
|
||||
err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
|
||||
if (err)
|
||||
goto default_conf_out;
|
||||
err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
|
||||
|
|
|
@ -402,7 +402,6 @@ struct brcmf_cfg80211_info {
|
|||
bool ibss_starter;
|
||||
bool pwr_save;
|
||||
bool dongle_up;
|
||||
bool roam_on;
|
||||
bool scan_tried;
|
||||
u8 *dcmd_buf;
|
||||
u8 *extra_buf;
|
||||
|
|
|
@ -202,8 +202,8 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
|
|||
}
|
||||
|
||||
/* calculate the block size */
|
||||
tx_size = block_size = min((size_t)(firmware->size - put),
|
||||
(size_t)DOWNLOAD_BLOCK_SIZE);
|
||||
tx_size = block_size = min_t(size_t, firmware->size - put,
|
||||
DOWNLOAD_BLOCK_SIZE);
|
||||
|
||||
memcpy(buf, &firmware->data[put], block_size);
|
||||
if (block_size < DOWNLOAD_BLOCK_SIZE) {
|
||||
|
|
|
@ -677,6 +677,8 @@ static const struct pcmcia_device_id hostap_cs_ids[] = {
|
|||
PCMCIA_DEVICE_PROD_ID12(
|
||||
"ZoomAir 11Mbps High", "Rate wireless Networking",
|
||||
0x273fe3db, 0x32a1eaee),
|
||||
PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card",
|
||||
0xa37434e9, 0x9762e8f1),
|
||||
PCMCIA_DEVICE_PROD_ID123(
|
||||
"Pretec", "CompactWLAN Card 802.11b", "2.5",
|
||||
0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
|
||||
|
|
|
@ -7065,7 +7065,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev,
|
|||
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
|
||||
return -E2BIG;
|
||||
|
||||
wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
|
||||
wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
|
||||
memset(priv->nick, 0, sizeof(priv->nick));
|
||||
memcpy(priv->nick, extra, wrqu->data.length);
|
||||
|
||||
|
|
|
@ -9169,7 +9169,7 @@ static int ipw_wx_set_nick(struct net_device *dev,
|
|||
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
|
||||
return -E2BIG;
|
||||
mutex_lock(&priv->mutex);
|
||||
wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
|
||||
wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
|
||||
memset(priv->nick, 0, sizeof(priv->nick));
|
||||
memcpy(priv->nick, extra, wrqu->data.length);
|
||||
IPW_DEBUG_TRACE("<<\n");
|
||||
|
|
|
@ -1248,14 +1248,7 @@ il3945_rx_handle(struct il_priv *il)
|
|||
len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
|
||||
len += sizeof(u32); /* account for status word */
|
||||
|
||||
/* Reclaim a command buffer only if this packet is a response
|
||||
* to a (driver-originated) command.
|
||||
* If the packet (e.g. Rx frame) originated from uCode,
|
||||
* there is no command buffer to reclaim.
|
||||
* Ucode should set SEQ_RX_FRAME bit if ucode-originated,
|
||||
* but apparently a few don't get set; catch them here. */
|
||||
reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
|
||||
pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX;
|
||||
reclaim = il_need_reclaim(il, pkt);
|
||||
|
||||
/* Based on type of command response or notification,
|
||||
* handle those that need handling via function in
|
||||
|
@ -1495,12 +1488,14 @@ il3945_irq_tasklet(struct il_priv *il)
|
|||
if (inta & CSR_INT_BIT_WAKEUP) {
|
||||
D_ISR("Wakeup interrupt\n");
|
||||
il_rx_queue_update_write_ptr(il, &il->rxq);
|
||||
|
||||
spin_lock_irqsave(&il->lock, flags);
|
||||
il_txq_update_write_ptr(il, &il->txq[0]);
|
||||
il_txq_update_write_ptr(il, &il->txq[1]);
|
||||
il_txq_update_write_ptr(il, &il->txq[2]);
|
||||
il_txq_update_write_ptr(il, &il->txq[3]);
|
||||
il_txq_update_write_ptr(il, &il->txq[4]);
|
||||
il_txq_update_write_ptr(il, &il->txq[5]);
|
||||
spin_unlock_irqrestore(&il->lock, flags);
|
||||
|
||||
il->isr_stats.wakeup++;
|
||||
handled |= CSR_INT_BIT_WAKEUP;
|
||||
|
|
|
@ -92,7 +92,6 @@ il4965_check_abort_status(struct il_priv *il, u8 frame_count, u32 status)
|
|||
* EEPROM
|
||||
*/
|
||||
struct il_mod_params il4965_mod_params = {
|
||||
.amsdu_size_8K = 1,
|
||||
.restart_fw = 1,
|
||||
/* the rest are 0 by default */
|
||||
};
|
||||
|
@ -4274,17 +4273,7 @@ il4965_rx_handle(struct il_priv *il)
|
|||
len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
|
||||
len += sizeof(u32); /* account for status word */
|
||||
|
||||
/* Reclaim a command buffer only if this packet is a response
|
||||
* to a (driver-originated) command.
|
||||
* If the packet (e.g. Rx frame) originated from uCode,
|
||||
* there is no command buffer to reclaim.
|
||||
* Ucode should set SEQ_RX_FRAME bit if ucode-originated,
|
||||
* but apparently a few don't get set; catch them here. */
|
||||
reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
|
||||
(pkt->hdr.cmd != N_RX_PHY) && (pkt->hdr.cmd != N_RX) &&
|
||||
(pkt->hdr.cmd != N_RX_MPDU) &&
|
||||
(pkt->hdr.cmd != N_COMPRESSED_BA) &&
|
||||
(pkt->hdr.cmd != N_STATS) && (pkt->hdr.cmd != C_TX);
|
||||
reclaim = il_need_reclaim(il, pkt);
|
||||
|
||||
/* Based on type of command response or notification,
|
||||
* handle those that need handling via function in
|
||||
|
@ -6876,6 +6865,6 @@ module_param_named(11n_disable, il4965_mod_params.disable_11n, int, S_IRUGO);
|
|||
MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
|
||||
module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int,
|
||||
S_IRUGO);
|
||||
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
|
||||
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0 [disabled])");
|
||||
module_param_named(fw_restart, il4965_mod_params.restart_fw, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
|
||||
|
|
|
@ -2270,7 +2270,8 @@ struct il_spectrum_notification {
|
|||
*/
|
||||
#define IL_POWER_VEC_SIZE 5
|
||||
|
||||
#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(BIT(0))
|
||||
#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(BIT(0))
|
||||
#define IL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(BIT(2))
|
||||
#define IL_POWER_PCI_PM_MSK cpu_to_le16(BIT(3))
|
||||
|
||||
struct il3945_powertable_cmd {
|
||||
|
|
|
@ -1078,29 +1078,82 @@ EXPORT_SYMBOL(il_get_channel_info);
|
|||
* Setting power level allows the card to go to sleep when not busy.
|
||||
*
|
||||
* We calculate a sleep command based on the required latency, which
|
||||
* we get from mac80211. In order to handle thermal throttling, we can
|
||||
* also use pre-defined power levels.
|
||||
* we get from mac80211.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This defines the old power levels. They are still used by default
|
||||
* (level 1) and for thermal throttle (levels 3 through 5)
|
||||
*/
|
||||
|
||||
struct il_power_vec_entry {
|
||||
struct il_powertable_cmd cmd;
|
||||
u8 no_dtim; /* number of skip dtim */
|
||||
};
|
||||
#define SLP_VEC(X0, X1, X2, X3, X4) { \
|
||||
cpu_to_le32(X0), \
|
||||
cpu_to_le32(X1), \
|
||||
cpu_to_le32(X2), \
|
||||
cpu_to_le32(X3), \
|
||||
cpu_to_le32(X4) \
|
||||
}
|
||||
|
||||
static void
|
||||
il_power_sleep_cam_cmd(struct il_priv *il, struct il_powertable_cmd *cmd)
|
||||
il_build_powertable_cmd(struct il_priv *il, struct il_powertable_cmd *cmd)
|
||||
{
|
||||
const __le32 interval[3][IL_POWER_VEC_SIZE] = {
|
||||
SLP_VEC(2, 2, 4, 6, 0xFF),
|
||||
SLP_VEC(2, 4, 7, 10, 10),
|
||||
SLP_VEC(4, 7, 10, 10, 0xFF)
|
||||
};
|
||||
int i, dtim_period, no_dtim;
|
||||
u32 max_sleep;
|
||||
bool skip;
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
|
||||
if (il->power_data.pci_pm)
|
||||
cmd->flags |= IL_POWER_PCI_PM_MSK;
|
||||
|
||||
D_POWER("Sleep command for CAM\n");
|
||||
/* if no Power Save, we are done */
|
||||
if (il->power_data.ps_disabled)
|
||||
return;
|
||||
|
||||
cmd->flags = IL_POWER_DRIVER_ALLOW_SLEEP_MSK;
|
||||
cmd->keep_alive_seconds = 0;
|
||||
cmd->debug_flags = 0;
|
||||
cmd->rx_data_timeout = cpu_to_le32(25 * 1024);
|
||||
cmd->tx_data_timeout = cpu_to_le32(25 * 1024);
|
||||
cmd->keep_alive_beacons = 0;
|
||||
|
||||
dtim_period = il->vif ? il->vif->bss_conf.dtim_period : 0;
|
||||
|
||||
if (dtim_period <= 2) {
|
||||
memcpy(cmd->sleep_interval, interval[0], sizeof(interval[0]));
|
||||
no_dtim = 2;
|
||||
} else if (dtim_period <= 10) {
|
||||
memcpy(cmd->sleep_interval, interval[1], sizeof(interval[1]));
|
||||
no_dtim = 2;
|
||||
} else {
|
||||
memcpy(cmd->sleep_interval, interval[2], sizeof(interval[2]));
|
||||
no_dtim = 0;
|
||||
}
|
||||
|
||||
if (dtim_period == 0) {
|
||||
dtim_period = 1;
|
||||
skip = false;
|
||||
} else {
|
||||
skip = !!no_dtim;
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
__le32 tmp = cmd->sleep_interval[IL_POWER_VEC_SIZE - 1];
|
||||
|
||||
max_sleep = le32_to_cpu(tmp);
|
||||
if (max_sleep == 0xFF)
|
||||
max_sleep = dtim_period * (skip + 1);
|
||||
else if (max_sleep > dtim_period)
|
||||
max_sleep = (max_sleep / dtim_period) * dtim_period;
|
||||
cmd->flags |= IL_POWER_SLEEP_OVER_DTIM_MSK;
|
||||
} else {
|
||||
max_sleep = dtim_period;
|
||||
cmd->flags &= ~IL_POWER_SLEEP_OVER_DTIM_MSK;
|
||||
}
|
||||
|
||||
for (i = 0; i < IL_POWER_VEC_SIZE; i++)
|
||||
if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
|
||||
cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1173,7 +1226,8 @@ il_power_update_mode(struct il_priv *il, bool force)
|
|||
{
|
||||
struct il_powertable_cmd cmd;
|
||||
|
||||
il_power_sleep_cam_cmd(il, &cmd);
|
||||
il_build_powertable_cmd(il, &cmd);
|
||||
|
||||
return il_power_set_mode(il, &cmd, force);
|
||||
}
|
||||
EXPORT_SYMBOL(il_power_update_mode);
|
||||
|
@ -5081,6 +5135,7 @@ il_mac_config(struct ieee80211_hw *hw, u32 changed)
|
|||
}
|
||||
|
||||
if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) {
|
||||
il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS);
|
||||
ret = il_power_update_mode(il, false);
|
||||
if (ret)
|
||||
D_MAC80211("Error setting sleep level\n");
|
||||
|
|
|
@ -1123,6 +1123,7 @@ struct il_power_mgr {
|
|||
struct il_powertable_cmd sleep_cmd_next;
|
||||
int debug_sleep_level_override;
|
||||
bool pci_pm;
|
||||
bool ps_disabled;
|
||||
};
|
||||
|
||||
struct il_priv {
|
||||
|
@ -1597,7 +1598,7 @@ struct il_mod_params {
|
|||
int disable_hw_scan; /* def: 0 = use h/w scan */
|
||||
int num_of_queues; /* def: HW dependent */
|
||||
int disable_11n; /* def: 0 = 11n capabilities enabled */
|
||||
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
|
||||
int amsdu_size_8K; /* def: 0 = disable 8K amsdu size */
|
||||
int antenna; /* def: 0 = both antennas (use diversity) */
|
||||
int restart_fw; /* def: 1 = restart firmware */
|
||||
};
|
||||
|
@ -1978,6 +1979,20 @@ void il_wr_prph(struct il_priv *il, u32 addr, u32 val);
|
|||
u32 il_read_targ_mem(struct il_priv *il, u32 addr);
|
||||
void il_write_targ_mem(struct il_priv *il, u32 addr, u32 val);
|
||||
|
||||
static inline bool il_need_reclaim(struct il_priv *il, struct il_rx_pkt *pkt)
|
||||
{
|
||||
/* Reclaim a command buffer only if this packet is a response
|
||||
* to a (driver-originated) command. If the packet (e.g. Rx frame)
|
||||
* originated from uCode, there is no command buffer to reclaim.
|
||||
* Ucode should set SEQ_RX_FRAME bit if ucode-originated, but
|
||||
* apparently a few don't get set; catch them here.
|
||||
*/
|
||||
return !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
|
||||
pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX &&
|
||||
pkt->hdr.cmd != N_RX_PHY && pkt->hdr.cmd != N_RX &&
|
||||
pkt->hdr.cmd != N_RX_MPDU && pkt->hdr.cmd != N_COMPRESSED_BA;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_il_write8(struct il_priv *il, u32 ofs, u8 val)
|
||||
{
|
||||
|
|
|
@ -109,7 +109,7 @@ extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg;
|
|||
|
||||
struct iwl_ucode_capabilities;
|
||||
|
||||
extern struct ieee80211_ops iwlagn_hw_ops;
|
||||
extern const struct ieee80211_ops iwlagn_hw_ops;
|
||||
|
||||
static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
|
||||
{
|
||||
|
@ -480,7 +480,7 @@ do { \
|
|||
} while (0)
|
||||
#endif /* CONFIG_IWLWIFI_DEBUG */
|
||||
|
||||
extern const char *iwl_dvm_cmd_strings[REPLY_MAX];
|
||||
extern const char *const iwl_dvm_cmd_strings[REPLY_MAX];
|
||||
|
||||
static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
|
||||
{
|
||||
|
|
|
@ -317,7 +317,7 @@ static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
|
|||
.nrg_th_cca = 62,
|
||||
};
|
||||
|
||||
static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
|
||||
static const struct iwl_sensitivity_ranges iwl5150_sensitivity = {
|
||||
.min_nrg_cck = 95,
|
||||
.auto_corr_min_ofdm = 90,
|
||||
.auto_corr_min_ofdm_mrc = 170,
|
||||
|
|
|
@ -1582,7 +1582,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
|
|||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
}
|
||||
|
||||
struct ieee80211_ops iwlagn_hw_ops = {
|
||||
const struct ieee80211_ops iwlagn_hw_ops = {
|
||||
.tx = iwlagn_mac_tx,
|
||||
.start = iwlagn_mac_start,
|
||||
.stop = iwlagn_mac_stop,
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
#define IWL_CMD_ENTRY(x) [x] = #x
|
||||
|
||||
const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
|
||||
const char *const iwl_dvm_cmd_strings[REPLY_MAX] = {
|
||||
IWL_CMD_ENTRY(REPLY_ALIVE),
|
||||
IWL_CMD_ENTRY(REPLY_ERROR),
|
||||
IWL_CMD_ENTRY(REPLY_ECHO),
|
||||
|
|
|
@ -404,6 +404,38 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data,
|
||||
struct iwl_ucode_capabilities *capa)
|
||||
{
|
||||
const struct iwl_ucode_api *ucode_api = (void *)data;
|
||||
u32 api_index = le32_to_cpu(ucode_api->api_index);
|
||||
|
||||
if (api_index >= IWL_API_ARRAY_SIZE) {
|
||||
IWL_ERR(drv, "api_index larger than supported by driver\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
capa->api[api_index] = le32_to_cpu(ucode_api->api_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data,
|
||||
struct iwl_ucode_capabilities *capa)
|
||||
{
|
||||
const struct iwl_ucode_capa *ucode_capa = (void *)data;
|
||||
u32 api_index = le32_to_cpu(ucode_capa->api_index);
|
||||
|
||||
if (api_index >= IWL_CAPABILITIES_ARRAY_SIZE) {
|
||||
IWL_ERR(drv, "api_index larger than supported by driver\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
capa->capa[api_index] = le32_to_cpu(ucode_capa->api_capa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
|
||||
const struct firmware *ucode_raw,
|
||||
struct iwl_firmware_pieces *pieces)
|
||||
|
@ -638,6 +670,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
*/
|
||||
capa->flags = le32_to_cpup((__le32 *)tlv_data);
|
||||
break;
|
||||
case IWL_UCODE_TLV_API_CHANGES_SET:
|
||||
if (tlv_len != sizeof(struct iwl_ucode_api))
|
||||
goto invalid_tlv_len;
|
||||
if (iwl_set_ucode_api_flags(drv, tlv_data, capa))
|
||||
goto tlv_error;
|
||||
break;
|
||||
case IWL_UCODE_TLV_ENABLED_CAPABILITIES:
|
||||
if (tlv_len != sizeof(struct iwl_ucode_capa))
|
||||
goto invalid_tlv_len;
|
||||
if (iwl_set_ucode_capabilities(drv, tlv_data, capa))
|
||||
goto tlv_error;
|
||||
break;
|
||||
case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
|
||||
if (tlv_len != sizeof(u32))
|
||||
goto invalid_tlv_len;
|
||||
|
@ -728,6 +772,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
if (tlv_len != sizeof(u32))
|
||||
goto invalid_tlv_len;
|
||||
drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
|
||||
drv->fw.valid_tx_ant = (drv->fw.phy_config &
|
||||
FW_PHY_CFG_TX_CHAIN) >>
|
||||
FW_PHY_CFG_TX_CHAIN_POS;
|
||||
drv->fw.valid_rx_ant = (drv->fw.phy_config &
|
||||
FW_PHY_CFG_RX_CHAIN) >>
|
||||
FW_PHY_CFG_RX_CHAIN_POS;
|
||||
break;
|
||||
case IWL_UCODE_TLV_SECURE_SEC_RT:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
|
||||
|
@ -1301,8 +1351,7 @@ MODULE_PARM_DESC(antenna_coupling,
|
|||
|
||||
module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(wd_disable,
|
||||
"Disable stuck queue watchdog timer 0=system default, "
|
||||
"1=disable, 2=enable (default: 0)");
|
||||
"Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)");
|
||||
|
||||
module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(nvm_file, "NVM file name");
|
||||
|
|
|
@ -70,6 +70,20 @@
|
|||
#define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation"
|
||||
#define DRV_AUTHOR "<ilw@linux.intel.com>"
|
||||
|
||||
/* radio config bits (actual values from NVM definition) */
|
||||
#define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */
|
||||
#define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
|
||||
#define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
|
||||
#define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
|
||||
#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
|
||||
#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
|
||||
|
||||
#define NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(x) (x & 0xF)
|
||||
#define NVM_RF_CFG_DASH_MSK_FAMILY_8000(x) ((x >> 4) & 0xF)
|
||||
#define NVM_RF_CFG_STEP_MSK_FAMILY_8000(x) ((x >> 8) & 0xF)
|
||||
#define NVM_RF_CFG_TYPE_MSK_FAMILY_8000(x) ((x >> 12) & 0xFFF)
|
||||
#define NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(x) ((x >> 24) & 0xF)
|
||||
#define NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(x) ((x >> 28) & 0xF)
|
||||
|
||||
/**
|
||||
* DOC: Driver system flows - drv component
|
||||
|
|
|
@ -81,16 +81,17 @@ struct iwl_nvm_data {
|
|||
bool sku_cap_band_24GHz_enable;
|
||||
bool sku_cap_band_52GHz_enable;
|
||||
bool sku_cap_11n_enable;
|
||||
bool sku_cap_11ac_enable;
|
||||
bool sku_cap_amt_enable;
|
||||
bool sku_cap_ipan_enable;
|
||||
|
||||
u8 radio_cfg_type;
|
||||
u16 radio_cfg_type;
|
||||
u8 radio_cfg_step;
|
||||
u8 radio_cfg_dash;
|
||||
u8 radio_cfg_pnum;
|
||||
u8 valid_tx_ant, valid_rx_ant;
|
||||
|
||||
u16 nvm_version;
|
||||
u32 nvm_version;
|
||||
s8 max_tx_pwr_half_dbm;
|
||||
|
||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||
|
|
|
@ -126,6 +126,8 @@ enum iwl_ucode_tlv_type {
|
|||
IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
|
||||
IWL_UCODE_TLV_NUM_OF_CPU = 27,
|
||||
IWL_UCODE_TLV_CSCHEME = 28,
|
||||
IWL_UCODE_TLV_API_CHANGES_SET = 29,
|
||||
IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30,
|
||||
};
|
||||
|
||||
struct iwl_ucode_tlv {
|
||||
|
@ -158,4 +160,19 @@ struct iwl_tlv_ucode_header {
|
|||
u8 data[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* ucode TLVs
|
||||
*
|
||||
* ability to get extension for: flags & capabilities from ucode binaries files
|
||||
*/
|
||||
struct iwl_ucode_api {
|
||||
__le32 api_index;
|
||||
__le32 api_flags;
|
||||
} __packed;
|
||||
|
||||
struct iwl_ucode_capa {
|
||||
__le32 api_index;
|
||||
__le32 api_capa;
|
||||
} __packed;
|
||||
|
||||
#endif /* __iwl_fw_file_h__ */
|
||||
|
|
|
@ -92,8 +92,8 @@
|
|||
* @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
|
||||
* @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
|
||||
* containing CAM (Continuous Active Mode) indication.
|
||||
* @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
|
||||
* single bound interface).
|
||||
* @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and
|
||||
* P2P client interfaces simultaneously if they are in different bindings.
|
||||
* @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
|
||||
* @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
|
||||
* @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
|
||||
|
@ -118,7 +118,7 @@ enum iwl_ucode_tlv_flag {
|
|||
IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17),
|
||||
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19),
|
||||
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20),
|
||||
IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21),
|
||||
IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22),
|
||||
IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24),
|
||||
IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26),
|
||||
IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29),
|
||||
|
@ -165,11 +165,15 @@ enum iwl_ucode_sec {
|
|||
* just an offset to the HW address.
|
||||
*/
|
||||
#define IWL_UCODE_SECTION_MAX 12
|
||||
#define IWL_API_ARRAY_SIZE 1
|
||||
#define IWL_CAPABILITIES_ARRAY_SIZE 1
|
||||
|
||||
struct iwl_ucode_capabilities {
|
||||
u32 max_probe_length;
|
||||
u32 standard_phy_calibration_size;
|
||||
u32 flags;
|
||||
u32 api[IWL_API_ARRAY_SIZE];
|
||||
u32 capa[IWL_CAPABILITIES_ARRAY_SIZE];
|
||||
};
|
||||
|
||||
/* one for each uCode image (inst/data, init/runtime/wowlan) */
|
||||
|
@ -288,22 +292,12 @@ struct iwl_fw {
|
|||
|
||||
struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX];
|
||||
u32 phy_config;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
|
||||
bool mvm_fw;
|
||||
|
||||
struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
|
||||
};
|
||||
|
||||
static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
|
||||
{
|
||||
return (fw->phy_config & FW_PHY_CFG_TX_CHAIN) >>
|
||||
FW_PHY_CFG_TX_CHAIN_POS;
|
||||
}
|
||||
|
||||
static inline u8 iwl_fw_valid_rx_ant(const struct iwl_fw *fw)
|
||||
{
|
||||
return (fw->phy_config & FW_PHY_CFG_RX_CHAIN) >>
|
||||
FW_PHY_CFG_RX_CHAIN_POS;
|
||||
}
|
||||
|
||||
#endif /* __iwl_fw_h__ */
|
||||
|
|
|
@ -96,7 +96,7 @@ enum iwl_disable_11n {
|
|||
* use IWL_[DIS,EN]ABLE_HT_* constants
|
||||
* @amsdu_size_8K: enable 8K amsdu size, default = 0
|
||||
* @restart_fw: restart firmware, default = 1
|
||||
* @wd_disable: enable stuck queue check, default = 0
|
||||
* @wd_disable: disable stuck queue check, default = 1
|
||||
* @bt_coex_active: enable bt coex, default = true
|
||||
* @led_mode: system default, default = 0
|
||||
* @power_save: disable power save, default = false
|
||||
|
|
|
@ -71,7 +71,7 @@ enum wkp_nvm_offsets {
|
|||
/* NVM HW-Section offset (in words) definitions */
|
||||
HW_ADDR = 0x15,
|
||||
|
||||
/* NVM SW-Section offset (in words) definitions */
|
||||
/* NVM SW-Section offset (in words) definitions */
|
||||
NVM_SW_SECTION = 0x1C0,
|
||||
NVM_VERSION = 0,
|
||||
RADIO_CFG = 1,
|
||||
|
@ -79,11 +79,32 @@ enum wkp_nvm_offsets {
|
|||
N_HW_ADDRS = 3,
|
||||
NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
|
||||
|
||||
/* NVM calibration section offset (in words) definitions */
|
||||
/* NVM calibration section offset (in words) definitions */
|
||||
NVM_CALIB_SECTION = 0x2B8,
|
||||
XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
|
||||
};
|
||||
|
||||
enum family_8000_nvm_offsets {
|
||||
/* NVM HW-Section offset (in words) definitions */
|
||||
HW_ADDR0_FAMILY_8000 = 0x12,
|
||||
HW_ADDR1_FAMILY_8000 = 0x16,
|
||||
MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1,
|
||||
|
||||
/* NVM SW-Section offset (in words) definitions */
|
||||
NVM_SW_SECTION_FAMILY_8000 = 0x1C0,
|
||||
NVM_VERSION_FAMILY_8000 = 0,
|
||||
RADIO_CFG_FAMILY_8000 = 2,
|
||||
SKU_FAMILY_8000 = 4,
|
||||
N_HW_ADDRS_FAMILY_8000 = 5,
|
||||
|
||||
/* NVM REGULATORY -Section offset (in words) definitions */
|
||||
NVM_CHANNELS_FAMILY_8000 = 0,
|
||||
|
||||
/* NVM calibration section offset (in words) definitions */
|
||||
NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8,
|
||||
XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000
|
||||
};
|
||||
|
||||
/* SKU Capabilities (actual values from NVM definition) */
|
||||
enum nvm_sku_bits {
|
||||
NVM_SKU_CAP_BAND_24GHZ = BIT(0),
|
||||
|
@ -92,14 +113,6 @@ enum nvm_sku_bits {
|
|||
NVM_SKU_CAP_11AC_ENABLE = BIT(3),
|
||||
};
|
||||
|
||||
/* radio config bits (actual values from NVM definition) */
|
||||
#define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */
|
||||
#define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
|
||||
#define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
|
||||
#define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
|
||||
#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
|
||||
#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
|
||||
|
||||
/*
|
||||
* These are the channel numbers in the order that they are stored in the NVM
|
||||
*/
|
||||
|
@ -112,7 +125,17 @@ static const u8 iwl_nvm_channels[] = {
|
|||
149, 153, 157, 161, 165
|
||||
};
|
||||
|
||||
static const u8 iwl_nvm_channels_family_8000[] = {
|
||||
/* 2.4 GHz */
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
/* 5 GHz */
|
||||
36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
|
||||
96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
|
||||
149, 153, 157, 161, 165, 169, 173, 177, 181
|
||||
};
|
||||
|
||||
#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
|
||||
#define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000)
|
||||
#define NUM_2GHZ_CHANNELS 14
|
||||
#define FIRST_2GHZ_HT_MINUS 5
|
||||
#define LAST_2GHZ_HT_PLUS 9
|
||||
|
@ -179,8 +202,18 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
|||
struct ieee80211_channel *channel;
|
||||
u16 ch_flags;
|
||||
bool is_5ghz;
|
||||
int num_of_ch;
|
||||
const u8 *nvm_chan;
|
||||
|
||||
for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) {
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
num_of_ch = IWL_NUM_CHANNELS;
|
||||
nvm_chan = &iwl_nvm_channels[0];
|
||||
} else {
|
||||
num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
|
||||
nvm_chan = &iwl_nvm_channels_family_8000[0];
|
||||
}
|
||||
|
||||
for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
|
||||
ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
|
||||
|
||||
if (ch_idx >= NUM_2GHZ_CHANNELS &&
|
||||
|
@ -190,7 +223,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
|||
if (!(ch_flags & NVM_CHANNEL_VALID)) {
|
||||
IWL_DEBUG_EEPROM(dev,
|
||||
"Ch. %d Flags %x [%sGHz] - No traffic\n",
|
||||
iwl_nvm_channels[ch_idx],
|
||||
nvm_chan[ch_idx],
|
||||
ch_flags,
|
||||
(ch_idx >= NUM_2GHZ_CHANNELS) ?
|
||||
"5.2" : "2.4");
|
||||
|
@ -200,7 +233,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
|||
channel = &data->channels[n_channels];
|
||||
n_channels++;
|
||||
|
||||
channel->hw_value = iwl_nvm_channels[ch_idx];
|
||||
channel->hw_value = nvm_chan[ch_idx];
|
||||
channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
|
||||
IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
|
||||
channel->center_freq =
|
||||
|
@ -211,11 +244,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
|
|||
channel->flags = IEEE80211_CHAN_NO_HT40;
|
||||
if (ch_idx < NUM_2GHZ_CHANNELS &&
|
||||
(ch_flags & NVM_CHANNEL_40MHZ)) {
|
||||
if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS)
|
||||
if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
||||
if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS)
|
||||
if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
|
||||
} else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT &&
|
||||
} else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT &&
|
||||
(ch_flags & NVM_CHANNEL_40MHZ)) {
|
||||
if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
||||
|
@ -307,14 +340,23 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
|
|||
}
|
||||
|
||||
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
|
||||
struct iwl_nvm_data *data, const __le16 *nvm_sw,
|
||||
bool enable_vht, u8 tx_chains, u8 rx_chains)
|
||||
struct iwl_nvm_data *data,
|
||||
const __le16 *ch_section, bool enable_vht,
|
||||
u8 tx_chains, u8 rx_chains)
|
||||
{
|
||||
int n_channels = iwl_init_channel_map(dev, cfg, data,
|
||||
&nvm_sw[NVM_CHANNELS]);
|
||||
int n_channels;
|
||||
int n_used = 0;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
n_channels = iwl_init_channel_map(
|
||||
dev, cfg, data,
|
||||
&ch_section[NVM_CHANNELS]);
|
||||
else
|
||||
n_channels = iwl_init_channel_map(
|
||||
dev, cfg, data,
|
||||
&ch_section[NVM_CHANNELS_FAMILY_8000]);
|
||||
|
||||
sband = &data->bands[IEEE80211_BAND_2GHZ];
|
||||
sband->band = IEEE80211_BAND_2GHZ;
|
||||
sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
|
||||
|
@ -340,67 +382,150 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
|
|||
n_used, n_channels);
|
||||
}
|
||||
|
||||
struct iwl_nvm_data *
|
||||
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_hw, const __le16 *nvm_sw,
|
||||
const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains)
|
||||
static int iwl_get_sku(const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_sw)
|
||||
{
|
||||
struct iwl_nvm_data *data;
|
||||
u8 hw_addr[ETH_ALEN];
|
||||
u16 radio_cfg, sku;
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
return le16_to_cpup(nvm_sw + SKU);
|
||||
else
|
||||
return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000));
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(*data) +
|
||||
sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return NULL;
|
||||
static int iwl_get_nvm_version(const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_sw)
|
||||
{
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
return le16_to_cpup(nvm_sw + NVM_VERSION);
|
||||
else
|
||||
return le32_to_cpup((__le32 *)(nvm_sw +
|
||||
NVM_VERSION_FAMILY_8000));
|
||||
}
|
||||
|
||||
data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION);
|
||||
static int iwl_get_radio_cfg(const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_sw)
|
||||
{
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
return le16_to_cpup(nvm_sw + RADIO_CFG);
|
||||
else
|
||||
return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000));
|
||||
}
|
||||
|
||||
radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG);
|
||||
data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
|
||||
data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
|
||||
data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
|
||||
data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
|
||||
data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
|
||||
data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
|
||||
#define N_HW_ADDRS_MASK_FAMILY_8000 0xF
|
||||
static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_sw)
|
||||
{
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
return le16_to_cpup(nvm_sw + N_HW_ADDRS);
|
||||
else
|
||||
return le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000))
|
||||
& N_HW_ADDRS_MASK_FAMILY_8000;
|
||||
}
|
||||
|
||||
sku = le16_to_cpup(nvm_sw + SKU);
|
||||
data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
|
||||
data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
|
||||
data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
|
||||
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
|
||||
data->sku_cap_11n_enable = false;
|
||||
|
||||
/* check overrides (some devices have wrong NVM) */
|
||||
if (cfg->valid_tx_ant)
|
||||
data->valid_tx_ant = cfg->valid_tx_ant;
|
||||
if (cfg->valid_rx_ant)
|
||||
data->valid_rx_ant = cfg->valid_rx_ant;
|
||||
|
||||
if (!data->valid_tx_ant || !data->valid_rx_ant) {
|
||||
IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
|
||||
data->valid_tx_ant, data->valid_rx_ant);
|
||||
kfree(data);
|
||||
return NULL;
|
||||
static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
|
||||
struct iwl_nvm_data *data,
|
||||
u32 radio_cfg)
|
||||
{
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
|
||||
data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
|
||||
data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
|
||||
data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
|
||||
return;
|
||||
}
|
||||
|
||||
data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS);
|
||||
/* set the radio configuration for family 8000 */
|
||||
data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg);
|
||||
data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg);
|
||||
data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg);
|
||||
data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg);
|
||||
}
|
||||
|
||||
data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
|
||||
data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
|
||||
static void iwl_set_hw_address(const struct iwl_cfg *cfg,
|
||||
struct iwl_nvm_data *data,
|
||||
const __le16 *nvm_sec)
|
||||
{
|
||||
u8 hw_addr[ETH_ALEN];
|
||||
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
memcpy(hw_addr, nvm_sec + HW_ADDR, ETH_ALEN);
|
||||
else
|
||||
memcpy(hw_addr, nvm_sec + MAC_ADDRESS_OVERRIDE_FAMILY_8000,
|
||||
ETH_ALEN);
|
||||
|
||||
/* The byte order is little endian 16 bit, meaning 214365 */
|
||||
memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN);
|
||||
data->hw_addr[0] = hw_addr[1];
|
||||
data->hw_addr[1] = hw_addr[0];
|
||||
data->hw_addr[2] = hw_addr[3];
|
||||
data->hw_addr[3] = hw_addr[2];
|
||||
data->hw_addr[4] = hw_addr[5];
|
||||
data->hw_addr[5] = hw_addr[4];
|
||||
}
|
||||
|
||||
iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE,
|
||||
tx_chains, rx_chains);
|
||||
struct iwl_nvm_data *
|
||||
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_hw, const __le16 *nvm_sw,
|
||||
const __le16 *nvm_calib, const __le16 *regulatory,
|
||||
const __le16 *mac_override, u8 tx_chains, u8 rx_chains)
|
||||
{
|
||||
struct iwl_nvm_data *data;
|
||||
u32 sku;
|
||||
u32 radio_cfg;
|
||||
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
|
||||
data = kzalloc(sizeof(*data) +
|
||||
sizeof(struct ieee80211_channel) *
|
||||
IWL_NUM_CHANNELS,
|
||||
GFP_KERNEL);
|
||||
else
|
||||
data = kzalloc(sizeof(*data) +
|
||||
sizeof(struct ieee80211_channel) *
|
||||
IWL_NUM_CHANNELS_FAMILY_8000,
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw);
|
||||
|
||||
radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw);
|
||||
iwl_set_radio_cfg(cfg, data, radio_cfg);
|
||||
|
||||
sku = iwl_get_sku(cfg, nvm_sw);
|
||||
data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
|
||||
data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
|
||||
data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
|
||||
data->sku_cap_11ac_enable = sku & NVM_SKU_CAP_11AC_ENABLE;
|
||||
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
|
||||
data->sku_cap_11n_enable = false;
|
||||
|
||||
data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
|
||||
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
/* Checking for required sections */
|
||||
if (!nvm_calib) {
|
||||
IWL_ERR_DEV(dev,
|
||||
"Can't parse empty Calib NVM sections\n");
|
||||
kfree(data);
|
||||
return NULL;
|
||||
}
|
||||
/* in family 8000 Xtal calibration values moved to OTP */
|
||||
data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
|
||||
data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
|
||||
}
|
||||
|
||||
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
iwl_set_hw_address(cfg, data, nvm_hw);
|
||||
|
||||
iwl_init_sbands(dev, cfg, data, nvm_sw,
|
||||
sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
|
||||
rx_chains);
|
||||
} else {
|
||||
/* MAC address in family 8000 */
|
||||
iwl_set_hw_address(cfg, data, mac_override);
|
||||
|
||||
iwl_init_sbands(dev, cfg, data, regulatory,
|
||||
sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
|
||||
rx_chains);
|
||||
}
|
||||
|
||||
data->calib_version = 255;
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
struct iwl_nvm_data *
|
||||
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
|
||||
const __le16 *nvm_hw, const __le16 *nvm_sw,
|
||||
const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains);
|
||||
const __le16 *nvm_calib, const __le16 *regulatory,
|
||||
const __le16 *mac_override, u8 tx_chains, u8 rx_chains);
|
||||
|
||||
#endif /* __iwl_nvm_parse_h__ */
|
||||
|
|
|
@ -393,7 +393,7 @@ struct iwl_trans_config {
|
|||
bool rx_buf_size_8k;
|
||||
bool bc_table_dword;
|
||||
unsigned int queue_watchdog_timeout;
|
||||
const char **command_names;
|
||||
const char *const *command_names;
|
||||
};
|
||||
|
||||
struct iwl_trans;
|
||||
|
|
|
@ -591,7 +591,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
|
||||
((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
|
||||
(vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
|
||||
mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)))
|
||||
mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)))
|
||||
MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
|
||||
S_IRUSR);
|
||||
|
||||
|
|
|
@ -531,6 +531,76 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
|
|||
}
|
||||
#undef PRINT_STAT_LE32
|
||||
|
||||
static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
|
||||
char __user *user_buf, size_t count,
|
||||
loff_t *ppos,
|
||||
struct iwl_mvm_frame_stats *stats)
|
||||
{
|
||||
char *buff;
|
||||
int pos = 0, idx, i;
|
||||
int ret;
|
||||
size_t bufsz = 1024;
|
||||
|
||||
buff = kmalloc(bufsz, GFP_KERNEL);
|
||||
if (!buff)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_bh(&mvm->drv_stats_lock);
|
||||
pos += scnprintf(buff + pos, bufsz - pos,
|
||||
"Legacy/HT/VHT\t:\t%d/%d/%d\n",
|
||||
stats->legacy_frames,
|
||||
stats->ht_frames,
|
||||
stats->vht_frames);
|
||||
pos += scnprintf(buff + pos, bufsz - pos, "20/40/80\t:\t%d/%d/%d\n",
|
||||
stats->bw_20_frames,
|
||||
stats->bw_40_frames,
|
||||
stats->bw_80_frames);
|
||||
pos += scnprintf(buff + pos, bufsz - pos, "NGI/SGI\t\t:\t%d/%d\n",
|
||||
stats->ngi_frames,
|
||||
stats->sgi_frames);
|
||||
pos += scnprintf(buff + pos, bufsz - pos, "SISO/MIMO2\t:\t%d/%d\n",
|
||||
stats->siso_frames,
|
||||
stats->mimo2_frames);
|
||||
pos += scnprintf(buff + pos, bufsz - pos, "FAIL/SCSS\t:\t%d/%d\n",
|
||||
stats->fail_frames,
|
||||
stats->success_frames);
|
||||
pos += scnprintf(buff + pos, bufsz - pos, "MPDUs agg\t:\t%d\n",
|
||||
stats->agg_frames);
|
||||
pos += scnprintf(buff + pos, bufsz - pos, "A-MPDUs\t\t:\t%d\n",
|
||||
stats->ampdu_count);
|
||||
pos += scnprintf(buff + pos, bufsz - pos, "Avg MPDUs/A-MPDU:\t%d\n",
|
||||
stats->ampdu_count > 0 ?
|
||||
(stats->agg_frames / stats->ampdu_count) : 0);
|
||||
|
||||
pos += scnprintf(buff + pos, bufsz - pos, "Last Rates\n");
|
||||
|
||||
idx = stats->last_frame_idx - 1;
|
||||
for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) {
|
||||
idx = (idx + 1) % ARRAY_SIZE(stats->last_rates);
|
||||
if (stats->last_rates[idx] == 0)
|
||||
continue;
|
||||
pos += scnprintf(buff + pos, bufsz - pos, "Rate[%d]: ",
|
||||
(int)(ARRAY_SIZE(stats->last_rates) - i));
|
||||
pos += rs_pretty_print_rate(buff + pos, stats->last_rates[idx]);
|
||||
}
|
||||
spin_unlock_bh(&mvm->drv_stats_lock);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos);
|
||||
kfree(buff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file,
|
||||
char __user *user_buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
|
||||
return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos,
|
||||
&mvm->drv_rx_stats);
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -591,7 +661,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
|
|||
return -EINVAL;
|
||||
if (scan_rx_ant > ANT_ABC)
|
||||
return -EINVAL;
|
||||
if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw))
|
||||
if (scan_rx_ant & ~mvm->fw->valid_rx_ant)
|
||||
return -EINVAL;
|
||||
|
||||
mvm->scan_rx_ant = scan_rx_ant;
|
||||
|
@ -907,6 +977,49 @@ static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
|
|||
#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
|
||||
MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
|
||||
|
||||
static ssize_t
|
||||
iwl_dbgfs_prph_reg_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
int pos = 0;
|
||||
char buf[32];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
||||
if (!mvm->dbgfs_prph_reg_addr)
|
||||
return -EINVAL;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
|
||||
mvm->dbgfs_prph_reg_addr,
|
||||
iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
u8 args;
|
||||
u32 value;
|
||||
|
||||
args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
|
||||
/* if we only want to set the reg address - nothing more to do */
|
||||
if (args == 1)
|
||||
goto out;
|
||||
|
||||
/* otherwise, make sure we have both address and value */
|
||||
if (args != 2)
|
||||
return -EINVAL;
|
||||
|
||||
iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
|
||||
out:
|
||||
return count;
|
||||
}
|
||||
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
|
||||
|
||||
/* Device wide debugfs entries */
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
|
||||
|
@ -916,6 +1029,7 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
|
|||
MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
|
||||
|
@ -947,10 +1061,12 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
|||
MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
|
||||
S_IRUSR | S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
|
||||
S_IWUSR | S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
|
||||
|
|
|
@ -257,7 +257,8 @@ enum {
|
|||
|
||||
/* Bit 17-18: (0) SS, (1) SS*2 */
|
||||
#define RATE_MCS_STBC_POS 17
|
||||
#define RATE_MCS_STBC_MSK (1 << RATE_MCS_STBC_POS)
|
||||
#define RATE_MCS_HT_STBC_MSK (3 << RATE_MCS_STBC_POS)
|
||||
#define RATE_MCS_VHT_STBC_MSK (1 << RATE_MCS_STBC_POS)
|
||||
|
||||
/* Bit 19: (0) Beamforming is off, (1) Beamforming is on */
|
||||
#define RATE_MCS_BF_POS 19
|
||||
|
|
|
@ -306,7 +306,6 @@ struct iwl_phy_cfg_cmd {
|
|||
#define PHY_CFG_RX_CHAIN_B BIT(13)
|
||||
#define PHY_CFG_RX_CHAIN_C BIT(14)
|
||||
|
||||
#define NVM_MAX_NUM_SECTIONS 11
|
||||
|
||||
/* Target of the NVM_ACCESS_CMD */
|
||||
enum {
|
||||
|
@ -318,8 +317,11 @@ enum {
|
|||
/* Section types for NVM_ACCESS_CMD */
|
||||
enum {
|
||||
NVM_SECTION_TYPE_SW = 1,
|
||||
NVM_SECTION_TYPE_REGULATORY = 3,
|
||||
NVM_SECTION_TYPE_CALIBRATION = 4,
|
||||
NVM_SECTION_TYPE_PRODUCTION = 5,
|
||||
NVM_SECTION_TYPE_MAC_OVERRIDE = 11,
|
||||
NVM_MAX_NUM_SECTIONS = 12,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -710,6 +712,7 @@ enum {
|
|||
TE_V2_NOTIF_HOST_FRAG_END = BIT(5),
|
||||
TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6),
|
||||
TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7),
|
||||
T2_V2_START_IMMEDIATELY = BIT(11),
|
||||
|
||||
TE_V2_NOTIF_MSK = 0xff,
|
||||
|
||||
|
|
|
@ -130,7 +130,6 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
|
|||
} else {
|
||||
palive2 = (void *)pkt->data;
|
||||
|
||||
mvm->support_umac_log = true;
|
||||
mvm->error_event_table =
|
||||
le32_to_cpu(palive2->error_event_table_ptr);
|
||||
mvm->log_event_table =
|
||||
|
@ -141,6 +140,9 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
|
|||
|
||||
alive_data->valid = le16_to_cpu(palive2->status) ==
|
||||
IWL_ALIVE_STATUS_OK;
|
||||
if (mvm->umac_error_event_table)
|
||||
mvm->support_umac_log = true;
|
||||
|
||||
IWL_DEBUG_FW(mvm,
|
||||
"Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
|
||||
le16_to_cpu(palive2->status), palive2->ver_type,
|
||||
|
@ -320,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
|
|||
}
|
||||
|
||||
/* Send TX valid antennas before triggering calibrations */
|
||||
ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
|
||||
ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
|
@ -356,8 +358,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
|
|||
GFP_KERNEL);
|
||||
if (!mvm->nvm_data)
|
||||
return -ENOMEM;
|
||||
mvm->nvm_data->valid_rx_ant = 1;
|
||||
mvm->nvm_data->valid_tx_ant = 1;
|
||||
mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels;
|
||||
mvm->nvm_data->bands[0].n_channels = 1;
|
||||
mvm->nvm_data->bands[0].n_bitrates = 1;
|
||||
|
@ -369,8 +369,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define UCODE_CALIB_TIMEOUT (2*HZ)
|
||||
|
||||
int iwl_mvm_up(struct iwl_mvm *mvm)
|
||||
{
|
||||
int ret, i;
|
||||
|
@ -422,7 +420,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
|||
if (ret)
|
||||
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
|
||||
|
||||
ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
|
||||
ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
|
@ -507,7 +505,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
|
|||
goto error;
|
||||
}
|
||||
|
||||
ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
|
||||
ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
|
|
|
@ -952,7 +952,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
|
|||
TX_CMD_FLG_TSF);
|
||||
|
||||
mvm->mgmt_last_antenna_idx =
|
||||
iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
|
||||
iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
|
||||
mvm->mgmt_last_antenna_idx);
|
||||
|
||||
beacon_cmd.tx.rate_n_flags =
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include <linux/ip.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include "iwl-op-mode.h"
|
||||
|
@ -280,6 +281,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
|
||||
hw->queues = mvm->first_agg_queue;
|
||||
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
|
||||
hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
|
||||
IEEE80211_RADIOTAP_MCS_HAVE_STBC;
|
||||
hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC;
|
||||
hw->rate_control_algorithm = "iwl-mvm-rs";
|
||||
|
||||
/*
|
||||
|
@ -1319,7 +1323,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
|||
mvmvif->ap_ibss_active = true;
|
||||
|
||||
/* power updated needs to be done before quotas */
|
||||
mvm->bound_vif_cnt++;
|
||||
iwl_mvm_power_update_mac(mvm, vif);
|
||||
|
||||
ret = iwl_mvm_update_quotas(mvm, vif);
|
||||
|
@ -1338,7 +1341,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
|||
return 0;
|
||||
|
||||
out_quota_failed:
|
||||
mvm->bound_vif_cnt--;
|
||||
iwl_mvm_power_update_mac(mvm, vif);
|
||||
mvmvif->ap_ibss_active = false;
|
||||
iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
|
||||
|
@ -1375,7 +1377,6 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
|
|||
iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
|
||||
iwl_mvm_binding_remove_vif(mvm, vif);
|
||||
|
||||
mvm->bound_vif_cnt--;
|
||||
iwl_mvm_power_update_mac(mvm, vif);
|
||||
|
||||
iwl_mvm_mac_ctxt_remove(mvm, vif);
|
||||
|
@ -1764,14 +1765,16 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
iwl_mvm_sched_scan_stop(mvm);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
||||
|
@ -2109,7 +2112,6 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
* Power state must be updated before quotas,
|
||||
* otherwise fw will complain.
|
||||
*/
|
||||
mvm->bound_vif_cnt++;
|
||||
iwl_mvm_power_update_mac(mvm, vif);
|
||||
|
||||
/* Setting the quota at this stage is only required for monitor
|
||||
|
@ -2127,7 +2129,6 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
|
||||
out_remove_binding:
|
||||
iwl_mvm_binding_remove_vif(mvm, vif);
|
||||
mvm->bound_vif_cnt--;
|
||||
iwl_mvm_power_update_mac(mvm, vif);
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
@ -2160,7 +2161,6 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
}
|
||||
|
||||
iwl_mvm_binding_remove_vif(mvm, vif);
|
||||
mvm->bound_vif_cnt--;
|
||||
iwl_mvm_power_update_mac(mvm, vif);
|
||||
|
||||
out_unlock:
|
||||
|
@ -2251,7 +2251,7 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
|
|||
}
|
||||
#endif
|
||||
|
||||
struct ieee80211_ops iwl_mvm_hw_ops = {
|
||||
const struct ieee80211_ops iwl_mvm_hw_ops = {
|
||||
.tx = iwl_mvm_mac_tx,
|
||||
.ampdu_action = iwl_mvm_mac_ampdu_action,
|
||||
.start = iwl_mvm_mac_start,
|
||||
|
|
|
@ -91,8 +91,7 @@ enum iwl_mvm_tx_fifo {
|
|||
IWL_MVM_TX_FIFO_MCAST = 5,
|
||||
};
|
||||
|
||||
extern struct ieee80211_ops iwl_mvm_hw_ops;
|
||||
extern const struct iwl_mvm_power_ops pm_mac_ops;
|
||||
extern const struct ieee80211_ops iwl_mvm_hw_ops;
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_mod_params - module parameters for iwlmvm
|
||||
|
@ -426,6 +425,28 @@ struct iwl_mvm_tt_mgmt {
|
|||
bool throttle;
|
||||
};
|
||||
|
||||
#define IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES 8
|
||||
|
||||
struct iwl_mvm_frame_stats {
|
||||
u32 legacy_frames;
|
||||
u32 ht_frames;
|
||||
u32 vht_frames;
|
||||
u32 bw_20_frames;
|
||||
u32 bw_40_frames;
|
||||
u32 bw_80_frames;
|
||||
u32 bw_160_frames;
|
||||
u32 sgi_frames;
|
||||
u32 ngi_frames;
|
||||
u32 siso_frames;
|
||||
u32 mimo2_frames;
|
||||
u32 agg_frames;
|
||||
u32 ampdu_count;
|
||||
u32 success_frames;
|
||||
u32 fail_frames;
|
||||
u32 last_rates[IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES];
|
||||
int last_frame_idx;
|
||||
};
|
||||
|
||||
struct iwl_mvm {
|
||||
/* for logger access */
|
||||
struct device *dev;
|
||||
|
@ -519,6 +540,7 @@ struct iwl_mvm {
|
|||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
struct dentry *debugfs_dir;
|
||||
u32 dbgfs_sram_offset, dbgfs_sram_len;
|
||||
u32 dbgfs_prph_reg_addr;
|
||||
bool disable_power_off;
|
||||
bool disable_power_off_d3;
|
||||
|
||||
|
@ -526,6 +548,9 @@ struct iwl_mvm {
|
|||
struct debugfs_blob_wrapper nvm_sw_blob;
|
||||
struct debugfs_blob_wrapper nvm_calib_blob;
|
||||
struct debugfs_blob_wrapper nvm_prod_blob;
|
||||
|
||||
struct iwl_mvm_frame_stats drv_rx_stats;
|
||||
spinlock_t drv_stats_lock;
|
||||
#endif
|
||||
|
||||
struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
|
||||
|
@ -587,8 +612,6 @@ struct iwl_mvm {
|
|||
u8 first_agg_queue;
|
||||
u8 last_agg_queue;
|
||||
|
||||
u8 bound_vif_cnt;
|
||||
|
||||
/* Indicate if device power save is allowed */
|
||||
bool ps_disabled;
|
||||
/* Indicate if device power management is allowed */
|
||||
|
@ -812,6 +835,10 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
|
||||
/* rate scaling */
|
||||
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
|
||||
void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_frame_stats *stats,
|
||||
u32 rate, bool agg);
|
||||
int rs_pretty_print_rate(char *buf, const u32 rate);
|
||||
|
||||
/* power management */
|
||||
int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm);
|
||||
|
|
|
@ -228,13 +228,23 @@ static struct iwl_nvm_data *
|
|||
iwl_parse_nvm_sections(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_nvm_section *sections = mvm->nvm_sections;
|
||||
const __le16 *hw, *sw, *calib;
|
||||
const __le16 *hw, *sw, *calib, *regulatory, *mac_override;
|
||||
|
||||
/* Checking for required sections */
|
||||
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
|
||||
!mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
|
||||
IWL_ERR(mvm, "Can't parse empty NVM sections\n");
|
||||
return NULL;
|
||||
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
|
||||
!mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
|
||||
IWL_ERR(mvm, "Can't parse empty NVM sections\n");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
|
||||
!mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data ||
|
||||
!mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) {
|
||||
IWL_ERR(mvm,
|
||||
"Can't parse empty family 8000 NVM sections\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (WARN_ON(!mvm->cfg))
|
||||
|
@ -243,9 +253,14 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
|
|||
hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
|
||||
sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
|
||||
calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
|
||||
regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data;
|
||||
mac_override =
|
||||
(const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data;
|
||||
|
||||
return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
|
||||
iwl_fw_valid_tx_ant(mvm->fw),
|
||||
iwl_fw_valid_rx_ant(mvm->fw));
|
||||
regulatory, mac_override,
|
||||
mvm->fw->valid_tx_ant,
|
||||
mvm->fw->valid_rx_ant);
|
||||
}
|
||||
|
||||
#define MAX_NVM_FILE_LEN 16384
|
||||
|
@ -285,6 +300,8 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
|
|||
|
||||
#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
|
||||
#define NVM_WORD2_ID(x) (x >> 12)
|
||||
#define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8))
|
||||
#define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4)
|
||||
|
||||
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
|
||||
|
||||
|
@ -335,8 +352,16 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
|
|||
break;
|
||||
}
|
||||
|
||||
section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
|
||||
section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
|
||||
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
section_size =
|
||||
2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
|
||||
section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
|
||||
} else {
|
||||
section_size = 2 * NVM_WORD2_LEN_FAMILY_8000(
|
||||
le16_to_cpu(file_sec->word2));
|
||||
section_id = NVM_WORD1_ID_FAMILY_8000(
|
||||
le16_to_cpu(file_sec->word1));
|
||||
}
|
||||
|
||||
if (section_size > IWL_MAX_NVM_SECTION_SIZE) {
|
||||
IWL_ERR(mvm, "ERROR - section too large (%d)\n",
|
||||
|
@ -406,6 +431,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
|
|||
{
|
||||
int ret, i, section;
|
||||
u8 *nvm_buffer, *temp;
|
||||
int nvm_to_read[NVM_MAX_NUM_SECTIONS];
|
||||
int num_of_sections_to_read;
|
||||
|
||||
if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS))
|
||||
return -EINVAL;
|
||||
|
@ -418,12 +445,20 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
|
|||
return ret;
|
||||
} else {
|
||||
/* list of NVM sections we are allowed/need to read */
|
||||
int nvm_to_read[] = {
|
||||
mvm->cfg->nvm_hw_section_num,
|
||||
NVM_SECTION_TYPE_SW,
|
||||
NVM_SECTION_TYPE_CALIBRATION,
|
||||
NVM_SECTION_TYPE_PRODUCTION,
|
||||
};
|
||||
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
nvm_to_read[0] = mvm->cfg->nvm_hw_section_num;
|
||||
nvm_to_read[1] = NVM_SECTION_TYPE_SW;
|
||||
nvm_to_read[2] = NVM_SECTION_TYPE_CALIBRATION;
|
||||
nvm_to_read[3] = NVM_SECTION_TYPE_PRODUCTION;
|
||||
num_of_sections_to_read = 4;
|
||||
} else {
|
||||
nvm_to_read[0] = NVM_SECTION_TYPE_SW;
|
||||
nvm_to_read[1] = NVM_SECTION_TYPE_CALIBRATION;
|
||||
nvm_to_read[2] = NVM_SECTION_TYPE_PRODUCTION;
|
||||
nvm_to_read[3] = NVM_SECTION_TYPE_REGULATORY;
|
||||
nvm_to_read[4] = NVM_SECTION_TYPE_MAC_OVERRIDE;
|
||||
num_of_sections_to_read = 5;
|
||||
}
|
||||
|
||||
/* Read From FW NVM */
|
||||
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
|
||||
|
@ -433,7 +468,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
|
|||
GFP_KERNEL);
|
||||
if (!nvm_buffer)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
|
||||
for (i = 0; i < num_of_sections_to_read; i++) {
|
||||
section = nvm_to_read[i];
|
||||
/* we override the constness for initial read */
|
||||
ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue