提交 42775a34 编写于 作者: J John W. Linville

Merge branch 'master' of...

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
...@@ -98,6 +98,8 @@ ...@@ -98,6 +98,8 @@
!Finclude/net/cfg80211.h priv_to_wiphy !Finclude/net/cfg80211.h priv_to_wiphy
!Finclude/net/cfg80211.h set_wiphy_dev !Finclude/net/cfg80211.h set_wiphy_dev
!Finclude/net/cfg80211.h wdev_priv !Finclude/net/cfg80211.h wdev_priv
!Finclude/net/cfg80211.h ieee80211_iface_limit
!Finclude/net/cfg80211.h ieee80211_iface_combination
</chapter> </chapter>
<chapter> <chapter>
<title>Actions and configuration</title> <title>Actions and configuration</title>
......
...@@ -353,6 +353,7 @@ Your cooperation is appreciated. ...@@ -353,6 +353,7 @@ Your cooperation is appreciated.
133 = /dev/exttrp External device trap 133 = /dev/exttrp External device trap
134 = /dev/apm_bios Advanced Power Management BIOS 134 = /dev/apm_bios Advanced Power Management BIOS
135 = /dev/rtc Real Time Clock 135 = /dev/rtc Real Time Clock
137 = /dev/vhci Bluetooth virtual HCI driver
139 = /dev/openprom SPARC OpenBoot PROM 139 = /dev/openprom SPARC OpenBoot PROM
140 = /dev/relay8 Berkshire Products Octal relay card 140 = /dev/relay8 Berkshire Products Octal relay card
141 = /dev/relay16 Berkshire Products ISO-16 relay card 141 = /dev/relay16 Berkshire Products ISO-16 relay card
......
* 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 = { ...@@ -536,11 +536,13 @@ static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
static void __init pandora_wl1251_init(void) static void __init pandora_wl1251_init(void)
{ {
struct wl12xx_platform_data pandora_wl1251_pdata; struct wl1251_platform_data pandora_wl1251_pdata;
int ret; int ret;
memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata)); 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"); ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq");
if (ret < 0) if (ret < 0)
goto fail; goto fail;
...@@ -550,7 +552,7 @@ static void __init pandora_wl1251_init(void) ...@@ -550,7 +552,7 @@ static void __init pandora_wl1251_init(void)
goto fail_irq; goto fail_irq;
pandora_wl1251_pdata.use_eeprom = true; 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) if (ret < 0)
goto fail_irq; goto fail_irq;
......
...@@ -84,7 +84,7 @@ enum { ...@@ -84,7 +84,7 @@ enum {
RX51_SPI_MIPID, /* LCD panel */ 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; static struct tsc2005_platform_data tsc2005_pdata;
#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE) #if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
...@@ -1173,13 +1173,7 @@ static inline void board_smc91x_init(void) ...@@ -1173,13 +1173,7 @@ static inline void board_smc91x_init(void)
#endif #endif
static void rx51_wl1251_set_power(bool enable)
{
gpio_set_value(RX51_WL1251_POWER_GPIO, enable);
}
static struct gpio rx51_wl1251_gpios[] __initdata = { 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" }, { RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" },
}; };
...@@ -1196,17 +1190,16 @@ static void __init rx51_init_wl1251(void) ...@@ -1196,17 +1190,16 @@ static void __init rx51_init_wl1251(void)
if (irq < 0) if (irq < 0)
goto err_irq; 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; rx51_peripherals_spi_board_info[RX51_SPI_WL1251].irq = irq;
return; return;
err_irq: err_irq:
gpio_free(RX51_WL1251_IRQ_GPIO); gpio_free(RX51_WL1251_IRQ_GPIO);
gpio_free(RX51_WL1251_POWER_GPIO);
error: error:
printk(KERN_ERR "wl1251 board initialisation failed\n"); 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 * Now rx51_peripherals_spi_board_info[1].irq is zero and
......
...@@ -62,50 +62,53 @@ static const struct usb_device_id ath3k_table[] = { ...@@ -62,50 +62,53 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x0CF3, 0x3000) }, { USB_DEVICE(0x0CF3, 0x3000) },
/* Atheros AR3011 with sflash firmware*/ /* Atheros AR3011 with sflash firmware*/
{ USB_DEVICE(0x0489, 0xE027) },
{ USB_DEVICE(0x0489, 0xE03D) },
{ USB_DEVICE(0x0930, 0x0215) },
{ USB_DEVICE(0x0CF3, 0x3002) }, { USB_DEVICE(0x0CF3, 0x3002) },
{ USB_DEVICE(0x0CF3, 0xE019) }, { USB_DEVICE(0x0CF3, 0xE019) },
{ USB_DEVICE(0x13d3, 0x3304) }, { USB_DEVICE(0x13d3, 0x3304) },
{ USB_DEVICE(0x0930, 0x0215) },
{ USB_DEVICE(0x0489, 0xE03D) },
{ USB_DEVICE(0x0489, 0xE027) },
/* Atheros AR9285 Malbec with sflash firmware */ /* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) }, { USB_DEVICE(0x03F0, 0x311D) },
/* Atheros AR3012 with sflash firmware*/ /* Atheros AR3012 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0489, 0xe04d) },
{ USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0489, 0xe04e) },
{ USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0489, 0xe057) },
{ USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x0489, 0xe056) },
{ USB_DEVICE(0x0CF3, 0x817a) }, { USB_DEVICE(0x0489, 0xe05f) },
{ USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x04c5, 0x1330) },
{ USB_DEVICE(0x04CA, 0x3004) }, { USB_DEVICE(0x04CA, 0x3004) },
{ USB_DEVICE(0x04CA, 0x3005) }, { USB_DEVICE(0x04CA, 0x3005) },
{ USB_DEVICE(0x04CA, 0x3006) }, { USB_DEVICE(0x04CA, 0x3006) },
{ USB_DEVICE(0x04CA, 0x3008) }, { USB_DEVICE(0x04CA, 0x3008) },
{ USB_DEVICE(0x04CA, 0x300b) }, { USB_DEVICE(0x04CA, 0x300b) },
{ USB_DEVICE(0x13d3, 0x3362) },
{ USB_DEVICE(0x0CF3, 0xE004) },
{ USB_DEVICE(0x0CF3, 0xE005) },
{ USB_DEVICE(0x0930, 0x0219) }, { USB_DEVICE(0x0930, 0x0219) },
{ USB_DEVICE(0x0930, 0x0220) }, { USB_DEVICE(0x0930, 0x0220) },
{ USB_DEVICE(0x0489, 0xe057) }, { USB_DEVICE(0x0b05, 0x17d0) },
{ USB_DEVICE(0x13d3, 0x3393) }, { USB_DEVICE(0x0CF3, 0x0036) },
{ USB_DEVICE(0x0489, 0xe04e) }, { USB_DEVICE(0x0CF3, 0x3004) },
{ USB_DEVICE(0x0489, 0xe056) }, { USB_DEVICE(0x0CF3, 0x3008) },
{ USB_DEVICE(0x0489, 0xe04d) }, { USB_DEVICE(0x0CF3, 0x311D) },
{ USB_DEVICE(0x04c5, 0x1330) }, { USB_DEVICE(0x0CF3, 0x311E) },
{ USB_DEVICE(0x13d3, 0x3402) }, { USB_DEVICE(0x0CF3, 0x311F) },
{ USB_DEVICE(0x0cf3, 0x3121) }, { USB_DEVICE(0x0cf3, 0x3121) },
{ USB_DEVICE(0x0CF3, 0x817a) },
{ USB_DEVICE(0x0cf3, 0xe003) }, { 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 */ /* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) }, { USB_DEVICE(0x0489, 0xE02C) },
/* Atheros AR5BBU22 with sflash firmware */ /* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C) },
{ USB_DEVICE(0x0489, 0xE036) }, { USB_DEVICE(0x0489, 0xE036) },
{ USB_DEVICE(0x0489, 0xE03C) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -118,36 +121,39 @@ MODULE_DEVICE_TABLE(usb, ath3k_table); ...@@ -118,36 +121,39 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
static const struct usb_device_id ath3k_blist_tbl[] = { static const struct usb_device_id ath3k_blist_tbl[] = {
/* Atheros AR3012 with sflash firmware*/ /* Atheros AR3012 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .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, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3121), .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(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 */ /* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -101,21 +101,24 @@ static const struct usb_device_id btusb_table[] = { ...@@ -101,21 +101,24 @@ static const struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) }, { USB_DEVICE(0x0c10, 0x0000) },
/* Broadcom BCM20702A0 */ /* Broadcom BCM20702A0 */
{ USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0b05, 0x17b5) }, { USB_DEVICE(0x0b05, 0x17b5) },
{ USB_DEVICE(0x0b05, 0x17cb) }, { USB_DEVICE(0x0b05, 0x17cb) },
{ USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x413c, 0x8197) }, { USB_DEVICE(0x413c, 0x8197) },
/* Foxconn - Hon Hai */ /* Foxconn - Hon Hai */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, { 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) }, { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
/* Belkin F8065bf - Broadcom based */ /* Belkin F8065bf - Broadcom based */
{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
/* IMC Networks - Broadcom based */
{ USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -129,55 +132,58 @@ static const struct usb_device_id blacklist_table[] = { ...@@ -129,55 +132,58 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
/* Atheros 3011 with sflash firmware */ /* 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, 0x3002), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x13d3, 0x3304), .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 */ /* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
/* Atheros 3012 with sflash firmware */ /* Atheros 3012 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .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, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3121), .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(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 */ /* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
/* Atheros AR5BBU12 with sflash firmware */ /* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
/* Broadcom BCM2035 */ /* 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, 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 */ /* Broadcom BCM2045 */
{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },
......
...@@ -359,7 +359,7 @@ static const struct file_operations vhci_fops = { ...@@ -359,7 +359,7 @@ static const struct file_operations vhci_fops = {
static struct miscdevice vhci_miscdev= { static struct miscdevice vhci_miscdev= {
.name = "vhci", .name = "vhci",
.fops = &vhci_fops, .fops = &vhci_fops,
.minor = MISC_DYNAMIC_MINOR, .minor = VHCI_MINOR,
}; };
static int __init vhci_init(void) static int __init vhci_init(void)
...@@ -385,3 +385,4 @@ MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); ...@@ -385,3 +385,4 @@ MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("devname:vhci"); MODULE_ALIAS("devname:vhci");
MODULE_ALIAS_MISCDEV(VHCI_MINOR);
...@@ -53,7 +53,7 @@ config LIBERTAS_THINFIRM_USB ...@@ -53,7 +53,7 @@ config LIBERTAS_THINFIRM_USB
config AIRO config AIRO
tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" 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 WIRELESS_EXT
select CRYPTO select CRYPTO
select WEXT_SPY select WEXT_SPY
...@@ -73,7 +73,7 @@ config AIRO ...@@ -73,7 +73,7 @@ config AIRO
config ATMEL config ATMEL
tristate "Atmel at76c50x chipset 802.11b support" tristate "Atmel at76c50x chipset 802.11b support"
depends on (PCI || PCMCIA) depends on CFG80211 && (PCI || PCMCIA)
select WIRELESS_EXT select WIRELESS_EXT
select WEXT_PRIV select WEXT_PRIV
select FW_LOADER select FW_LOADER
...@@ -138,7 +138,7 @@ config AIRO_CS ...@@ -138,7 +138,7 @@ config AIRO_CS
config PCMCIA_WL3501 config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards" tristate "Planet WL3501 PCMCIA cards"
depends on PCMCIA depends on CFG80211 && PCMCIA
select WIRELESS_EXT select WIRELESS_EXT
select WEXT_SPY select WEXT_SPY
help help
...@@ -168,7 +168,7 @@ config PRISM54 ...@@ -168,7 +168,7 @@ config PRISM54
config USB_ZD1201 config USB_ZD1201
tristate "USB ZD1201 based Wireless device support" tristate "USB ZD1201 based Wireless device support"
depends on USB depends on CFG80211 && USB
select WIRELESS_EXT select WIRELESS_EXT
select WEXT_PRIV select WEXT_PRIV
select FW_LOADER select FW_LOADER
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/crypto.h> #include <linux/crypto.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -45,11 +45,11 @@ ...@@ -45,11 +45,11 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/ieee80211.h> #include <net/cfg80211.h>
#include <net/iw_handler.h> #include <net/iw_handler.h>
#include "airo.h" #include "airo.h"
...@@ -5797,7 +5797,7 @@ static int airo_set_freq(struct net_device *dev, ...@@ -5797,7 +5797,7 @@ static int airo_set_freq(struct net_device *dev,
/* Hack to fall through... */ /* Hack to fall through... */
fwrq->e = 0; fwrq->e = 0;
fwrq->m = ieee80211_freq_to_dsss_chan(f); fwrq->m = ieee80211_frequency_to_channel(f);
} }
/* Setting by channel number */ /* Setting by channel number */
if((fwrq->m > 1000) || (fwrq->e > 0)) if((fwrq->m > 1000) || (fwrq->e > 0))
...@@ -5841,7 +5841,8 @@ static int airo_get_freq(struct net_device *dev, ...@@ -5841,7 +5841,8 @@ static int airo_get_freq(struct net_device *dev,
ch = le16_to_cpu(status_rid.channel); ch = le16_to_cpu(status_rid.channel);
if((ch > 0) && (ch < 15)) { 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; fwrq->e = 1;
} else { } else {
fwrq->m = ch; fwrq->m = ch;
...@@ -6898,7 +6899,8 @@ static int airo_get_range(struct net_device *dev, ...@@ -6898,7 +6899,8 @@ static int airo_get_range(struct net_device *dev,
k = 0; k = 0;
for(i = 0; i < 14; i++) { for(i = 0; i < 14; i++) {
range->freq[k].i = i + 1; /* List index */ 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->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */
} }
range->num_frequency = k; range->num_frequency = k;
...@@ -7297,7 +7299,8 @@ static inline char *airo_translate_scan(struct net_device *dev, ...@@ -7297,7 +7299,8 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* Add frequency */ /* Add frequency */
iwe.cmd = SIOCGIWFREQ; iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = le16_to_cpu(bss->dsChannel); 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; iwe.u.freq.e = 1;
current_ev = iwe_stream_add_event(info, current_ev, end_buf, current_ev = iwe_stream_add_event(info, current_ev, end_buf,
&iwe, IW_EV_FREQ_LEN); &iwe, IW_EV_FREQ_LEN);
......
...@@ -63,7 +63,7 @@ enum ath_bus_type { ...@@ -63,7 +63,7 @@ enum ath_bus_type {
}; };
struct reg_dmn_pair_mapping { struct reg_dmn_pair_mapping {
u16 regDmnEnum; u16 reg_domain;
u16 reg_5ghz_ctl; u16 reg_5ghz_ctl;
u16 reg_2ghz_ctl; u16 reg_2ghz_ctl;
}; };
...@@ -163,6 +163,7 @@ struct ath_common { ...@@ -163,6 +163,7 @@ struct ath_common {
bool bt_ant_diversity; bool bt_ant_diversity;
int last_rssi; int last_rssi;
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
}; };
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
......
...@@ -55,8 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) ...@@ -55,8 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
{ {
ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n"); ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
ar->is_target_paused = true; complete(&ar->target_suspend);
wake_up(&ar->event_queue);
} }
static int ath10k_init_connect_htc(struct ath10k *ar) static int ath10k_init_connect_htc(struct ath10k *ar)
...@@ -470,8 +469,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ...@@ -470,8 +469,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
if (index == ie_len) if (index == ie_len)
break; 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); __set_bit(i, ar->fw_features);
}
} }
ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
...@@ -699,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ...@@ -699,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
init_completion(&ar->scan.started); init_completion(&ar->scan.started);
init_completion(&ar->scan.completed); init_completion(&ar->scan.completed);
init_completion(&ar->scan.on_channel); init_completion(&ar->scan.on_channel);
init_completion(&ar->target_suspend);
init_completion(&ar->install_key_done); init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done); init_completion(&ar->vdev_setup_done);
...@@ -722,8 +726,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ...@@ -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); INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
skb_queue_head_init(&ar->wmi_mgmt_tx_queue); skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
init_waitqueue_head(&ar->event_queue);
INIT_WORK(&ar->restart_work, ath10k_core_restart); INIT_WORK(&ar->restart_work, ath10k_core_restart);
return ar; return ar;
...@@ -856,10 +858,34 @@ int ath10k_core_start(struct ath10k *ar) ...@@ -856,10 +858,34 @@ int ath10k_core_start(struct ath10k *ar)
} }
EXPORT_SYMBOL(ath10k_core_start); 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) void ath10k_core_stop(struct ath10k *ar)
{ {
lockdep_assert_held(&ar->conf_mutex); 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_debug_stop(ar);
ath10k_htc_stop(&ar->htc); ath10k_htc_stop(&ar->htc);
ath10k_htt_detach(&ar->htt); ath10k_htt_detach(&ar->htt);
......
...@@ -46,6 +46,18 @@ ...@@ -46,6 +46,18 @@
#define ATH10K_MAX_NUM_MGMT_PENDING 128 #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;
struct ath10k_skb_cb { struct ath10k_skb_cb {
...@@ -61,6 +73,11 @@ struct ath10k_skb_cb { ...@@ -61,6 +73,11 @@ struct ath10k_skb_cb {
u8 frag_len; u8 frag_len;
u8 pad_len; u8 pad_len;
} __packed htt; } __packed htt;
struct {
bool dtim_zero;
bool deliver_cab;
} bcn;
} __packed; } __packed;
static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
...@@ -211,6 +228,18 @@ struct ath10k_peer { ...@@ -211,6 +228,18 @@ struct ath10k_peer {
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; 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) #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
struct ath10k_vif { struct ath10k_vif {
...@@ -222,10 +251,17 @@ struct ath10k_vif { ...@@ -222,10 +251,17 @@ struct ath10k_vif {
u32 beacon_interval; u32 beacon_interval;
u32 dtim_period; u32 dtim_period;
struct sk_buff *beacon; struct sk_buff *beacon;
/* protected by data_lock */
bool beacon_sent;
struct ath10k *ar; struct ath10k *ar;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
bool is_started;
bool is_up;
u32 aid;
u8 bssid[ETH_ALEN];
struct work_struct wep_key_work; struct work_struct wep_key_work;
struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
u8 def_wep_key_idx; u8 def_wep_key_idx;
...@@ -235,7 +271,6 @@ struct ath10k_vif { ...@@ -235,7 +271,6 @@ struct ath10k_vif {
union { union {
struct { struct {
u8 bssid[ETH_ALEN];
u32 uapsd; u32 uapsd;
} sta; } sta;
struct { struct {
...@@ -249,9 +284,6 @@ struct ath10k_vif { ...@@ -249,9 +284,6 @@ struct ath10k_vif {
u32 noa_len; u32 noa_len;
u8 *noa_data; u8 *noa_data;
} ap; } ap;
struct {
u8 bssid[ETH_ALEN];
} ibss;
} u; } u;
u8 fixed_rate; u8 fixed_rate;
...@@ -355,8 +387,7 @@ struct ath10k { ...@@ -355,8 +387,7 @@ struct ath10k {
const struct ath10k_hif_ops *ops; const struct ath10k_hif_ops *ops;
} hif; } hif;
wait_queue_head_t event_queue; struct completion target_suspend;
bool is_target_paused;
struct ath10k_bmi bmi; struct ath10k_bmi bmi;
struct ath10k_wmi wmi; struct ath10k_wmi wmi;
...@@ -412,6 +443,9 @@ struct ath10k { ...@@ -412,6 +443,9 @@ struct ath10k {
/* valid during scan; needed for mgmt rx during scan */ /* valid during scan; needed for mgmt rx during scan */
struct ieee80211_channel *scan_channel; struct ieee80211_channel *scan_channel;
/* current operating channel definition */
struct cfg80211_chan_def chandef;
int free_vdev_map; int free_vdev_map;
int monitor_vdev_id; int monitor_vdev_id;
bool monitor_enabled; bool monitor_enabled;
...@@ -470,6 +504,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ...@@ -470,6 +504,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
void ath10k_core_destroy(struct ath10k *ar); void ath10k_core_destroy(struct ath10k *ar);
int ath10k_core_start(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); void ath10k_core_stop(struct ath10k *ar);
int ath10k_core_register(struct ath10k *ar, u32 chip_id); int ath10k_core_register(struct ath10k *ar, u32 chip_id);
void ath10k_core_unregister(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar);
......
...@@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar, ...@@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
#ifdef CONFIG_ATH10K_DEBUG #ifdef CONFIG_ATH10K_DEBUG
__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask, __printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
const char *fmt, ...); const char *fmt, ...);
void ath10k_dbg_dump(enum ath10k_debug_mask mask, void ath10k_dbg_dump(enum ath10k_debug_mask mask,
const char *msg, const char *prefix, const char *msg, const char *prefix,
const void *buf, size_t len); const void *buf, size_t len);
......
...@@ -324,7 +324,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, ...@@ -324,7 +324,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
msdu->len + skb_tailroom(msdu), msdu->len + skb_tailroom(msdu),
DMA_FROM_DEVICE); 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)); msdu->data, msdu->len + skb_tailroom(msdu));
rx_desc = (struct htt_rx_desc *)msdu->data; rx_desc = (struct htt_rx_desc *)msdu->data;
...@@ -417,8 +417,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, ...@@ -417,8 +417,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
next->len + skb_tailroom(next), next->len + skb_tailroom(next),
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
next->data, "htt rx chained: ", next->data,
next->len + skb_tailroom(next)); next->len + skb_tailroom(next));
skb_trim(next, 0); skb_trim(next, 0);
...@@ -430,12 +430,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, ...@@ -430,12 +430,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
msdu_chaining = 1; 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) & last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
RX_MSDU_END_INFO0_LAST_MSDU; 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) ...@@ -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. */ /* This shouldn't happen. If it does than it may be a FW bug. */
if (skb->next) { 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); ath10k_htt_rx_free_msdu_chain(skb->next);
skb->next = NULL; skb->next = NULL;
} }
...@@ -937,6 +931,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -937,6 +931,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
} }
if (ath10k_htt_rx_has_decrypt_err(msdu_head)) { 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); ath10k_htt_rx_free_msdu_chain(msdu_head);
continue; continue;
} }
...@@ -945,12 +941,14 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -945,12 +941,14 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
/* Skip mgmt frames while we handle this in WMI */ /* Skip mgmt frames while we handle this in WMI */
if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL) { 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); ath10k_htt_rx_free_msdu_chain(msdu_head);
continue; continue;
} }
if (status != HTT_RX_IND_MPDU_STATUS_OK && if (status != HTT_RX_IND_MPDU_STATUS_OK &&
status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
!htt->ar->monitor_enabled) { !htt->ar->monitor_enabled) {
ath10k_dbg(ATH10K_DBG_HTT, ath10k_dbg(ATH10K_DBG_HTT,
"htt rx ignoring frame w/ status %d\n", "htt rx ignoring frame w/ status %d\n",
...@@ -960,6 +958,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -960,6 +958,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
} }
if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { 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); ath10k_htt_rx_free_msdu_chain(msdu_head);
continue; continue;
} }
...@@ -967,7 +967,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -967,7 +967,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
/* FIXME: we do not support chaining yet. /* FIXME: we do not support chaining yet.
* this needs investigation */ * this needs investigation */
if (msdu_chaining) { 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); ath10k_htt_rx_free_msdu_chain(msdu_head);
continue; continue;
} }
...@@ -975,6 +975,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, ...@@ -975,6 +975,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
info.skb = msdu_head; info.skb = msdu_head;
info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head); info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
info.mic_err = ath10k_htt_rx_has_mic_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 = ATH10K_DEFAULT_NOISE_FLOOR;
info.signal += rx->ppdu.combined_rssi; info.signal += rx->ppdu.combined_rssi;
...@@ -1095,7 +1104,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, ...@@ -1095,7 +1104,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
skb_trim(info.skb, info.skb->len - trim); 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); info.skb->data, info.skb->len);
ath10k_process_rx(htt->ar, &info); ath10k_process_rx(htt->ar, &info);
...@@ -1116,7 +1125,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) ...@@ -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)) if (!IS_ALIGNED((unsigned long)skb->data, 4))
ath10k_warn("unaligned htt message, expect trouble\n"); 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); resp->hdr.msg_type);
switch (resp->hdr.msg_type) { switch (resp->hdr.msg_type) {
case HTT_T2H_MSG_TYPE_VERSION_CONF: { case HTT_T2H_MSG_TYPE_VERSION_CONF: {
......
...@@ -460,9 +460,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -460,9 +460,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
DMA_TO_DEVICE); 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); (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); msdu->data, msdu->len);
skb_put(txdesc, desc_len); skb_put(txdesc, desc_len);
......
...@@ -205,8 +205,11 @@ enum ath10k_mcast2ucast_mode { ...@@ -205,8 +205,11 @@ enum ath10k_mcast2ucast_mode {
#define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000
#define PCIE_LOCAL_BASE_ADDRESS 0x00080000 #define PCIE_LOCAL_BASE_ADDRESS 0x00080000
#define SOC_RESET_CONTROL_ADDRESS 0x00000000
#define SOC_RESET_CONTROL_OFFSET 0x00000000 #define SOC_RESET_CONTROL_OFFSET 0x00000000
#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 #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_OFFSET 0x00000020
#define SOC_CPU_CLOCK_STANDARD_LSB 0 #define SOC_CPU_CLOCK_STANDARD_LSB 0
#define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 #define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003
...@@ -216,6 +219,8 @@ enum ath10k_mcast2ucast_mode { ...@@ -216,6 +219,8 @@ enum ath10k_mcast2ucast_mode {
#define SOC_LPO_CAL_OFFSET 0x000000e0 #define SOC_LPO_CAL_OFFSET 0x000000e0
#define SOC_LPO_CAL_ENABLE_LSB 20 #define SOC_LPO_CAL_ENABLE_LSB 20
#define SOC_LPO_CAL_ENABLE_MASK 0x00100000 #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_ADDRESS 0x000000ec
#define SOC_CHIP_ID_REV_LSB 8 #define SOC_CHIP_ID_REV_LSB 8
...@@ -273,6 +278,7 @@ enum ath10k_mcast2ucast_mode { ...@@ -273,6 +278,7 @@ enum ath10k_mcast2ucast_mode {
#define PCIE_INTR_CAUSE_ADDRESS 0x000c #define PCIE_INTR_CAUSE_ADDRESS 0x000c
#define PCIE_INTR_CLR_ADDRESS 0x0014 #define PCIE_INTR_CLR_ADDRESS 0x0014
#define SCRATCH_3_ADDRESS 0x0030 #define SCRATCH_3_ADDRESS 0x0030
#define CPU_INTR_ADDRESS 0x0010
/* Firmware indications to the Host via SCRATCH_3 register. */ /* Firmware indications to the Host via SCRATCH_3 register. */
#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) #define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS)
......
...@@ -64,7 +64,8 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, ...@@ -64,7 +64,8 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
int num); int num);
static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
static void ath10k_pci_stop_ce(struct ath10k *ar); 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_wait_for_target_init(struct ath10k *ar);
static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_init_irq(struct ath10k *ar);
static int ath10k_pci_deinit_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) ...@@ -833,9 +834,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
ath10k_err("firmware crashed!\n"); ath10k_err("firmware crashed!\n");
ath10k_err("hardware name %s version 0x%x\n", ath10k_err("hardware name %s version 0x%x\n",
ar->hw_params.name, ar->target_version); ar->hw_params.name, ar->target_version);
ath10k_err("firmware version: %u.%u.%u.%u\n", ar->fw_version_major, ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
ar->fw_version_minor, ar->fw_version_release,
ar->fw_version_build);
host_addr = host_interest_item_address(HI_ITEM(hi_failure_state)); host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
ret = ath10k_pci_diag_read_mem(ar, host_addr, ret = ath10k_pci_diag_read_mem(ar, host_addr,
...@@ -1502,7 +1501,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ...@@ -1502,7 +1501,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
* configuration during init. If ringbuffers are freed and the device * configuration during init. If ringbuffers are freed and the device
* were to access them this could lead to memory corruption on the * were to access them this could lead to memory corruption on the
* host. */ * host. */
ath10k_pci_device_reset(ar); ath10k_pci_warm_reset(ar);
ar_pci->started = 0; ar_pci->started = 0;
} }
...@@ -1993,7 +1992,94 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ...@@ -1993,7 +1992,94 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
ath10k_pci_sleep(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); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
const char *irq_mode; const char *irq_mode;
...@@ -2009,7 +2095,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ...@@ -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 * is in an unexpected state. We try to catch that here in order to
* reset the Target and retry the probe. * 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) { if (ret) {
ath10k_err("failed to reset target: %d\n", ret); ath10k_err("failed to reset target: %d\n", ret);
goto err; goto err;
...@@ -2079,7 +2169,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ...@@ -2079,7 +2169,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
ath10k_pci_deinit_irq(ar); ath10k_pci_deinit_irq(ar);
err_ce: err_ce:
ath10k_pci_ce_deinit(ar); ath10k_pci_ce_deinit(ar);
ath10k_pci_device_reset(ar); ath10k_pci_warm_reset(ar);
err_ps: err_ps:
if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
ath10k_do_pci_sleep(ar); ath10k_do_pci_sleep(ar);
...@@ -2087,6 +2177,34 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) ...@@ -2087,6 +2177,34 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
return ret; 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) static void ath10k_pci_hif_power_down(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
...@@ -2094,7 +2212,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) ...@@ -2094,7 +2212,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
ath10k_pci_free_early_irq(ar); ath10k_pci_free_early_irq(ar);
ath10k_pci_kill_tasklet(ar); ath10k_pci_kill_tasklet(ar);
ath10k_pci_deinit_irq(ar); ath10k_pci_deinit_irq(ar);
ath10k_pci_device_reset(ar); ath10k_pci_warm_reset(ar);
ath10k_pci_ce_deinit(ar); ath10k_pci_ce_deinit(ar);
if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) 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) ...@@ -2411,11 +2529,10 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
/* Try MSI-X */ /* Try MSI-X */
if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) { if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
ar_pci->num_msi_intrs = MSI_NUM_REQUEST; ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs); ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
if (ret == 0) ar_pci->num_msi_intrs);
return 0;
if (ret > 0) if (ret > 0)
pci_disable_msi(ar_pci->pdev); return 0;
/* fall-through */ /* fall-through */
} }
...@@ -2482,6 +2599,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) ...@@ -2482,6 +2599,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
case MSI_NUM_REQUEST: case MSI_NUM_REQUEST:
pci_disable_msi(ar_pci->pdev); pci_disable_msi(ar_pci->pdev);
return 0; return 0;
default:
pci_disable_msi(ar_pci->pdev);
} }
ath10k_warn("unknown irq configuration upon deinit\n"); ath10k_warn("unknown irq configuration upon deinit\n");
...@@ -2523,7 +2642,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) ...@@ -2523,7 +2642,7 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
return ret; return ret;
} }
static int ath10k_pci_device_reset(struct ath10k *ar) static int ath10k_pci_cold_reset(struct ath10k *ar)
{ {
int i, ret; int i, ret;
u32 val; u32 val;
......
...@@ -259,7 +259,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) ...@@ -259,7 +259,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
status->freq = ch->center_freq; status->freq = ch->center_freq;
ath10k_dbg(ATH10K_DBG_DATA, 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,
info->skb->len, info->skb->len,
status->flag == 0 ? "legacy" : "", status->flag == 0 ? "legacy" : "",
...@@ -271,7 +271,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) ...@@ -271,7 +271,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
status->rate_idx, status->rate_idx,
status->vht_nss, status->vht_nss,
status->freq, status->freq,
status->band); status->band, status->flag, info->fcs_err);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
info->skb->data, info->skb->len); info->skb->data, info->skb->len);
......
...@@ -213,7 +213,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { ...@@ -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_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE,
.p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE, .p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE,
.p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, .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, .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
.peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID, .peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID,
.wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_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 = { ...@@ -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, .bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
.pmf_qos = WMI_PDEV_PARAM_PMF_QOS, .pmf_qos = WMI_PDEV_PARAM_PMF_QOS,
.arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE, .arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
.arpdhcp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
.dcs = WMI_PDEV_PARAM_DCS, .dcs = WMI_PDEV_PARAM_DCS,
.ani_enable = WMI_PDEV_PARAM_ANI_ENABLE, .ani_enable = WMI_PDEV_PARAM_ANI_ENABLE,
.ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD, .ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD,
...@@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { ...@@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
.bcnflt_stats_update_period = .bcnflt_stats_update_period =
WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
.pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS,
.arp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
.arpdhcp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
.dcs = WMI_10X_PDEV_PARAM_DCS, .dcs = WMI_10X_PDEV_PARAM_DCS,
.ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE, .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE,
.ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD,
...@@ -561,7 +559,6 @@ static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, ...@@ -561,7 +559,6 @@ static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
{ {
struct wmi_bcn_tx_arg arg = {0};
int ret; int ret;
lockdep_assert_held(&arvif->ar->data_lock); lockdep_assert_held(&arvif->ar->data_lock);
...@@ -569,18 +566,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) ...@@ -569,18 +566,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
if (arvif->beacon == NULL) if (arvif->beacon == NULL)
return; return;
arg.vdev_id = arvif->vdev_id; if (arvif->beacon_sent)
arg.tx_rate = 0; return;
arg.tx_power = 0;
arg.bcn = arvif->beacon->data;
arg.bcn_len = arvif->beacon->len;
ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg); ret = ath10k_wmi_beacon_send_ref_nowait(arvif);
if (ret) if (ret)
return; return;
dev_kfree_skb_any(arvif->beacon); /* We need to retain the arvif->beacon reference for DMA unmapping and
arvif->beacon = NULL; * freeing the skbuff later. */
arvif->beacon_sent = true;
} }
static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, 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, ...@@ -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, static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
struct sk_buff *skb) 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, ...@@ -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); tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);
memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); 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", ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
tim->dtim_count, tim->dtim_period, tim->dtim_count, tim->dtim_period,
tim->bitmap_ctrl, pvm_len); tim->bitmap_ctrl, pvm_len);
...@@ -1385,6 +1407,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ...@@ -1385,6 +1407,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
continue; 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); bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
if (!bcn) { if (!bcn) {
ath10k_warn("could not get mac80211 beacon\n"); 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) ...@@ -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); ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
if (arvif->beacon) { if (arvif->beacon) {
ath10k_warn("SWBA overrun on vdev %d\n", if (!arvif->beacon_sent)
arvif->vdev_id); ath10k_warn("SWBA overrun on vdev %d\n",
arvif->vdev_id);
ath10k_skb_unmap(ar->dev, arvif->beacon);
dev_kfree_skb_any(arvif->beacon); dev_kfree_skb_any(arvif->beacon);
} }
ath10k_skb_map(ar->dev, bcn);
arvif->beacon = bcn; arvif->beacon = bcn;
arvif->beacon_sent = false;
ath10k_wmi_tx_beacon_nowait(arvif); ath10k_wmi_tx_beacon_nowait(arvif);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
...@@ -2031,11 +2071,11 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -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); memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
ath10k_dbg(ATH10K_DBG_WMI, 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->sw_version),
__le32_to_cpu(ev->abi_version), __le32_to_cpu(ev->abi_version),
ev->mac_addr.addr, ev->mac_addr.addr,
__le32_to_cpu(ev->status)); __le32_to_cpu(ev->status), skb->len, sizeof(*ev));
complete(&ar->wmi.unified_ready); complete(&ar->wmi.unified_ready);
return 0; return 0;
...@@ -2403,7 +2443,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, ...@@ -2403,7 +2443,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
ar->wmi.cmd->pdev_set_channel_cmdid); 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 wmi_pdev_suspend_cmd *cmd;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -2413,7 +2453,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) ...@@ -2413,7 +2453,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar)
return -ENOMEM; return -ENOMEM;
cmd = (struct wmi_pdev_suspend_cmd *)skb->data; 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); 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, ...@@ -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); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
} }
int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, /* This function assumes the beacon is already DMA mapped */
const struct wmi_bcn_tx_arg *arg) 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 *skb;
struct sk_buff *beacon = arvif->beacon;
struct ath10k *ar = arvif->ar;
struct ieee80211_hdr *hdr;
int ret; int ret;
u16 fc;
skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
cmd = (struct wmi_bcn_tx_cmd *)skb->data; hdr = (struct ieee80211_hdr *)beacon->data;
cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id); fc = le16_to_cpu(hdr->frame_control);
cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate);
cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power); cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data;
cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
memcpy(cmd->bcn, arg->bcn, arg->bcn_len); 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) if (ret)
dev_kfree_skb(skb); dev_kfree_skb(skb);
......
...@@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map { ...@@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map {
u32 bcnflt_stats_update_period; u32 bcnflt_stats_update_period;
u32 pmf_qos; u32 pmf_qos;
u32 arp_ac_override; u32 arp_ac_override;
u32 arpdhcp_ac_override;
u32 dcs; u32 dcs;
u32 ani_enable; u32 ani_enable;
u32 ani_poll_period; u32 ani_poll_period;
...@@ -3403,6 +3402,24 @@ struct wmi_bcn_tx_arg { ...@@ -3403,6 +3402,24 @@ struct wmi_bcn_tx_arg {
const void *bcn; 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 */ /* Beacon filter */
#define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */ #define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */
#define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */ #define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */
...@@ -3859,6 +3876,12 @@ enum wmi_peer_smps_state { ...@@ -3859,6 +3876,12 @@ enum wmi_peer_smps_state {
WMI_PEER_SMPS_DYNAMIC = 0x2 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 { enum wmi_peer_param {
WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */ WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */
WMI_PEER_AMPDU = 0x2, WMI_PEER_AMPDU = 0x2,
...@@ -4039,6 +4062,10 @@ struct wmi_chan_info_event { ...@@ -4039,6 +4062,10 @@ struct wmi_chan_info_event {
__le32 cycle_count; __le32 cycle_count;
} __packed; } __packed;
struct wmi_peer_sta_kickout_event {
struct wmi_mac_addr peer_macaddr;
} __packed;
#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
/* FIXME: empirically extrapolated */ /* FIXME: empirically extrapolated */
...@@ -4172,7 +4199,7 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar); ...@@ -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_connect_htc_service(struct ath10k *ar);
int ath10k_wmi_pdev_set_channel(struct ath10k *ar, int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
const struct wmi_channel_arg *); 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_resume_target(struct ath10k *ar);
int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
u16 rd5g, u16 ctl2g, u16 ctl5g); 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, ...@@ -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); enum wmi_ap_ps_peer_param param_id, u32 value);
int ath10k_wmi_scan_chan_list(struct ath10k *ar, int ath10k_wmi_scan_chan_list(struct ath10k *ar,
const struct wmi_scan_chan_list_arg *arg); const struct wmi_scan_chan_list_arg *arg);
int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
const struct wmi_bcn_tx_arg *arg);
int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
const struct wmi_pdev_set_wmm_params_arg *arg); const struct wmi_pdev_set_wmm_params_arg *arg);
int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); 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) ...@@ -681,6 +681,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
survey->channel = conf->chandef.chan; survey->channel = conf->chandef.chan;
survey->noise = ah->ah_noise_floor; survey->noise = ah->ah_noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM | survey->filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_IN_USE |
SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_RX | SURVEY_INFO_CHANNEL_TIME_RX |
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
/* constants */ /* constants */
#define TX_URB_COUNT 32 #define TX_URB_COUNT 32
#define RX_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 */ /* tx/rx pipes for usb */
enum ATH6KL_USB_PIPE_ID { enum ATH6KL_USB_PIPE_ID {
...@@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb) ...@@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb)
* ATH6KL_USB_RX_BUFFER_SIZE); * 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_cnt_thresh = 1;
ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2;
ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA], ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA],
ATH6KL_USB_RX_BUFFER_SIZE); ATH6KL_USB_RX_BUFFER_SIZE);
} }
......
...@@ -914,7 +914,7 @@ ath6kl_get_regpair(u16 regdmn) ...@@ -914,7 +914,7 @@ ath6kl_get_regpair(u16 regdmn)
return NULL; return NULL;
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
if (regDomainPairs[i].regDmnEnum == regdmn) if (regDomainPairs[i].reg_domain == regdmn)
return &regDomainPairs[i]; return &regDomainPairs[i];
} }
...@@ -954,7 +954,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) ...@@ -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); country = ath6kl_regd_find_country_by_rd((u16) reg_code);
if (regpair) if (regpair)
ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
regpair->regDmnEnum); regpair->reg_domain);
else else
ath6kl_warn("Regpair not found reg_code 0x%0x\n", ath6kl_warn("Regpair not found reg_code 0x%0x\n",
reg_code); reg_code);
......
...@@ -51,7 +51,8 @@ ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ ...@@ -51,7 +51,8 @@ ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.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 \ ath9k_htc-y += htc_hst.o \
hif_usb.o \ hif_usb.o \
......
...@@ -176,16 +176,26 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, ...@@ -176,16 +176,26 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
if (ah->opmode == NL80211_IFTYPE_STATION && if (ah->opmode == NL80211_IFTYPE_STATION &&
BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH) BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
weak_sig = true; 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 && else if (AR_SREV_9300_20_OR_LATER(ah) &&
aniState->ofdmWeakSigDetect != weak_sig) { ah->opmode != NL80211_IFTYPE_STATION)
ath9k_hw_ani_control(ah, weak_sig = true;
ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
entry_ofdm->ofdm_weak_signal_on); /* 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) { if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
...@@ -483,10 +493,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ...@@ -483,10 +493,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ath_dbg(common, ANI, "Initialize ANI\n"); ath_dbg(common, ANI, "Initialize ANI\n");
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; if (AR_SREV_9300_20_OR_LATER(ah)) {
ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
ah->config.cck_trig_low = ATH9K_ANI_CCK_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->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
......
...@@ -22,12 +22,16 @@ ...@@ -22,12 +22,16 @@
/* units are errors per second */ /* units are errors per second */
#define ATH9K_ANI_OFDM_TRIG_HIGH 3500 #define ATH9K_ANI_OFDM_TRIG_HIGH 3500
#define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000 #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 400
#define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900 #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 600
#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200
#define ATH9K_ANI_CCK_TRIG_LOW 300 #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_SPUR_IMMUNE_LVL 3
#define ATH9K_ANI_FIRSTEP_LVL 2 #define ATH9K_ANI_FIRSTEP_LVL 2
......
...@@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah, ...@@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah,
if (IS_CHAN_A_FAST_CLOCK(ah, chan)) if (IS_CHAN_A_FAST_CLOCK(ah, chan))
rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); 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)) if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
......
...@@ -410,7 +410,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, ...@@ -410,7 +410,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
struct ath_beacon_config { struct ath_beacon_config {
int beacon_interval; int beacon_interval;
u16 listen_interval;
u16 dtim_period; u16 dtim_period;
u16 bmiss_timeout; u16 bmiss_timeout;
u8 dtim_count; u8 dtim_count;
...@@ -753,7 +752,6 @@ struct ath_softc { ...@@ -753,7 +752,6 @@ struct ath_softc {
struct ath_rx rx; struct ath_rx rx;
struct ath_tx tx; struct ath_tx tx;
struct ath_beacon beacon; struct ath_beacon beacon;
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
#ifdef CONFIG_MAC80211_LEDS #ifdef CONFIG_MAC80211_LEDS
bool led_registered; bool led_registered;
......
...@@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, ...@@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
u8 chainmask = ah->txchainmask; u8 chainmask = ah->txchainmask;
u8 rate = 0; 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; rate = sband->bitrates[rateidx].hw_value;
if (vif->bss_conf.use_short_preamble) if (vif->bss_conf.use_short_preamble)
rate |= sband->bitrates[rateidx].hw_value_short; rate |= sband->bitrates[rateidx].hw_value_short;
...@@ -519,7 +519,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, ...@@ -519,7 +519,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_beacon_state bs; struct ath9k_beacon_state bs;
int dtim_intval, sleepduration; int dtim_intval;
u32 nexttbtt = 0, intval; u32 nexttbtt = 0, intval;
u64 tsf; u64 tsf;
...@@ -538,7 +538,6 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, ...@@ -538,7 +538,6 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
* last beacon we received (which may be none). * last beacon we received (which may be none).
*/ */
dtim_intval = intval * conf->dtim_period; dtim_intval = intval * conf->dtim_period;
sleepduration = conf->listen_interval * intval;
/* /*
* Pull nexttbtt forward to reflect the current * Pull nexttbtt forward to reflect the current
...@@ -560,16 +559,11 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, ...@@ -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 * need calculate based on the beacon interval. Note that we clamp the
* result to at most 15 beacons. * result to at most 15 beacons.
*/ */
if (sleepduration > intval) { bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
bs.bs_bmissthreshold = conf->listen_interval * if (bs.bs_bmissthreshold > 15)
ATH_DEFAULT_BMISS_LIMIT / 2; bs.bs_bmissthreshold = 15;
} else { else if (bs.bs_bmissthreshold <= 0)
bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); bs.bs_bmissthreshold = 1;
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. * Calculate sleep duration. The configuration is given in ms.
...@@ -581,7 +575,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, ...@@ -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), bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
sleepduration)); intval));
if (bs.bs_sleepduration > bs.bs_dtimperiod) if (bs.bs_sleepduration > bs.bs_dtimperiod)
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, ...@@ -677,7 +671,6 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
cur_conf->beacon_interval = bss_conf->beacon_int; cur_conf->beacon_interval = bss_conf->beacon_int;
cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->dtim_period = bss_conf->dtim_period;
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1; cur_conf->dtim_count = 1;
cur_conf->ibss_creator = bss_conf->ibss_creator; cur_conf->ibss_creator = bss_conf->ibss_creator;
cur_conf->bmiss_timeout = cur_conf->bmiss_timeout =
......
/*
* 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);
/*
* 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 @@ ...@@ -21,6 +21,8 @@
#include "hw.h" #include "hw.h"
#include "hw-ops.h" #include "hw-ops.h"
#include "common-init.h"
/* Common header for Atheros 802.11n base driver cores */ /* Common header for Atheros 802.11n base driver cores */
#define WME_BA_BMP_SIZE 64 #define WME_BA_BMP_SIZE 64
......
...@@ -135,7 +135,8 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, ...@@ -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_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_hw *ah = 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; ssize_t retval = 0;
char *buf; char *buf;
...@@ -307,13 +308,13 @@ static ssize_t read_file_antenna_diversity(struct file *file, ...@@ -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_main = &sc->debug.stats.ant_stats[ANT_MAIN];
struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT]; struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
struct ath_hw_antcomb_conf div_ant_conf; 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; ssize_t retval = 0;
char *buf; char *buf;
char *lna_conf_str[4] = {"LNA1_MINUS_LNA2", static const char *lna_conf_str[4] = {
"LNA2", "LNA1_MINUS_LNA2", "LNA2", "LNA1", "LNA1_PLUS_LNA2"
"LNA1", };
"LNA1_PLUS_LNA2"};
buf = kzalloc(size, GFP_KERNEL); buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL) if (buf == NULL)
...@@ -716,10 +717,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf, ...@@ -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_softc *sc = file->private_data;
struct ath_txq *txq; struct ath_txq *txq;
char *buf; char *buf;
unsigned int len = 0, size = 1024; unsigned int len = 0;
const unsigned int size = 1024;
ssize_t retval = 0; ssize_t retval = 0;
int i; int i;
char *qname[4] = {"VO", "VI", "BE", "BK"}; static const char *qname[4] = {
"VO", "VI", "BE", "BK"
};
buf = kzalloc(size, GFP_KERNEL); buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL) if (buf == NULL)
...@@ -865,6 +869,12 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf, ...@@ -865,6 +869,12 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
len += scnprintf(buf + len, sizeof(buf) - len, len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "PLL RX Hang", "%17s: %2d\n", "PLL RX Hang",
sc->debug.stats.reset[RESET_TYPE_PLL_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, len += scnprintf(buf + len, sizeof(buf) - len,
"%17s: %2d\n", "MCI Reset", "%17s: %2d\n", "MCI Reset",
sc->debug.stats.reset[RESET_TYPE_MCI]); sc->debug.stats.reset[RESET_TYPE_MCI]);
......
...@@ -487,7 +487,6 @@ struct ath9k_htc_priv { ...@@ -487,7 +487,6 @@ struct ath9k_htc_priv {
unsigned long op_flags; unsigned long op_flags;
struct ath9k_hw_cal_data caldata; struct ath9k_hw_cal_data caldata;
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
spinlock_t beacon_lock; spinlock_t beacon_lock;
struct htc_beacon_config cur_beacon_conf; struct htc_beacon_config cur_beacon_conf;
......
...@@ -69,7 +69,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, ...@@ -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 ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_beacon_state bs; struct ath9k_beacon_state bs;
enum ath9k_int imask = 0; enum ath9k_int imask = 0;
int dtimperiod, dtimcount, sleepduration; int dtimperiod, dtimcount;
int bmiss_timeout; int bmiss_timeout;
u32 nexttbtt = 0, intval, tsftu; u32 nexttbtt = 0, intval, tsftu;
__be32 htc_imask = 0; __be32 htc_imask = 0;
...@@ -94,10 +94,6 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, ...@@ -94,10 +94,6 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
if (dtimcount >= dtimperiod) /* NB: sanity check */ if (dtimcount >= dtimperiod) /* NB: sanity check */
dtimcount = 0; dtimcount = 0;
sleepduration = intval;
if (sleepduration <= 0)
sleepduration = intval;
/* /*
* Pull nexttbtt forward to reflect the current * Pull nexttbtt forward to reflect the current
* TSF and calculate dtim state for the result. * TSF and calculate dtim state for the result.
...@@ -128,15 +124,11 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, ...@@ -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 * need calculate based on the beacon interval. Note that we clamp the
* result to at most 15 beacons. * result to at most 15 beacons.
*/ */
if (sleepduration > intval) { bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2; if (bs.bs_bmissthreshold > 15)
} else { bs.bs_bmissthreshold = 15;
bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); else if (bs.bs_bmissthreshold <= 0)
if (bs.bs_bmissthreshold > 15) bs.bs_bmissthreshold = 1;
bs.bs_bmissthreshold = 15;
else if (bs.bs_bmissthreshold <= 0)
bs.bs_bmissthreshold = 1;
}
/* /*
* Calculate sleep duration. The configuration is given in ms. * 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, ...@@ -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), bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
sleepduration)); intval));
if (bs.bs_sleepduration > bs.bs_dtimperiod) if (bs.bs_sleepduration > bs.bs_dtimperiod)
bs.bs_sleepduration = bs.bs_dtimperiod; bs.bs_sleepduration = bs.bs_dtimperiod;
......
...@@ -38,93 +38,6 @@ static int ath9k_ps_enable; ...@@ -38,93 +38,6 @@ static int ath9k_ps_enable;
module_param_named(ps_enable, ath9k_ps_enable, int, 0444); module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); 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 #ifdef CONFIG_MAC80211_LEDS
static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
{ .throughput = 0 * 1024, .blink_time = 334 }, { .throughput = 0 * 1024, .blink_time = 334 },
...@@ -343,6 +256,25 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, ...@@ -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) static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
{ {
struct ath_hw *ah = (struct ath_hw *) hw_priv; 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) ...@@ -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_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
u32 rsp_status;
int r;
mutex_lock(&priv->wmi->multi_write_mutex); mutex_lock(&priv->wmi->multi_write_mutex);
...@@ -383,19 +313,8 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) ...@@ -383,19 +313,8 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
priv->wmi->multi_write_idx++; priv->wmi->multi_write_idx++;
/* If the buffer is full, send it out. */ /* If the buffer is full, send it out. */
if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER)
r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, ath9k_regwrite_multi(common);
(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;
}
mutex_unlock(&priv->wmi->multi_write_mutex); mutex_unlock(&priv->wmi->multi_write_mutex);
} }
...@@ -426,26 +345,13 @@ static void ath9k_regwrite_flush(void *hw_priv) ...@@ -426,26 +345,13 @@ static void ath9k_regwrite_flush(void *hw_priv)
struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
u32 rsp_status;
int r;
atomic_dec(&priv->wmi->mwrite_cnt); atomic_dec(&priv->wmi->mwrite_cnt);
mutex_lock(&priv->wmi->multi_write_mutex); mutex_lock(&priv->wmi->multi_write_mutex);
if (priv->wmi->multi_write_idx) { if (priv->wmi->multi_write_idx)
r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, ath9k_regwrite_multi(common);
(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;
}
mutex_unlock(&priv->wmi->multi_write_mutex); mutex_unlock(&priv->wmi->multi_write_mutex);
} }
...@@ -491,51 +397,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = { ...@@ -491,51 +397,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = {
.eeprom_read = ath_usb_eeprom_read, .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) static int ath9k_init_queues(struct ath9k_htc_priv *priv)
{ {
struct ath_common *common = ath9k_hw_common(priv->ah); struct ath_common *common = ath9k_hw_common(priv->ah);
...@@ -580,31 +441,6 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv) ...@@ -580,31 +441,6 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)
return -EINVAL; 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) static void ath9k_init_misc(struct ath9k_htc_priv *priv)
{ {
struct ath_common *common = ath9k_hw_common(priv->ah); struct ath_common *common = ath9k_hw_common(priv->ah);
...@@ -629,6 +465,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ...@@ -629,6 +465,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
if (!ah) if (!ah)
return -ENOMEM; return -ENOMEM;
ah->dev = priv->dev;
ah->hw_version.devid = devid; ah->hw_version.devid = devid;
ah->hw_version.usbdev = drv_info; ah->hw_version.usbdev = drv_info;
ah->ah_flags |= AH_USE_EEPROM; ah->ah_flags |= AH_USE_EEPROM;
...@@ -685,8 +522,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ...@@ -685,8 +522,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
priv->cur_beacon_conf.bslot[i] = NULL; priv->cur_beacon_conf.bslot[i] = NULL;
ath9k_cmn_init_channels_rates(common);
ath9k_cmn_init_crypto(ah); ath9k_cmn_init_crypto(ah);
ath9k_init_channels_rates(priv);
ath9k_init_misc(priv); ath9k_init_misc(priv);
ath9k_htc_init_btcoex(priv, product); ath9k_htc_init_btcoex(priv, product);
...@@ -722,6 +559,7 @@ static const struct ieee80211_iface_combination if_comb = { ...@@ -722,6 +559,7 @@ static const struct ieee80211_iface_combination if_comb = {
static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
struct ieee80211_hw *hw) struct ieee80211_hw *hw)
{ {
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(priv->ah); struct ath_common *common = ath9k_hw_common(priv->ah);
struct base_eep_header *pBase; struct base_eep_header *pBase;
...@@ -766,19 +604,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, ...@@ -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) if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
hw->wiphy->bands[IEEE80211_BAND_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) if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
hw->wiphy->bands[IEEE80211_BAND_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) { ath9k_cmn_reload_chainmask(ah);
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);
}
pBase = ath9k_htc_get_eeprom_base(priv); pBase = ath9k_htc_get_eeprom_base(priv);
if (pBase) { if (pBase) {
......
...@@ -62,111 +62,6 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444); ...@@ -62,111 +62,6 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
bool is_ath9k_unloaded; 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 #ifdef CONFIG_MAC80211_LEDS
static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { 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 ...@@ -258,64 +153,6 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl
/* Initialization */ /* 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, static void ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request) struct regulatory_request *request)
{ {
...@@ -486,51 +323,6 @@ static int ath9k_init_queues(struct ath_softc *sc) ...@@ -486,51 +323,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
return 0; 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) static void ath9k_init_misc(struct ath_softc *sc)
{ {
struct ath_common *common = ath9k_hw_common(sc->sc_ah); 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, ...@@ -793,7 +585,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (ret) if (ret)
goto err_btcoex; goto err_btcoex;
ret = ath9k_init_channels_rates(sc); ret = ath9k_cmn_init_channels_rates(common);
if (ret) if (ret)
goto err_btcoex; goto err_btcoex;
...@@ -823,10 +615,11 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) ...@@ -823,10 +615,11 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
int i; int i;
sband = &sc->sbands[band]; sband = &common->sbands[band];
for (i = 0; i < sband->n_channels; i++) { for (i = 0; i < sband->n_channels; i++) {
chan = &sband->channels[i]; chan = &sband->channels[i];
ah->curchan = &ah->channels[chan->hw_value]; ah->curchan = &ah->channels[chan->hw_value];
...@@ -849,17 +642,6 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) ...@@ -849,17 +642,6 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc)
ah->curchan = curchan; 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[] = { static const struct ieee80211_iface_limit if_limits[] = {
{ .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
...@@ -949,6 +731,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -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_HAS_REMAIN_ON_CHANNEL;
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
hw->queues = 4; hw->queues = 4;
hw->max_rates = 4; hw->max_rates = 4;
...@@ -969,13 +752,13 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -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) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
hw->wiphy->bands[IEEE80211_BAND_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) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] = hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&sc->sbands[IEEE80211_BAND_5GHZ]; &common->sbands[IEEE80211_BAND_5GHZ];
ath9k_init_wow(hw); ath9k_init_wow(hw);
ath9k_reload_chainmask_settings(sc); ath9k_cmn_reload_chainmask(ah);
SET_IEEE80211_PERM_ADDR(hw, common->macaddr); SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
} }
......
...@@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data) ...@@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data)
* interrupts are enabled in the reset routine. * interrupts are enabled in the reset routine.
*/ */
atomic_inc(&ah->intr_ref_cnt); atomic_inc(&ah->intr_ref_cnt);
ath_dbg(common, ANY, "FATAL: Skipping interrupts\n"); ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
goto out; goto out;
} }
...@@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data) ...@@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data)
* interrupts are enabled in the reset routine. * interrupts are enabled in the reset routine.
*/ */
atomic_inc(&ah->intr_ref_cnt); atomic_inc(&ah->intr_ref_cnt);
ath_dbg(common, ANY, ath_dbg(common, RESET,
"BB_WATCHDOG: Skipping interrupts\n"); "BB_WATCHDOG: Skipping interrupts\n");
goto out; goto out;
} }
...@@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data) ...@@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data)
type = RESET_TYPE_TX_GTT; type = RESET_TYPE_TX_GTT;
ath9k_queue_reset(sc, type); ath9k_queue_reset(sc, type);
atomic_inc(&ah->intr_ref_cnt); atomic_inc(&ah->intr_ref_cnt);
ath_dbg(common, ANY, ath_dbg(common, RESET,
"GTT: Skipping interrupts\n"); "GTT: Skipping interrupts\n");
goto out; goto out;
} }
...@@ -2053,7 +2053,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ...@@ -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->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
ath9k_reload_chainmask_settings(sc); ath9k_cmn_reload_chainmask(ah);
return 0; return 0;
} }
......
...@@ -871,8 +871,16 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, ...@@ -871,8 +871,16 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
if (WARN_ON(!ah->curchan)) if (WARN_ON(!ah->curchan))
return -EINVAL; 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; return -EINVAL;
}
ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); 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) ...@@ -1040,11 +1040,11 @@ static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi)
int symbols, bits; int symbols, bits;
int bytes = 0; 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); symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec);
bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams; bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams;
bits -= OFDM_PLCP_BITS; bits -= OFDM_PLCP_BITS;
bytes = bits / 8; bytes = bits / 8;
bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
if (bytes > 65532) if (bytes > 65532)
bytes = 65532; bytes = 65532;
...@@ -1076,6 +1076,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, ...@@ -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_tx_info *info, int len, bool rts)
{ {
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_tx_info *tx_info; struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *rates; struct ieee80211_tx_rate *rates;
...@@ -1145,7 +1146,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, ...@@ -1145,7 +1146,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
} }
/* legacy rates */ /* 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) && if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
!(rate->flags & IEEE80211_RATE_ERP_G)) !(rate->flags & IEEE80211_RATE_ERP_G))
phy = WLAN_RC_PHY_CCK; phy = WLAN_RC_PHY_CCK;
......
...@@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void) ...@@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
static const struct static const struct
ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
{ {
switch (reg->regpair->regDmnEnum) { switch (reg->regpair->reg_domain) {
case 0x60: case 0x60:
case 0x61: case 0x61:
case 0x62: case 0x62:
...@@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, ...@@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator, enum nl80211_reg_initiator initiator,
struct ath_regulatory *reg) struct ath_regulatory *reg)
{ {
switch (reg->regpair->regDmnEnum) { switch (reg->regpair->reg_domain) {
case 0x60: case 0x60:
case 0x63: case 0x63:
case 0x66: case 0x66:
...@@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) ...@@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
printk(KERN_DEBUG "ath: EEPROM indicates we " printk(KERN_DEBUG "ath: EEPROM indicates we "
"should expect a direct regpair map\n"); "should expect a direct regpair map\n");
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
if (regDomainPairs[i].regDmnEnum == rd) if (regDomainPairs[i].reg_domain == rd)
return true; return true;
} }
printk(KERN_DEBUG printk(KERN_DEBUG
...@@ -617,7 +617,7 @@ ath_get_regpair(int regdmn) ...@@ -617,7 +617,7 @@ ath_get_regpair(int regdmn)
if (regdmn == NO_ENUMRD) if (regdmn == NO_ENUMRD)
return NULL; return NULL;
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
if (regDomainPairs[i].regDmnEnum == regdmn) if (regDomainPairs[i].reg_domain == regdmn)
return &regDomainPairs[i]; return &regDomainPairs[i];
} }
return NULL; return NULL;
...@@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg) ...@@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
reg->alpha2[0], reg->alpha2[1]); reg->alpha2[0], reg->alpha2[1]);
printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
reg->regpair->regDmnEnum); reg->regpair->reg_domain);
return 0; return 0;
} }
......
...@@ -9,6 +9,7 @@ wil6210-y += wmi.o ...@@ -9,6 +9,7 @@ wil6210-y += wmi.o
wil6210-y += interrupt.o wil6210-y += interrupt.o
wil6210-y += txrx.o wil6210-y += txrx.o
wil6210-y += debug.o wil6210-y += debug.o
wil6210-y += rx_reorder.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
# for tracing framework to find trace.h # for tracing framework to find trace.h
......
...@@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) ...@@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int wil_cfg80211_get_station(struct wiphy *wiphy, static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
struct net_device *ndev, struct station_info *sinfo)
u8 *mac, struct station_info *sinfo)
{ {
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int rc;
struct wmi_notify_req_cmd cmd = { struct wmi_notify_req_cmd cmd = {
.cid = 0, .cid = cid,
.interval_usec = 0, .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;
if (memcmp(mac, wil->dst_addr[0], ETH_ALEN))
return -ENOENT;
/* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
if (rc) if (rc)
return 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->generation = wil->sinfo_gen;
sinfo->filled |= STATION_INFO_TX_BITRATE; 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.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
sinfo->txrate.mcs = wil->stats.bf_mcs; sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
sinfo->filled |= STATION_INFO_RX_BITRATE;
sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
sinfo->rxrate.mcs = wil->stats.last_mcs_rx; 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)) { if (test_bit(wil_status_fwconnected, &wil->status)) {
sinfo->filled |= STATION_INFO_SIGNAL; sinfo->filled |= STATION_INFO_SIGNAL;
sinfo->signal = 12; /* TODO: provide real value */ sinfo->signal = reply.evt.sqi;
} }
return 0; 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;
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);
return rc;
}
/*
* Find @idx-th active STA for station dump.
*/
static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx)
{
int i;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
if (wil->sta[i].status == wil_sta_unused)
continue;
if (idx == 0)
return i;
idx--;
}
return -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, static int wil_cfg80211_change_iface(struct wiphy *wiphy,
...@@ -352,6 +436,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, ...@@ -352,6 +436,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
return rc; 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, static int wil_cfg80211_set_channel(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
...@@ -402,6 +520,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy, ...@@ -402,6 +520,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
return 0; 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, static int wil_fix_bcon(struct wil6210_priv *wil,
struct cfg80211_beacon_data *bcon) struct cfg80211_beacon_data *bcon)
{ {
...@@ -504,12 +657,24 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, ...@@ -504,12 +657,24 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
return rc; 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 = { static struct cfg80211_ops wil_cfg80211_ops = {
.scan = wil_cfg80211_scan, .scan = wil_cfg80211_scan,
.connect = wil_cfg80211_connect, .connect = wil_cfg80211_connect,
.disconnect = wil_cfg80211_disconnect, .disconnect = wil_cfg80211_disconnect,
.change_virtual_intf = wil_cfg80211_change_iface, .change_virtual_intf = wil_cfg80211_change_iface,
.get_station = wil_cfg80211_get_station, .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, .set_monitor_channel = wil_cfg80211_set_channel,
.add_key = wil_cfg80211_add_key, .add_key = wil_cfg80211_add_key,
.del_key = wil_cfg80211_del_key, .del_key = wil_cfg80211_del_key,
...@@ -517,6 +682,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { ...@@ -517,6 +682,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
/* AP mode */ /* AP mode */
.start_ap = wil_cfg80211_start_ap, .start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap, .stop_ap = wil_cfg80211_stop_ap,
.del_station = wil_cfg80211_del_station,
}; };
static void wil_wiphy_init(struct wiphy *wiphy) static void wil_wiphy_init(struct wiphy *wiphy)
...@@ -542,7 +708,7 @@ 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; wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;
/* TODO: figure this out */ /* 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->cipher_suites = wil_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
......
...@@ -26,9 +26,11 @@ ...@@ -26,9 +26,11 @@
/* Nasty hack. Better have per device instances */ /* Nasty hack. Better have per device instances */
static u32 mem_addr; static u32 mem_addr;
static u32 dbg_txdesc_index; 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, 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); 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, ...@@ -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; volatile struct vring_tx_desc *d = &vring->va[i].tx;
if ((i % 64) == 0 && (i != 0)) if ((i % 64) == 0 && (i != 0))
seq_printf(s, "\n"); seq_printf(s, "\n");
seq_printf(s, "%s", (d->dma.status & BIT(0)) ? seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
"S" : (vring->ctx[i].skb ? "H" : "h")); _s : (vring->ctx[i].skb ? _h : 'h'));
} }
seq_printf(s, "\n"); seq_printf(s, "\n");
} }
...@@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) ...@@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
uint i; uint i;
struct wil6210_priv *wil = s->private; 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++) { for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
struct vring *vring = &(wil->vring_tx[i]); struct vring *vring = &(wil->vring_tx[i]);
if (vring->va) { if (vring->va) {
int cid = wil->vring2cid_tid[i][0];
int tid = wil->vring2cid_tid[i][1];
char name[10]; char name[10];
snprintf(name, sizeof(name), "tx_%2d", i); 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 = { ...@@ -390,25 +397,40 @@ static const struct file_operations fops_reset = {
.write = wil_write_file_reset, .write = wil_write_file_reset,
.open = simple_open, .open = simple_open,
}; };
/*---------Tx descriptor------------*/
/*---------Tx/Rx descriptor------------*/
static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
{ {
struct wil6210_priv *wil = s->private; 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) { 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; return 0;
} }
if (dbg_txdesc_index < vring->size) { 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 = volatile struct vring_tx_desc *d =
&(vring->va[dbg_txdesc_index].tx); &(vring->va[dbg_txdesc_index].tx);
volatile u32 *u = (volatile u32 *)d; volatile u32 *u = (volatile u32 *)d;
struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; 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", seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
u[0], u[1], u[2], u[3]); u[0], u[1], u[2], u[3]);
seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
...@@ -439,8 +461,13 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) ...@@ -439,8 +461,13 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
} }
seq_printf(s, "}\n"); seq_printf(s, "}\n");
} else { } else {
seq_printf(s, "TxDesc index (%d) >= size (%d)\n", if (tx)
dbg_txdesc_index, vring->size); seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
dbg_vring_index, dbg_txdesc_index,
vring->size);
else
seq_printf(s, "RxDesc index (%d) >= size (%d)\n",
dbg_txdesc_index, vring->size);
} }
return 0; return 0;
...@@ -570,6 +597,68 @@ static const struct file_operations fops_temp = { ...@@ -570,6 +597,68 @@ static const struct file_operations fops_temp = {
.llseek = seq_lseek, .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) int wil6210_debugfs_init(struct wil6210_priv *wil)
{ {
...@@ -581,9 +670,13 @@ 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("mbox", S_IRUGO, dbg, wil, &fops_mbox);
debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
&dbg_txdesc_index); &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("bf", S_IRUGO, dbg, wil, &fops_bf);
debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
......
...@@ -16,8 +16,10 @@ ...@@ -16,8 +16,10 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include "wil6210.h" #include "wil6210.h"
#include "txrx.h"
/* /*
* Due to a hardware issue, * Due to a hardware issue,
...@@ -52,29 +54,75 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, ...@@ -52,29 +54,75 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
__raw_writel(*s++, d++); __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; uint i;
struct net_device *ndev = wil_to_ndev(wil); struct wil_sta_info *sta = &wil->sta[cid];
wil_dbg_misc(wil, "%s()\n", __func__); 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_link_off(wil); might_sleep();
if (test_bit(wil_status_fwconnected, &wil->status)) { if (bssid) {
clear_bit(wil_status_fwconnected, &wil->status); cid = wil_find_cid(wil, bssid);
cfg80211_disconnected(ndev, wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
WLAN_STATUS_UNSPECIFIED_FAILURE, } else {
NULL, 0, GFP_KERNEL); wil_dbg_misc(wil, "%s(all)\n", __func__);
} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
} }
clear_bit(wil_status_fwconnecting, &wil->status);
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
wil_vring_fini_tx(wil, i);
clear_bit(wil_status_dontscan, &wil->status); if (cid >= 0) /* disconnect 1 peer */
wil_disconnect_cid(wil, cid);
else /* disconnect all */
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
wil_disconnect_cid(wil, cid);
/* link state */
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
wil_link_off(wil);
if (test_bit(wil_status_fwconnected, &wil->status)) {
clear_bit(wil_status_fwconnected, &wil->status);
cfg80211_disconnected(ndev,
WLAN_STATUS_UNSPECIFIED_FAILURE,
NULL, 0, GFP_KERNEL);
} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
}
clear_bit(wil_status_fwconnecting, &wil->status);
wil_dbg_misc(wil, "clear_bit(wil_status_dontscan)\n");
clear_bit(wil_status_dontscan, &wil->status);
break;
default:
/* AP-like interface and monitor:
* never scan, always connected
*/
if (bssid)
cfg80211_del_sta(ndev, bssid, GFP_KERNEL);
break;
}
} }
static void wil_disconnect_worker(struct work_struct *work) static void wil_disconnect_worker(struct work_struct *work)
...@@ -97,12 +145,23 @@ static void wil_connect_timer_fn(ulong x) ...@@ -97,12 +145,23 @@ static void wil_connect_timer_fn(ulong x)
schedule_work(&wil->disconnect_worker); 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) static void wil_connect_worker(struct work_struct *work)
{ {
int rc; int rc;
struct wil6210_priv *wil = container_of(work, struct wil6210_priv, struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
connect_worker); connect_worker);
int cid = wil->pending_connect_cid; int cid = wil->pending_connect_cid;
int ringid = wil_find_free_vring(wil);
if (cid < 0) { if (cid < 0) {
wil_err(wil, "No connection pending\n"); wil_err(wil, "No connection pending\n");
...@@ -111,16 +170,22 @@ static void wil_connect_worker(struct work_struct *work) ...@@ -111,16 +170,22 @@ static void wil_connect_worker(struct work_struct *work)
wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid); 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; wil->pending_connect_cid = -1;
if (rc == 0) if (rc == 0) {
wil->sta[cid].status = wil_sta_connected;
wil_link_on(wil); wil_link_on(wil);
} else {
wil->sta[cid].status = wil_sta_unused;
}
} }
int wil_priv_init(struct wil6210_priv *wil) int wil_priv_init(struct wil6210_priv *wil)
{ {
wil_dbg_misc(wil, "%s()\n", __func__); wil_dbg_misc(wil, "%s()\n", __func__);
memset(wil->sta, 0, sizeof(wil->sta));
mutex_init(&wil->mutex); mutex_init(&wil->mutex);
mutex_init(&wil->wmi_mutex); mutex_init(&wil->wmi_mutex);
...@@ -370,3 +435,19 @@ int wil_down(struct wil6210_priv *wil) ...@@ -370,3 +435,19 @@ int wil_down(struct wil6210_priv *wil)
return rc; 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;
}
#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, ...@@ -344,6 +344,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
u16 dmalen; u16 dmalen;
u8 ftype; u8 ftype;
u8 ds_bits; u8 ds_bits;
int cid;
struct wil_net_stats *stats;
BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); 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, ...@@ -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, wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb_headlen(skb), false); skb->data, skb_headlen(skb), false);
cid = wil_rxdesc_cid(d);
wil->stats.last_mcs_rx = wil_rxdesc_mcs(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 */ /* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
...@@ -472,10 +477,14 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) ...@@ -472,10 +477,14 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count)
* Pass Rx packet to the netif. Update statistics. * Pass Rx packet to the netif. Update statistics.
* Called in softirq context (NAPI poll). * 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; int rc;
struct wil6210_priv *wil = ndev_to_wil(ndev);
unsigned int len = skb->len; 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); skb_orphan(skb);
...@@ -483,10 +492,13 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) ...@@ -483,10 +492,13 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
if (likely(rc == NET_RX_SUCCESS)) { if (likely(rc == NET_RX_SUCCESS)) {
ndev->stats.rx_packets++; ndev->stats.rx_packets++;
stats->rx_packets++;
ndev->stats.rx_bytes += len; ndev->stats.rx_bytes += len;
stats->rx_bytes += len;
} else { } else {
ndev->stats.rx_dropped++; ndev->stats.rx_dropped++;
stats->rx_dropped++;
} }
} }
...@@ -515,12 +527,18 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) ...@@ -515,12 +527,18 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->pkt_type = PACKET_OTHERHOST; skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = htons(ETH_P_802_2); skb->protocol = htons(ETH_P_802_2);
wil_netif_rx_any(skb, ndev);
} else { } else {
struct ethhdr *eth = (void *)skb->data;
skb->protocol = eth_type_trans(skb, ndev); 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); wil_rx_refill(wil, v->size);
} }
...@@ -598,6 +616,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, ...@@ -598,6 +616,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
if (rc) if (rc)
goto out; 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); 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), rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
...@@ -634,12 +655,83 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) ...@@ -634,12 +655,83 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
struct sk_buff *skb) 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 (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;
}
if (v->va) wil_err(wil, "Tx while no vrings active?\n");
return v;
return NULL; 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, static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
...@@ -740,9 +832,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, ...@@ -740,9 +832,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
} }
_d = &(vring->va[i].tx); _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, pa = dma_map_single(dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE); skb_headlen(skb), DMA_TO_DEVICE);
...@@ -836,6 +925,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, ...@@ -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) netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{ {
struct wil6210_priv *wil = ndev_to_wil(ndev); struct wil6210_priv *wil = ndev_to_wil(ndev);
struct ethhdr *eth = (void *)skb->data;
struct vring *vring; struct vring *vring;
int rc; int rc;
...@@ -854,9 +944,13 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -854,9 +944,13 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
} }
/* find vring */ /* find vring */
vring = wil_find_tx_vring(wil, skb); if (is_unicast_ether_addr(eth->h_dest)) {
vring = wil_find_tx_vring(wil, skb);
} else {
vring = wil_tx_bcast(wil, skb);
}
if (!vring) { 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; goto drop;
} }
/* set up vring entry */ /* set up vring entry */
...@@ -892,6 +986,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) ...@@ -892,6 +986,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct vring *vring = &wil->vring_tx[ringid]; struct vring *vring = &wil->vring_tx[ringid];
int done = 0; int done = 0;
int cid = wil->vring2cid_tid[ringid][0];
struct wil_net_stats *stats = &wil->sta[cid].stats;
if (!vring->va) { if (!vring->va) {
wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); 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) ...@@ -933,9 +1029,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
if (skb) { if (skb) {
if (d->dma.error == 0) { if (d->dma.error == 0) {
ndev->stats.tx_packets++; ndev->stats.tx_packets++;
stats->tx_packets++;
ndev->stats.tx_bytes += skb->len; ndev->stats.tx_bytes += skb->len;
stats->tx_bytes += skb->len;
} else { } else {
ndev->stats.tx_errors++; ndev->stats.tx_errors++;
stats->tx_errors++;
} }
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
......
...@@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb) ...@@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
return (void *)skb->cb; 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 */ #endif /* WIL6210_TXRX_H */
...@@ -215,6 +215,46 @@ enum { /* for wil6210_priv.status */ ...@@ -215,6 +215,46 @@ enum { /* for wil6210_priv.status */
struct pci_dev; 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 { struct wil6210_stats {
u64 tsf; u64 tsf;
u32 snr; u32 snr;
...@@ -226,6 +266,42 @@ struct wil6210_stats { ...@@ -226,6 +266,42 @@ struct wil6210_stats {
u16 peer_tx_sector; 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 wil6210_priv {
struct pci_dev *pdev; struct pci_dev *pdev;
int n_msi; int n_msi;
...@@ -267,7 +343,8 @@ struct wil6210_priv { ...@@ -267,7 +343,8 @@ struct wil6210_priv {
/* DMA related */ /* DMA related */
struct vring vring_rx; struct vring vring_rx;
struct vring vring_tx[WIL6210_MAX_TX_RINGS]; 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 */ /* scan */
struct cfg80211_scan_request *scan_request; struct cfg80211_scan_request *scan_request;
...@@ -334,6 +411,7 @@ void wil_link_off(struct wil6210_priv *wil); ...@@ -334,6 +411,7 @@ void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil);
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); 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_buffer(struct wil6210_priv *wil, __le32 ptr);
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
...@@ -357,7 +435,9 @@ int wmi_echo(struct wil6210_priv *wil); ...@@ -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_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_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); 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_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); int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_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) ...@@ -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, u32 freq = ieee80211_channel_to_frequency(ch_no,
IEEE80211_BAND_60GHZ); IEEE80211_BAND_60GHZ);
struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq);
/* TODO convert LE to CPU */ s32 signal = data->info.sqi;
s32 signal = 0; /* TODO */
__le16 fc = rx_mgmt_frame->frame_control; __le16 fc = rx_mgmt_frame->frame_control;
u32 d_len = le32_to_cpu(data->info.len); u32 d_len = le32_to_cpu(data->info.len);
u16 d_status = le16_to_cpu(data->info.status); u16 d_status = le16_to_cpu(data->info.status);
wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n", 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.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, wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
le16_to_cpu(fc)); le16_to_cpu(fc));
wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", 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) ...@@ -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); evt->assoc_req_len, evt->assoc_resp_len);
return; return;
} }
if (evt->cid >= WIL6210_MAX_CID) {
wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
return;
}
ch = evt->channel + 1; ch = evt->channel + 1;
wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
evt->bssid, ch, evt->cid); evt->bssid, ch, evt->cid);
...@@ -439,7 +444,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) ...@@ -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 FW can transmit only ucast frames to peer */
/* FIXME real ring_id instead of hard coded 0 */ /* 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; wil->pending_connect_cid = evt->cid;
queue_work(wil->wmi_wq_conn, &wil->connect_worker); 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) ...@@ -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_rx_sector = le16_to_cpu(evt->other_rx_sector);
wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_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" 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" "Tx Tpt %d goodput %d Rx goodput %d\n"
"Sectors(rx:tx) my %d:%d peer %d:%d\n", "Sectors(rx:tx) my %d:%d peer %d:%d\n",
wil->stats.bf_mcs, wil->stats.tsf, evt->status, 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), le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
wil->stats.my_rx_sector, wil->stats.my_tx_sector, wil->stats.my_rx_sector, wil->stats.my_tx_sector,
wil->stats.peer_rx_sector, wil->stats.peer_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, ...@@ -499,10 +505,16 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
int sz = eapol_len + ETH_HLEN; int sz = eapol_len + ETH_HLEN;
struct sk_buff *skb; struct sk_buff *skb;
struct ethhdr *eth; struct ethhdr *eth;
int cid;
struct wil_net_stats *stats = NULL;
wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
evt->src_mac); 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 */ if (eapol_len > 196) { /* TODO: revisit size limit */
wil_err(wil, "EAPOL too large\n"); wil_err(wil, "EAPOL too large\n");
return; return;
...@@ -513,6 +525,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, ...@@ -513,6 +525,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
wil_err(wil, "Failed to allocate skb\n"); wil_err(wil, "Failed to allocate skb\n");
return; return;
} }
eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);
memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);
memcpy(eth->h_source, evt->src_mac, 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, ...@@ -521,9 +534,15 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
skb->protocol = eth_type_trans(skb, ndev); skb->protocol = eth_type_trans(skb, ndev);
if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
ndev->stats.rx_packets++; 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 { } else {
ndev->stats.rx_dropped++; 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, ...@@ -552,10 +571,42 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
int len) int len)
{ {
struct wmi_vring_ba_status_event *evt = d; 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", wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize, evt->ringid,
__le16_to_cpu(evt->ba_timeout)); 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 { static const struct {
...@@ -893,6 +944,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) ...@@ -893,6 +944,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
return rc; 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) int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
{ {
struct wireless_dev *wdev = wil->wdev; struct wireless_dev *wdev = wil->wdev;
...@@ -906,6 +989,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) ...@@ -906,6 +989,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
}, },
.mid = 0, /* TODO - what is it? */ .mid = 0, /* TODO - what is it? */
.decap_trans_type = WMI_DECAP_TYPE_802_3, .decap_trans_type = WMI_DECAP_TYPE_802_3,
.reorder_type = WMI_RX_SW_REORDER,
}; };
struct { struct {
struct wil6210_mbox_hdr_wmi wmi; struct wil6210_mbox_hdr_wmi wmi;
...@@ -973,6 +1057,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) ...@@ -973,6 +1057,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
return 0; 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) void wmi_event_flush(struct wil6210_priv *wil)
{ {
struct pending_wmi_event *evt, *t; struct pending_wmi_event *evt, *t;
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/ieee80211.h> #include <net/cfg80211.h>
#include "atmel.h" #include "atmel.h"
#define DRIVER_MAJOR 0 #define DRIVER_MAJOR 0
...@@ -2273,7 +2273,7 @@ static int atmel_set_freq(struct net_device *dev, ...@@ -2273,7 +2273,7 @@ static int atmel_set_freq(struct net_device *dev,
/* Hack to fall through... */ /* Hack to fall through... */
fwrq->e = 0; fwrq->e = 0;
fwrq->m = ieee80211_freq_to_dsss_chan(f); fwrq->m = ieee80211_frequency_to_channel(f);
} }
/* Setting by channel number */ /* Setting by channel number */
if ((fwrq->m > 1000) || (fwrq->e > 0)) if ((fwrq->m > 1000) || (fwrq->e > 0))
...@@ -2434,8 +2434,8 @@ static int atmel_get_range(struct net_device *dev, ...@@ -2434,8 +2434,8 @@ static int atmel_get_range(struct net_device *dev,
range->freq[k].i = i; /* List index */ range->freq[k].i = i; /* List index */
/* Values in MHz -> * 10^5 * 10 */ /* Values in MHz -> * 10^5 * 10 */
range->freq[k].m = (ieee80211_dsss_chan_to_freq(i) * range->freq[k].m = 100000 *
100000); ieee80211_channel_to_frequency(i, IEEE80211_BAND_2GHZ);
range->freq[k++].e = 1; range->freq[k++].e = 1;
} }
range->num_frequency = k; range->num_frequency = k;
......
...@@ -92,7 +92,7 @@ config B43_SDIO ...@@ -92,7 +92,7 @@ config B43_SDIO
# if we can do DMA. # if we can do DMA.
config B43_BCMA_PIO config B43_BCMA_PIO
bool bool
depends on B43_BCMA depends on B43 && B43_BCMA
select BCMA_BLOCKIO select BCMA_BLOCKIO
default y default y
......
...@@ -86,7 +86,7 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev, ...@@ -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) static inline bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
{ {
return 0; return false;
} }
static inline void b43_debugfs_init(void) static inline void b43_debugfs_init(void)
......
...@@ -1549,7 +1549,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, ...@@ -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); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); 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)); 0x200 - sizeof(struct b43_plcp_hdr6));
rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
......
...@@ -133,9 +133,9 @@ void b43_phy_exit(struct b43_wldev *dev) ...@@ -133,9 +133,9 @@ void b43_phy_exit(struct b43_wldev *dev)
bool b43_has_hardware_pctl(struct b43_wldev *dev) bool b43_has_hardware_pctl(struct b43_wldev *dev)
{ {
if (!dev->phy.hardware_power_control) if (!dev->phy.hardware_power_control)
return 0; return false;
if (!dev->phy.ops->supports_hwpctl) if (!dev->phy.ops->supports_hwpctl)
return 0; return false;
return dev->phy.ops->supports_hwpctl(dev); return dev->phy.ops->supports_hwpctl(dev);
} }
......
...@@ -637,7 +637,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) ...@@ -637,7 +637,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
ctl = b43_piorx_read32(q, B43_PIO8_RXCTL); ctl = b43_piorx_read32(q, B43_PIO8_RXCTL);
if (!(ctl & B43_PIO8_RXCTL_FRAMERDY)) if (!(ctl & B43_PIO8_RXCTL_FRAMERDY))
return 0; return false;
b43_piorx_write32(q, B43_PIO8_RXCTL, b43_piorx_write32(q, B43_PIO8_RXCTL,
B43_PIO8_RXCTL_FRAMERDY); B43_PIO8_RXCTL_FRAMERDY);
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
...@@ -651,7 +651,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) ...@@ -651,7 +651,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
ctl = b43_piorx_read16(q, B43_PIO_RXCTL); ctl = b43_piorx_read16(q, B43_PIO_RXCTL);
if (!(ctl & B43_PIO_RXCTL_FRAMERDY)) if (!(ctl & B43_PIO_RXCTL_FRAMERDY))
return 0; return false;
b43_piorx_write16(q, B43_PIO_RXCTL, b43_piorx_write16(q, B43_PIO_RXCTL,
B43_PIO_RXCTL_FRAMERDY); B43_PIO_RXCTL_FRAMERDY);
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
...@@ -662,7 +662,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) ...@@ -662,7 +662,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
} }
} }
b43dbg(q->dev->wl, "PIO RX timed out\n"); b43dbg(q->dev->wl, "PIO RX timed out\n");
return 1; return true;
data_ready: data_ready:
/* Get the preamble (RX header) */ /* Get the preamble (RX header) */
...@@ -759,7 +759,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) ...@@ -759,7 +759,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
b43_rx(q->dev, skb, rxhdr); b43_rx(q->dev, skb, rxhdr);
return 1; return true;
rx_error: rx_error:
if (err_msg) if (err_msg)
...@@ -769,7 +769,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) ...@@ -769,7 +769,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
else else
b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY); b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY);
return 1; return true;
} }
void b43_pio_rx(struct b43_pio_rxqueue *q) void b43_pio_rx(struct b43_pio_rxqueue *q)
......
...@@ -40,7 +40,7 @@ static int get_integer(const char *buf, size_t count) ...@@ -40,7 +40,7 @@ static int get_integer(const char *buf, size_t count)
if (count == 0) if (count == 0)
goto out; goto out;
count = min(count, (size_t) 10); count = min_t(size_t, count, 10);
memcpy(tmp, buf, count); memcpy(tmp, buf, count);
ret = simple_strtol(tmp, NULL, 10); ret = simple_strtol(tmp, NULL, 10);
out: out:
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册