Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts: drivers/net/wireless/ath/ath9k/recv.c
This commit is contained in:
commit
42775a34d2
@ -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
|
||||
|
39
Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
Normal file
39
Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
Normal file
@ -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,9 +469,13 @@ 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", "",
|
||||
ar->fw_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 @@ err:
|
||||
}
|
||||
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);
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
* 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 = max((n+7) / 8, 1);
|
||||
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,
|
||||
static int ath10k_peer_assoc_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)
|
||||
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,
|
||||
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,
|
||||
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 @@ exit:
|
||||
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");
|
||||
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 @@ err_deinit_irq:
|
||||
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 @@ err:
|
||||
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 @@ out:
|
||||
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 @@ err_pull:
|
||||
|
||||
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) {
|
||||
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");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 =
|
||||
|
244
drivers/net/wireless/ath/ath9k/common-init.c
Normal file
244
drivers/net/wireless/ath/ath9k/common-init.c
Normal file
@ -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);
|
20
drivers/net/wireless/ath/ath9k/common-init.h
Normal file
20
drivers/net/wireless/ath/ath9k/common-init.h
Normal file
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 @@ err:
|
||||
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);
|
||||
|
||||
wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
|
||||
if (cid < 0)
|
||||
return cid;
|
||||
|
||||
rc = wil_cid_fill_sinfo(wil, cid, sinfo);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
sinfo->generation = wil->sinfo_gen;
|
||||
/*
|
||||
* Find @idx-th active STA for station dump.
|
||||
*/
|
||||
static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
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;
|
||||
|
||||
if (test_bit(wil_status_fwconnected, &wil->status)) {
|
||||
sinfo->filled |= STATION_INFO_SIGNAL;
|
||||
sinfo->signal = 12; /* TODO: provide real value */
|
||||
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,7 +461,12 @@ 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",
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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,13 +54,52 @@ 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 wil_sta_info *sta = &wil->sta[cid];
|
||||
|
||||
if (sta->status != wil_sta_unused) {
|
||||
wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
|
||||
sta->status = wil_sta_unused;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
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);
|
||||
@ -71,10 +112,17 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
|
||||
GFP_KERNEL);
|
||||
}
|
||||
clear_bit(wil_status_fwconnecting, &wil->status);
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
|
||||
wil_vring_fini_tx(wil, i);
|
||||
|
||||
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;
|
||||
}
|
||||
|
177
drivers/net/wireless/ath/wil6210/rx_reorder.c
Normal file
177
drivers/net/wireless/ath/wil6210/rx_reorder.c
Normal file
@ -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)
|
||||
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 */
|
||||
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 @@ data_ready:
|
||||
|
||||
b43_rx(q->dev, skb, rxhdr);
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
rx_error:
|
||||
if (err_msg)
|
||||
@ -769,7 +769,7 @@ rx_error:
|
||||
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;
|
||||
|
||||
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,37 +2772,14 @@ break2:
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,10 +4717,16 @@ 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));
|
||||
if (ndev != cfg_to_ndev(cfg))
|
||||
@ -4905,10 +4919,7 @@ 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->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)
|
||||
@ -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");
|
||||
|
@ -2271,6 +2271,7 @@ 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_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 @@ set_ch_out:
|
||||
}
|
||||
|
||||
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);
|
||||
#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;
|
||||
}
|
||||
|
||||
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);
|
||||
data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
|
||||
data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
|
||||
|
||||
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;
|
||||
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 @@ out:
|
||||
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 @@ out:
|
||||
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,7 +1765,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
|
||||
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);
|
||||
@ -1772,6 +1773,8 @@ static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *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,14 +228,24 @@ 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->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))
|
||||
return NULL;
|
||||
@ -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));
|
||||
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);
|
||||
|
@ -245,7 +245,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
|
||||
#undef RX_HANDLER
|
||||
#define CMD(x) [x] = #x
|
||||
|
||||
static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
|
||||
static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
|
||||
CMD(MVM_ALIVE),
|
||||
CMD(REPLY_ERROR),
|
||||
CMD(INIT_COMPLETE_NOTIF),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user