Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts: drivers/net/wireless/ath/ath9k/recv.c
This commit is contained in:
		
				commit
				
					
						42775a34d2
					
				
			
		
					 314 changed files with 30435 additions and 4694 deletions
				
			
		| 
						 | 
					@ -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.
 | 
				
			||||||
		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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										39
									
								
								Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					* Texas Instruments wl1251 wireless lan controller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The wl1251 chip can be connected via SPI or via SDIO. This
 | 
				
			||||||
 | 
					document describes the binding for the SPI connected chip.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Required properties:
 | 
				
			||||||
 | 
					- compatible :        Should be "ti,wl1251"
 | 
				
			||||||
 | 
					- reg :               Chip select address of device
 | 
				
			||||||
 | 
					- spi-max-frequency : Maximum SPI clocking speed of device in Hz
 | 
				
			||||||
 | 
					- interrupts :        Should contain interrupt line
 | 
				
			||||||
 | 
					- interrupt-parent :  Should be the phandle for the interrupt controller
 | 
				
			||||||
 | 
					                      that services interrupts for this device
 | 
				
			||||||
 | 
					- vio-supply :        phandle to regulator providing VIO
 | 
				
			||||||
 | 
					- ti,power-gpio :     GPIO connected to chip's PMEN pin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Optional properties:
 | 
				
			||||||
 | 
					- ti,wl1251-has-eeprom : boolean, the wl1251 has an eeprom connected, which
 | 
				
			||||||
 | 
					                         provides configuration data (calibration, MAC, ...)
 | 
				
			||||||
 | 
					- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
 | 
				
			||||||
 | 
					  for optional SPI connection related properties,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Examples:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					&spi1 {
 | 
				
			||||||
 | 
						wl1251@0 {
 | 
				
			||||||
 | 
							compatible = "ti,wl1251";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							reg = <0>;
 | 
				
			||||||
 | 
							spi-max-frequency = <48000000>;
 | 
				
			||||||
 | 
							spi-cpol;
 | 
				
			||||||
 | 
							spi-cpha;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							interrupt-parent = <&gpio2>;
 | 
				
			||||||
 | 
							interrupts = <10 IRQ_TYPE_NONE>; /* gpio line 42 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vio-supply = <&vio>;
 | 
				
			||||||
 | 
							ti,power-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -536,11 +536,13 @@ static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __init pandora_wl1251_init(void)
 | 
					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)
 | 
				
			||||||
		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 {
 | 
				
			||||||
	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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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)
 | 
				
			||||||
	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[] = {
 | 
				
			||||||
	{ 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);
 | 
				
			||||||
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,10 +101,10 @@ 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 */
 | 
				
			||||||
| 
						 | 
					@ -116,6 +116,9 @@ static const struct usb_device_id btusb_table[] = {
 | 
				
			||||||
	/* 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[] = {
 | 
				
			||||||
	{ 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 = {
 | 
				
			||||||
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);
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 @@
 | 
				
			||||||
#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 @@
 | 
				
			||||||
#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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* 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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	/* 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 {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 {
 | 
				
			||||||
	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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	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,9 +469,13 @@ 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", "",
 | 
				
			||||||
					ar->fw_features,
 | 
										ar->fw_features,
 | 
				
			||||||
| 
						 | 
					@ -699,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
 | 
				
			||||||
	init_completion(&ar->scan.started);
 | 
						init_completion(&ar->scan.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,
 | 
				
			||||||
	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 @@ err:
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
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 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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 {
 | 
				
			||||||
		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 {
 | 
				
			||||||
	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 {
 | 
				
			||||||
	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 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
			u8 bssid[ETH_ALEN];
 | 
					 | 
				
			||||||
			u32 uapsd;
 | 
								u32 uapsd;
 | 
				
			||||||
		} sta;
 | 
							} sta;
 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
| 
						 | 
					@ -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 {
 | 
				
			||||||
		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 {
 | 
				
			||||||
	/* 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,
 | 
				
			||||||
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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
					 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,
 | 
				
			||||||
			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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 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,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* 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,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			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,
 | 
				
			||||||
			/* 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,
 | 
				
			||||||
			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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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)
 | 
				
			||||||
	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)
 | 
				
			||||||
					   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 {
 | 
				
			||||||
#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 {
 | 
				
			||||||
#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 {
 | 
				
			||||||
#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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -339,6 +339,50 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ath10k *ar = arvif->ar;
 | 
				
			||||||
 | 
						u32 param;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						param = ar->wmi.pdev_param->sta_kickout_th;
 | 
				
			||||||
 | 
						ret = ath10k_wmi_pdev_set_param(ar, param,
 | 
				
			||||||
 | 
										ATH10K_KICKOUT_THRESHOLD);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							ath10k_warn("Failed to set kickout threshold: %d\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs;
 | 
				
			||||||
 | 
						ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
 | 
				
			||||||
 | 
										ATH10K_KEEPALIVE_MIN_IDLE);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							ath10k_warn("Failed to set keepalive minimum idle time : %d\n",
 | 
				
			||||||
 | 
								    ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs;
 | 
				
			||||||
 | 
						ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
 | 
				
			||||||
 | 
										ATH10K_KEEPALIVE_MAX_IDLE);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							ath10k_warn("Failed to set keepalive maximum idle time: %d\n",
 | 
				
			||||||
 | 
								    ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs;
 | 
				
			||||||
 | 
						ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
 | 
				
			||||||
 | 
										ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							ath10k_warn("Failed to set keepalive maximum unresponsive time: %d\n",
 | 
				
			||||||
 | 
								    ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int  ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
 | 
					static int  ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ath10k *ar = arvif->ar;
 | 
						struct ath10k *ar = arvif->ar;
 | 
				
			||||||
| 
						 | 
					@ -444,8 +488,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
 | 
				
			||||||
static int ath10k_vdev_start(struct ath10k_vif *arvif)
 | 
					static int ath10k_vdev_start(struct ath10k_vif *arvif)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ath10k *ar = arvif->ar;
 | 
						struct ath10k *ar = arvif->ar;
 | 
				
			||||||
	struct ieee80211_conf *conf = &ar->hw->conf;
 | 
						struct cfg80211_chan_def *chandef = &ar->chandef;
 | 
				
			||||||
	struct ieee80211_channel *channel = conf->chandef.chan;
 | 
					 | 
				
			||||||
	struct wmi_vdev_start_request_arg arg = {};
 | 
						struct wmi_vdev_start_request_arg arg = {};
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -457,16 +500,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
 | 
				
			||||||
	arg.dtim_period = arvif->dtim_period;
 | 
						arg.dtim_period = arvif->dtim_period;
 | 
				
			||||||
	arg.bcn_intval = arvif->beacon_interval;
 | 
						arg.bcn_intval = arvif->beacon_interval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	arg.channel.freq = channel->center_freq;
 | 
						arg.channel.freq = chandef->chan->center_freq;
 | 
				
			||||||
 | 
						arg.channel.band_center_freq1 = chandef->center_freq1;
 | 
				
			||||||
	arg.channel.band_center_freq1 = conf->chandef.center_freq1;
 | 
						arg.channel.mode = chan_to_phymode(chandef);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	arg.channel.mode = chan_to_phymode(&conf->chandef);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	arg.channel.min_power = 0;
 | 
						arg.channel.min_power = 0;
 | 
				
			||||||
	arg.channel.max_power = channel->max_power * 2;
 | 
						arg.channel.max_power = chandef->chan->max_power * 2;
 | 
				
			||||||
	arg.channel.max_reg_power = channel->max_reg_power * 2;
 | 
						arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
 | 
				
			||||||
	arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
 | 
						arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 | 
						if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 | 
				
			||||||
		arg.ssid = arvif->u.ap.ssid;
 | 
							arg.ssid = arvif->u.ap.ssid;
 | 
				
			||||||
| 
						 | 
					@ -475,7 +516,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* For now allow DFS for AP mode */
 | 
							/* For now allow DFS for AP mode */
 | 
				
			||||||
		arg.channel.chan_radar =
 | 
							arg.channel.chan_radar =
 | 
				
			||||||
			!!(channel->flags & IEEE80211_CHAN_RADAR);
 | 
								!!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
 | 
				
			||||||
	} else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
 | 
						} else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
 | 
				
			||||||
		arg.ssid = arvif->vif->bss_conf.ssid;
 | 
							arg.ssid = arvif->vif->bss_conf.ssid;
 | 
				
			||||||
		arg.ssid_len = arvif->vif->bss_conf.ssid_len;
 | 
							arg.ssid_len = arvif->vif->bss_conf.ssid_len;
 | 
				
			||||||
| 
						 | 
					@ -527,7 +568,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 | 
					static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ieee80211_channel *channel = ar->hw->conf.chandef.chan;
 | 
						struct cfg80211_chan_def *chandef = &ar->chandef;
 | 
				
			||||||
 | 
						struct ieee80211_channel *channel = chandef->chan;
 | 
				
			||||||
	struct wmi_vdev_start_request_arg arg = {};
 | 
						struct wmi_vdev_start_request_arg arg = {};
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -540,11 +582,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	arg.vdev_id = vdev_id;
 | 
						arg.vdev_id = vdev_id;
 | 
				
			||||||
	arg.channel.freq = channel->center_freq;
 | 
						arg.channel.freq = channel->center_freq;
 | 
				
			||||||
	arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1;
 | 
						arg.channel.band_center_freq1 = chandef->center_freq1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO setup this dynamically, what in case we
 | 
						/* TODO setup this dynamically, what in case we
 | 
				
			||||||
	   don't have any vifs? */
 | 
						   don't have any vifs? */
 | 
				
			||||||
	arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef);
 | 
						arg.channel.mode = chan_to_phymode(chandef);
 | 
				
			||||||
	arg.channel.chan_radar =
 | 
						arg.channel.chan_radar =
 | 
				
			||||||
			!!(channel->flags & IEEE80211_CHAN_RADAR);
 | 
								!!(channel->flags & IEEE80211_CHAN_RADAR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -791,6 +833,20 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!info->enable_beacon) {
 | 
						if (!info->enable_beacon) {
 | 
				
			||||||
		ath10k_vdev_stop(arvif);
 | 
							ath10k_vdev_stop(arvif);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							arvif->is_started = false;
 | 
				
			||||||
 | 
							arvif->is_up = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							spin_lock_bh(&arvif->ar->data_lock);
 | 
				
			||||||
 | 
							if (arvif->beacon) {
 | 
				
			||||||
 | 
								ath10k_skb_unmap(arvif->ar->dev, arvif->beacon);
 | 
				
			||||||
 | 
								dev_kfree_skb_any(arvif->beacon);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								arvif->beacon = NULL;
 | 
				
			||||||
 | 
								arvif->beacon_sent = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							spin_unlock_bh(&arvif->ar->data_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -800,12 +856,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid);
 | 
						arvif->aid = 0;
 | 
				
			||||||
 | 
						memcpy(arvif->bssid, info->bssid, ETH_ALEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
 | 
				
			||||||
 | 
									 arvif->bssid);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		ath10k_warn("Failed to bring up VDEV: %d\n",
 | 
							ath10k_warn("Failed to bring up VDEV: %d\n",
 | 
				
			||||||
			    arvif->vdev_id);
 | 
								    arvif->vdev_id);
 | 
				
			||||||
 | 
							ath10k_vdev_stop(arvif);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arvif->is_started = true;
 | 
				
			||||||
 | 
						arvif->is_up = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
 | 
						ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -824,18 +889,18 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
 | 
				
			||||||
			ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n",
 | 
								ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n",
 | 
				
			||||||
				    self_peer, arvif->vdev_id, ret);
 | 
									    self_peer, arvif->vdev_id, ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (is_zero_ether_addr(arvif->u.ibss.bssid))
 | 
							if (is_zero_ether_addr(arvif->bssid))
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
 | 
							ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
 | 
				
			||||||
					 arvif->u.ibss.bssid);
 | 
										 arvif->bssid);
 | 
				
			||||||
		if (ret) {
 | 
							if (ret) {
 | 
				
			||||||
			ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n",
 | 
								ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n",
 | 
				
			||||||
				    arvif->u.ibss.bssid, arvif->vdev_id, ret);
 | 
									    arvif->bssid, arvif->vdev_id, ret);
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		memset(arvif->u.ibss.bssid, 0, ETH_ALEN);
 | 
							memset(arvif->bssid, 0, ETH_ALEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1017,7 +1082,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
 | 
				
			||||||
				   struct wmi_peer_assoc_complete_arg *arg)
 | 
									   struct wmi_peer_assoc_complete_arg *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 | 
						const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 | 
				
			||||||
	int smps;
 | 
					 | 
				
			||||||
	int i, n;
 | 
						int i, n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lockdep_assert_held(&ar->conf_mutex);
 | 
						lockdep_assert_held(&ar->conf_mutex);
 | 
				
			||||||
| 
						 | 
					@ -1063,17 +1127,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
 | 
				
			||||||
		arg->peer_flags |= WMI_PEER_STBC;
 | 
							arg->peer_flags |= WMI_PEER_STBC;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
 | 
					 | 
				
			||||||
	smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (smps == WLAN_HT_CAP_SM_PS_STATIC) {
 | 
					 | 
				
			||||||
		arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
 | 
					 | 
				
			||||||
		arg->peer_flags |= WMI_PEER_STATIC_MIMOPS;
 | 
					 | 
				
			||||||
	} else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) {
 | 
					 | 
				
			||||||
		arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
 | 
					 | 
				
			||||||
		arg->peer_flags |= WMI_PEER_DYN_MIMOPS;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
 | 
						if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
 | 
				
			||||||
		arg->peer_rate_caps |= WMI_RC_TS_FLAG;
 | 
							arg->peer_rate_caps |= WMI_RC_TS_FLAG;
 | 
				
			||||||
	else if (ht_cap->mcs.rx_mask[1])
 | 
						else if (ht_cap->mcs.rx_mask[1])
 | 
				
			||||||
| 
						 | 
					@ -1083,8 +1136,23 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
 | 
				
			||||||
		if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8))
 | 
							if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8))
 | 
				
			||||||
			arg->peer_ht_rates.rates[n++] = i;
 | 
								arg->peer_ht_rates.rates[n++] = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * This is a workaround for HT-enabled STAs which break the spec
 | 
				
			||||||
 | 
						 * and have no HT capabilities RX mask (no HT RX MCS map).
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * As per spec, in section 20.3.5 Modulation and coding scheme (MCS),
 | 
				
			||||||
 | 
						 * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Firmware asserts if such situation occurs.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (n == 0) {
 | 
				
			||||||
 | 
							arg->peer_ht_rates.num_rates = 8;
 | 
				
			||||||
 | 
							for (i = 0; i < arg->peer_ht_rates.num_rates; i++)
 | 
				
			||||||
 | 
								arg->peer_ht_rates.rates[i] = i;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		arg->peer_ht_rates.num_rates = n;
 | 
							arg->peer_ht_rates.num_rates = n;
 | 
				
			||||||
	arg->peer_num_spatial_streams = max((n+7) / 8, 1);
 | 
							arg->peer_num_spatial_streams = sta->rx_nss;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
 | 
						ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
 | 
				
			||||||
		   arg->addr,
 | 
							   arg->addr,
 | 
				
			||||||
| 
						 | 
					@ -1092,27 +1160,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
 | 
				
			||||||
		   arg->peer_num_spatial_streams);
 | 
							   arg->peer_num_spatial_streams);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
 | 
					static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
 | 
				
			||||||
				    struct ath10k_vif *arvif,
 | 
									    struct ath10k_vif *arvif,
 | 
				
			||||||
				       struct ieee80211_sta *sta,
 | 
									    struct ieee80211_sta *sta)
 | 
				
			||||||
				       struct ieee80211_bss_conf *bss_conf,
 | 
					 | 
				
			||||||
				       struct wmi_peer_assoc_complete_arg *arg)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 uapsd = 0;
 | 
						u32 uapsd = 0;
 | 
				
			||||||
	u32 max_sp = 0;
 | 
						u32 max_sp = 0;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lockdep_assert_held(&ar->conf_mutex);
 | 
						lockdep_assert_held(&ar->conf_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sta->wme)
 | 
					 | 
				
			||||||
		arg->peer_flags |= WMI_PEER_QOS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sta->wme && sta->uapsd_queues) {
 | 
						if (sta->wme && sta->uapsd_queues) {
 | 
				
			||||||
		ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
 | 
							ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
 | 
				
			||||||
			   sta->uapsd_queues, sta->max_sp);
 | 
								   sta->uapsd_queues, sta->max_sp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		arg->peer_flags |= WMI_PEER_APSD;
 | 
					 | 
				
			||||||
		arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
 | 
							if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
 | 
				
			||||||
			uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
 | 
								uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
 | 
				
			||||||
				 WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
 | 
									 WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
 | 
				
			||||||
| 
						 | 
					@ -1130,35 +1191,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
 | 
				
			||||||
		if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
 | 
							if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
 | 
				
			||||||
			max_sp = sta->max_sp;
 | 
								max_sp = sta->max_sp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
 | 
							ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
 | 
				
			||||||
						 sta->addr,
 | 
											 sta->addr,
 | 
				
			||||||
						 WMI_AP_PS_PEER_PARAM_UAPSD,
 | 
											 WMI_AP_PS_PEER_PARAM_UAPSD,
 | 
				
			||||||
						 uapsd);
 | 
											 uapsd);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								ath10k_warn("failed to set ap ps peer param uapsd: %d\n",
 | 
				
			||||||
 | 
									    ret);
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
 | 
							ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
 | 
				
			||||||
						 sta->addr,
 | 
											 sta->addr,
 | 
				
			||||||
						 WMI_AP_PS_PEER_PARAM_MAX_SP,
 | 
											 WMI_AP_PS_PEER_PARAM_MAX_SP,
 | 
				
			||||||
						 max_sp);
 | 
											 max_sp);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								ath10k_warn("failed to set ap ps peer param max sp: %d\n",
 | 
				
			||||||
 | 
									    ret);
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* TODO setup this based on STA listen interval and
 | 
							/* TODO setup this based on STA listen interval and
 | 
				
			||||||
		   beacon interval. Currently we don't know
 | 
							   beacon interval. Currently we don't know
 | 
				
			||||||
		   sta->listen_interval - mac80211 patch required.
 | 
							   sta->listen_interval - mac80211 patch required.
 | 
				
			||||||
		   Currently use 10 seconds */
 | 
							   Currently use 10 seconds */
 | 
				
			||||||
		ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id,
 | 
							ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
 | 
				
			||||||
					   sta->addr,
 | 
										WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
 | 
				
			||||||
					   WMI_AP_PS_PEER_PARAM_AGEOUT_TIME,
 | 
							if (ret) {
 | 
				
			||||||
					   10);
 | 
								ath10k_warn("failed to set ap ps peer param ageout time: %d\n",
 | 
				
			||||||
 | 
									    ret);
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar,
 | 
						return 0;
 | 
				
			||||||
					struct ath10k_vif *arvif,
 | 
					 | 
				
			||||||
					struct ieee80211_sta *sta,
 | 
					 | 
				
			||||||
					struct ieee80211_bss_conf *bss_conf,
 | 
					 | 
				
			||||||
					struct wmi_peer_assoc_complete_arg *arg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (bss_conf->qos)
 | 
					 | 
				
			||||||
		arg->peer_flags |= WMI_PEER_QOS;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
 | 
					static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
 | 
				
			||||||
| 
						 | 
					@ -1211,10 +1277,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (arvif->vdev_type) {
 | 
						switch (arvif->vdev_type) {
 | 
				
			||||||
	case WMI_VDEV_TYPE_AP:
 | 
						case WMI_VDEV_TYPE_AP:
 | 
				
			||||||
		ath10k_peer_assoc_h_qos_ap(ar, arvif, sta, bss_conf, arg);
 | 
							if (sta->wme)
 | 
				
			||||||
 | 
								arg->peer_flags |= WMI_PEER_QOS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (sta->wme && sta->uapsd_queues) {
 | 
				
			||||||
 | 
								arg->peer_flags |= WMI_PEER_APSD;
 | 
				
			||||||
 | 
								arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case WMI_VDEV_TYPE_STA:
 | 
						case WMI_VDEV_TYPE_STA:
 | 
				
			||||||
		ath10k_peer_assoc_h_qos_sta(ar, arvif, sta, bss_conf, arg);
 | 
							if (bss_conf->qos)
 | 
				
			||||||
 | 
								arg->peer_flags |= WMI_PEER_QOS;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -1293,6 +1366,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const u32 ath10k_smps_map[] = {
 | 
				
			||||||
 | 
						[WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC,
 | 
				
			||||||
 | 
						[WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC,
 | 
				
			||||||
 | 
						[WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE,
 | 
				
			||||||
 | 
						[WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif,
 | 
				
			||||||
 | 
									  const u8 *addr,
 | 
				
			||||||
 | 
									  const struct ieee80211_sta_ht_cap *ht_cap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int smps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ht_cap->ht_supported)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
 | 
				
			||||||
 | 
						smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (smps >= ARRAY_SIZE(ath10k_smps_map))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr,
 | 
				
			||||||
 | 
										 WMI_PEER_SMPS_STATE,
 | 
				
			||||||
 | 
										 ath10k_smps_map[smps]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* can be called only in mac80211 callbacks due to `key_count` usage */
 | 
					/* can be called only in mac80211 callbacks due to `key_count` usage */
 | 
				
			||||||
static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 | 
					static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 | 
				
			||||||
			     struct ieee80211_vif *vif,
 | 
								     struct ieee80211_vif *vif,
 | 
				
			||||||
| 
						 | 
					@ -1300,6 +1400,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ath10k *ar = hw->priv;
 | 
						struct ath10k *ar = hw->priv;
 | 
				
			||||||
	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 | 
						struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 | 
				
			||||||
 | 
						struct ieee80211_sta_ht_cap ht_cap;
 | 
				
			||||||
	struct wmi_peer_assoc_complete_arg peer_arg;
 | 
						struct wmi_peer_assoc_complete_arg peer_arg;
 | 
				
			||||||
	struct ieee80211_sta *ap_sta;
 | 
						struct ieee80211_sta *ap_sta;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
| 
						 | 
					@ -1316,6 +1417,10 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* ap_sta must be accessed only within rcu section which must be left
 | 
				
			||||||
 | 
						 * before calling ath10k_setup_peer_smps() which might sleep. */
 | 
				
			||||||
 | 
						ht_cap = ap_sta->ht_cap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
 | 
						ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
 | 
				
			||||||
					bss_conf, &peer_arg);
 | 
										bss_conf, &peer_arg);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
| 
						 | 
					@ -1334,15 +1439,27 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							ath10k_warn("failed to setup peer SMPS: %d\n", ret);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ath10k_dbg(ATH10K_DBG_MAC,
 | 
						ath10k_dbg(ATH10K_DBG_MAC,
 | 
				
			||||||
		   "mac vdev %d up (associated) bssid %pM aid %d\n",
 | 
							   "mac vdev %d up (associated) bssid %pM aid %d\n",
 | 
				
			||||||
		   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
 | 
							   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid,
 | 
						arvif->aid = bss_conf->aid;
 | 
				
			||||||
				 bss_conf->bssid);
 | 
						memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
 | 
				
			||||||
	if (ret)
 | 
					
 | 
				
			||||||
 | 
						ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
		ath10k_warn("VDEV: %d up failed: ret %d\n",
 | 
							ath10k_warn("VDEV: %d up failed: ret %d\n",
 | 
				
			||||||
			    arvif->vdev_id, ret);
 | 
								    arvif->vdev_id, ret);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arvif->is_up = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1382,6 +1499,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
 | 
				
			||||||
	ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
 | 
						ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	arvif->def_wep_key_idx = 0;
 | 
						arvif->def_wep_key_idx = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arvif->is_started = false;
 | 
				
			||||||
 | 
						arvif->is_up = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
 | 
					static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
 | 
				
			||||||
| 
						 | 
					@ -1406,12 +1526,25 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							ath10k_warn("failed to setup peer SMPS: %d\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
 | 
						ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		ath10k_warn("could not install peer wep keys (%d)\n", ret);
 | 
							ath10k_warn("could not install peer wep keys (%d)\n", ret);
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							ath10k_warn("could not set qos params for STA %pM, %d\n",
 | 
				
			||||||
 | 
								    sta->addr, ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1547,9 +1680,9 @@ static void ath10k_regd_update(struct ath10k *ar)
 | 
				
			||||||
	/* Target allows setting up per-band regdomain but ath_common provides
 | 
						/* Target allows setting up per-band regdomain but ath_common provides
 | 
				
			||||||
	 * a combined one only */
 | 
						 * a combined one only */
 | 
				
			||||||
	ret = ath10k_wmi_pdev_set_regdomain(ar,
 | 
						ret = ath10k_wmi_pdev_set_regdomain(ar,
 | 
				
			||||||
					    regpair->regDmnEnum,
 | 
										    regpair->reg_domain,
 | 
				
			||||||
					    regpair->regDmnEnum, /* 2ghz */
 | 
										    regpair->reg_domain, /* 2ghz */
 | 
				
			||||||
					    regpair->regDmnEnum, /* 5ghz */
 | 
										    regpair->reg_domain, /* 5ghz */
 | 
				
			||||||
					    regpair->reg_2ghz_ctl,
 | 
										    regpair->reg_2ghz_ctl,
 | 
				
			||||||
					    regpair->reg_5ghz_ctl);
 | 
										    regpair->reg_5ghz_ctl);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
| 
						 | 
					@ -2100,11 +2233,29 @@ static int ath10k_start(struct ieee80211_hw *hw)
 | 
				
			||||||
		ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
 | 
							ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
 | 
				
			||||||
			    ret);
 | 
								    ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * By default FW set ARP frames ac to voice (6). In that case ARP
 | 
				
			||||||
 | 
						 * exchange is not working properly for UAPSD enabled AP. ARP requests
 | 
				
			||||||
 | 
						 * which arrives with access category 0 are processed by network stack
 | 
				
			||||||
 | 
						 * and send back with access category 0, but FW changes access category
 | 
				
			||||||
 | 
						 * to 6. Set ARP frames access category to best effort (0) solves
 | 
				
			||||||
 | 
						 * this problem.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = ath10k_wmi_pdev_set_param(ar,
 | 
				
			||||||
 | 
										ar->wmi.pdev_param->arp_ac_override, 0);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							ath10k_warn("could not set arp ac override parameter: %d\n",
 | 
				
			||||||
 | 
								    ret);
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ath10k_regd_update(ar);
 | 
						ath10k_regd_update(ar);
 | 
				
			||||||
 | 
						ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit:
 | 
					exit:
 | 
				
			||||||
	mutex_unlock(&ar->conf_mutex);
 | 
						mutex_unlock(&ar->conf_mutex);
 | 
				
			||||||
	return 0;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ath10k_stop(struct ieee80211_hw *hw)
 | 
					static void ath10k_stop(struct ieee80211_hw *hw)
 | 
				
			||||||
| 
						 | 
					@ -2145,6 +2296,98 @@ static int ath10k_config_ps(struct ath10k *ar)
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *chandef_get_width(enum nl80211_chan_width width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (width) {
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_20_NOHT:
 | 
				
			||||||
 | 
							return "20 (noht)";
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_20:
 | 
				
			||||||
 | 
							return "20";
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_40:
 | 
				
			||||||
 | 
							return "40";
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_80:
 | 
				
			||||||
 | 
							return "80";
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_80P80:
 | 
				
			||||||
 | 
							return "80+80";
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_160:
 | 
				
			||||||
 | 
							return "160";
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_5:
 | 
				
			||||||
 | 
							return "5";
 | 
				
			||||||
 | 
						case NL80211_CHAN_WIDTH_10:
 | 
				
			||||||
 | 
							return "10";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return "?";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ath10k_config_chan(struct ath10k *ar)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ath10k_vif *arvif;
 | 
				
			||||||
 | 
						bool monitor_was_enabled;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lockdep_assert_held(&ar->conf_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ath10k_dbg(ATH10K_DBG_MAC,
 | 
				
			||||||
 | 
							   "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
 | 
				
			||||||
 | 
							   ar->chandef.chan->center_freq,
 | 
				
			||||||
 | 
							   ar->chandef.center_freq1,
 | 
				
			||||||
 | 
							   ar->chandef.center_freq2,
 | 
				
			||||||
 | 
							   chandef_get_width(ar->chandef.width));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* First stop monitor interface. Some FW versions crash if there's a
 | 
				
			||||||
 | 
						 * lone monitor interface. */
 | 
				
			||||||
 | 
						monitor_was_enabled = ar->monitor_enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ar->monitor_enabled)
 | 
				
			||||||
 | 
							ath10k_monitor_stop(ar);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry(arvif, &ar->arvifs, list) {
 | 
				
			||||||
 | 
							if (!arvif->is_started)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = ath10k_vdev_stop(arvif);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								ath10k_warn("could not stop vdev %d (%d)\n",
 | 
				
			||||||
 | 
									    arvif->vdev_id, ret);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* all vdevs are now stopped - now attempt to restart them */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry(arvif, &ar->arvifs, list) {
 | 
				
			||||||
 | 
							if (!arvif->is_started)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = ath10k_vdev_start(arvif);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								ath10k_warn("could not start vdev %d (%d)\n",
 | 
				
			||||||
 | 
									    arvif->vdev_id, ret);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!arvif->is_up)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
 | 
				
			||||||
 | 
										 arvif->bssid);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								ath10k_warn("could not bring vdev up %d (%d)\n",
 | 
				
			||||||
 | 
									    arvif->vdev_id, ret);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (monitor_was_enabled)
 | 
				
			||||||
 | 
							ath10k_monitor_start(ar, ar->monitor_vdev_id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
 | 
					static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ath10k *ar = hw->priv;
 | 
						struct ath10k *ar = hw->priv;
 | 
				
			||||||
| 
						 | 
					@ -2165,6 +2408,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
 | 
				
			||||||
		spin_unlock_bh(&ar->data_lock);
 | 
							spin_unlock_bh(&ar->data_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ath10k_config_radar_detection(ar);
 | 
							ath10k_config_radar_detection(ar);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) {
 | 
				
			||||||
 | 
								ar->chandef = conf->chandef;
 | 
				
			||||||
 | 
								ath10k_config_chan(ar);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (changed & IEEE80211_CONF_CHANGE_POWER) {
 | 
						if (changed & IEEE80211_CONF_CHANGE_POWER) {
 | 
				
			||||||
| 
						 | 
					@ -2214,7 +2462,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
 | 
				
			||||||
	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 | 
						struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 | 
				
			||||||
	enum wmi_sta_powersave_param param;
 | 
						enum wmi_sta_powersave_param param;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
	u32 value, param_id;
 | 
						u32 value;
 | 
				
			||||||
	int bit;
 | 
						int bit;
 | 
				
			||||||
	u32 vdev_param;
 | 
						u32 vdev_param;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2307,12 +2555,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
 | 
				
			||||||
			goto err_vdev_delete;
 | 
								goto err_vdev_delete;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		param_id = ar->wmi.pdev_param->sta_kickout_th;
 | 
							ret = ath10k_mac_set_kickout(arvif);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
		/* Disable STA KICKOUT functionality in FW */
 | 
								ath10k_warn("Failed to set kickout parameters: %d\n",
 | 
				
			||||||
		ret = ath10k_wmi_pdev_set_param(ar, param_id, 0);
 | 
									    ret);
 | 
				
			||||||
		if (ret)
 | 
								goto err_peer_delete;
 | 
				
			||||||
			ath10k_warn("Failed to disable STA KICKOUT\n");
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
 | 
						if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
 | 
				
			||||||
| 
						 | 
					@ -2559,15 +2807,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
 | 
				
			||||||
				 * this is never erased as we it for crypto key
 | 
									 * this is never erased as we it for crypto key
 | 
				
			||||||
				 * clearing; this is FW requirement
 | 
									 * clearing; this is FW requirement
 | 
				
			||||||
				 */
 | 
									 */
 | 
				
			||||||
				memcpy(arvif->u.sta.bssid, info->bssid,
 | 
									memcpy(arvif->bssid, info->bssid, ETH_ALEN);
 | 
				
			||||||
				       ETH_ALEN);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				ath10k_dbg(ATH10K_DBG_MAC,
 | 
									ath10k_dbg(ATH10K_DBG_MAC,
 | 
				
			||||||
					   "mac vdev %d start %pM\n",
 | 
										   "mac vdev %d start %pM\n",
 | 
				
			||||||
					   arvif->vdev_id, info->bssid);
 | 
										   arvif->vdev_id, info->bssid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/* FIXME: check return value */
 | 
					 | 
				
			||||||
				ret = ath10k_vdev_start(arvif);
 | 
									ret = ath10k_vdev_start(arvif);
 | 
				
			||||||
 | 
									if (ret) {
 | 
				
			||||||
 | 
										ath10k_warn("failed to start vdev: %d\n",
 | 
				
			||||||
 | 
											    ret);
 | 
				
			||||||
 | 
										goto exit;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									arvif->is_started = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
| 
						 | 
					@ -2576,7 +2829,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
 | 
				
			||||||
			 * IBSS in order to remove BSSID peer.
 | 
								 * IBSS in order to remove BSSID peer.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			if (vif->type == NL80211_IFTYPE_ADHOC)
 | 
								if (vif->type == NL80211_IFTYPE_ADHOC)
 | 
				
			||||||
				memcpy(arvif->u.ibss.bssid, info->bssid,
 | 
									memcpy(arvif->bssid, info->bssid,
 | 
				
			||||||
				       ETH_ALEN);
 | 
									       ETH_ALEN);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2645,6 +2898,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
 | 
				
			||||||
			ath10k_bss_assoc(hw, vif, info);
 | 
								ath10k_bss_assoc(hw, vif, info);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
	mutex_unlock(&ar->conf_mutex);
 | 
						mutex_unlock(&ar->conf_mutex);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2850,6 +3104,69 @@ exit:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ath10k_sta_rc_update_wk(struct work_struct *wk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ath10k *ar;
 | 
				
			||||||
 | 
						struct ath10k_vif *arvif;
 | 
				
			||||||
 | 
						struct ath10k_sta *arsta;
 | 
				
			||||||
 | 
						struct ieee80211_sta *sta;
 | 
				
			||||||
 | 
						u32 changed, bw, nss, smps;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arsta = container_of(wk, struct ath10k_sta, update_wk);
 | 
				
			||||||
 | 
						sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
 | 
				
			||||||
 | 
						arvif = arsta->arvif;
 | 
				
			||||||
 | 
						ar = arvif->ar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_bh(&ar->data_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						changed = arsta->changed;
 | 
				
			||||||
 | 
						arsta->changed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bw = arsta->bw;
 | 
				
			||||||
 | 
						nss = arsta->nss;
 | 
				
			||||||
 | 
						smps = arsta->smps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock_bh(&ar->data_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&ar->conf_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (changed & IEEE80211_RC_BW_CHANGED) {
 | 
				
			||||||
 | 
							ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
 | 
				
			||||||
 | 
								   sta->addr, bw);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
 | 
				
			||||||
 | 
											WMI_PEER_CHAN_WIDTH, bw);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								ath10k_warn("failed to update STA %pM peer bw %d: %d\n",
 | 
				
			||||||
 | 
									    sta->addr, bw, err);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (changed & IEEE80211_RC_NSS_CHANGED) {
 | 
				
			||||||
 | 
							ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
 | 
				
			||||||
 | 
								   sta->addr, nss);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
 | 
				
			||||||
 | 
											WMI_PEER_NSS, nss);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								ath10k_warn("failed to update STA %pM nss %d: %d\n",
 | 
				
			||||||
 | 
									    sta->addr, nss, err);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (changed & IEEE80211_RC_SMPS_CHANGED) {
 | 
				
			||||||
 | 
							ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
 | 
				
			||||||
 | 
								   sta->addr, smps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
 | 
				
			||||||
 | 
											WMI_PEER_SMPS_STATE, smps);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								ath10k_warn("failed to update STA %pM smps %d: %d\n",
 | 
				
			||||||
 | 
									    sta->addr, smps, err);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&ar->conf_mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ath10k_sta_state(struct ieee80211_hw *hw,
 | 
					static int ath10k_sta_state(struct ieee80211_hw *hw,
 | 
				
			||||||
			    struct ieee80211_vif *vif,
 | 
								    struct ieee80211_vif *vif,
 | 
				
			||||||
			    struct ieee80211_sta *sta,
 | 
								    struct ieee80211_sta *sta,
 | 
				
			||||||
| 
						 | 
					@ -2858,9 +3175,15 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ath10k *ar = hw->priv;
 | 
						struct ath10k *ar = hw->priv;
 | 
				
			||||||
	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 | 
						struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 | 
				
			||||||
 | 
						struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
 | 
				
			||||||
	int max_num_peers;
 | 
						int max_num_peers;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* cancel must be done outside the mutex to avoid deadlock */
 | 
				
			||||||
 | 
						if ((old_state == IEEE80211_STA_NONE &&
 | 
				
			||||||
 | 
						     new_state == IEEE80211_STA_NOTEXIST))
 | 
				
			||||||
 | 
							cancel_work_sync(&arsta->update_wk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&ar->conf_mutex);
 | 
						mutex_lock(&ar->conf_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (old_state == IEEE80211_STA_NOTEXIST &&
 | 
						if (old_state == IEEE80211_STA_NOTEXIST &&
 | 
				
			||||||
| 
						 | 
					@ -2885,6 +3208,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 | 
				
			||||||
			   "mac vdev %d peer create %pM (new sta) num_peers %d\n",
 | 
								   "mac vdev %d peer create %pM (new sta) num_peers %d\n",
 | 
				
			||||||
			   arvif->vdev_id, sta->addr, ar->num_peers);
 | 
								   arvif->vdev_id, sta->addr, ar->num_peers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memset(arsta, 0, sizeof(*arsta));
 | 
				
			||||||
 | 
							arsta->arvif = arvif;
 | 
				
			||||||
 | 
							INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
 | 
							ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 | 
								ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 | 
				
			||||||
| 
						 | 
					@ -3234,23 +3561,14 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
 | 
				
			||||||
	struct ath10k *ar = hw->priv;
 | 
						struct ath10k *ar = hw->priv;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ar->is_target_paused = false;
 | 
						mutex_lock(&ar->conf_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ath10k_wmi_pdev_suspend_target(ar);
 | 
						ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		ath10k_warn("could not suspend target (%d)\n", ret);
 | 
							if (ret == -ETIMEDOUT)
 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = wait_event_interruptible_timeout(ar->event_queue,
 | 
					 | 
				
			||||||
					       ar->is_target_paused == true,
 | 
					 | 
				
			||||||
					       1 * HZ);
 | 
					 | 
				
			||||||
	if (ret < 0) {
 | 
					 | 
				
			||||||
		ath10k_warn("suspend interrupted (%d)\n", ret);
 | 
					 | 
				
			||||||
		goto resume;
 | 
					 | 
				
			||||||
	} else if (ret == 0) {
 | 
					 | 
				
			||||||
		ath10k_warn("suspend timed out - target pause event never came\n");
 | 
					 | 
				
			||||||
			goto resume;
 | 
								goto resume;
 | 
				
			||||||
 | 
							ret = 1;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ath10k_hif_suspend(ar);
 | 
						ret = ath10k_hif_suspend(ar);
 | 
				
			||||||
| 
						 | 
					@ -3259,12 +3577,17 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
 | 
				
			||||||
		goto resume;
 | 
							goto resume;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						ret = 0;
 | 
				
			||||||
 | 
						goto exit;
 | 
				
			||||||
resume:
 | 
					resume:
 | 
				
			||||||
	ret = ath10k_wmi_pdev_resume_target(ar);
 | 
						ret = ath10k_wmi_pdev_resume_target(ar);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		ath10k_warn("could not resume target (%d)\n", ret);
 | 
							ath10k_warn("could not resume target (%d)\n", ret);
 | 
				
			||||||
	return 1;
 | 
					
 | 
				
			||||||
 | 
						ret = 1;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						mutex_unlock(&ar->conf_mutex);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ath10k_resume(struct ieee80211_hw *hw)
 | 
					static int ath10k_resume(struct ieee80211_hw *hw)
 | 
				
			||||||
| 
						 | 
					@ -3272,19 +3595,26 @@ static int ath10k_resume(struct ieee80211_hw *hw)
 | 
				
			||||||
	struct ath10k *ar = hw->priv;
 | 
						struct ath10k *ar = hw->priv;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&ar->conf_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ath10k_hif_resume(ar);
 | 
						ret = ath10k_hif_resume(ar);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		ath10k_warn("could not resume hif (%d)\n", ret);
 | 
							ath10k_warn("could not resume hif (%d)\n", ret);
 | 
				
			||||||
		return 1;
 | 
							ret = 1;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = ath10k_wmi_pdev_resume_target(ar);
 | 
						ret = ath10k_wmi_pdev_resume_target(ar);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		ath10k_warn("could not resume target (%d)\n", ret);
 | 
							ath10k_warn("could not resume target (%d)\n", ret);
 | 
				
			||||||
		return 1;
 | 
							ret = 1;
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						ret = 0;
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						mutex_unlock(&ar->conf_mutex);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3640,6 +3970,96 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
 | 
				
			||||||
	return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss);
 | 
						return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw,
 | 
				
			||||||
 | 
										 struct ieee80211_vif *vif,
 | 
				
			||||||
 | 
										 struct cfg80211_chan_def *chandef)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* there's no need to do anything here. vif->csa_active is enough */
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
 | 
				
			||||||
 | 
									 struct ieee80211_vif *vif,
 | 
				
			||||||
 | 
									 struct ieee80211_sta *sta,
 | 
				
			||||||
 | 
									 u32 changed)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ath10k *ar = hw->priv;
 | 
				
			||||||
 | 
						struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
 | 
				
			||||||
 | 
						u32 bw, smps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_bh(&ar->data_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ath10k_dbg(ATH10K_DBG_MAC,
 | 
				
			||||||
 | 
							   "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
 | 
				
			||||||
 | 
							   sta->addr, changed, sta->bandwidth, sta->rx_nss,
 | 
				
			||||||
 | 
							   sta->smps_mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (changed & IEEE80211_RC_BW_CHANGED) {
 | 
				
			||||||
 | 
							bw = WMI_PEER_CHWIDTH_20MHZ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (sta->bandwidth) {
 | 
				
			||||||
 | 
							case IEEE80211_STA_RX_BW_20:
 | 
				
			||||||
 | 
								bw = WMI_PEER_CHWIDTH_20MHZ;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case IEEE80211_STA_RX_BW_40:
 | 
				
			||||||
 | 
								bw = WMI_PEER_CHWIDTH_40MHZ;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case IEEE80211_STA_RX_BW_80:
 | 
				
			||||||
 | 
								bw = WMI_PEER_CHWIDTH_80MHZ;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case IEEE80211_STA_RX_BW_160:
 | 
				
			||||||
 | 
								ath10k_warn("mac sta rc update for %pM: invalid bw %d\n",
 | 
				
			||||||
 | 
									    sta->addr, sta->bandwidth);
 | 
				
			||||||
 | 
								bw = WMI_PEER_CHWIDTH_20MHZ;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							arsta->bw = bw;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (changed & IEEE80211_RC_NSS_CHANGED)
 | 
				
			||||||
 | 
							arsta->nss = sta->rx_nss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (changed & IEEE80211_RC_SMPS_CHANGED) {
 | 
				
			||||||
 | 
							smps = WMI_PEER_SMPS_PS_NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (sta->smps_mode) {
 | 
				
			||||||
 | 
							case IEEE80211_SMPS_AUTOMATIC:
 | 
				
			||||||
 | 
							case IEEE80211_SMPS_OFF:
 | 
				
			||||||
 | 
								smps = WMI_PEER_SMPS_PS_NONE;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case IEEE80211_SMPS_STATIC:
 | 
				
			||||||
 | 
								smps = WMI_PEER_SMPS_STATIC;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case IEEE80211_SMPS_DYNAMIC:
 | 
				
			||||||
 | 
								smps = WMI_PEER_SMPS_DYNAMIC;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case IEEE80211_SMPS_NUM_MODES:
 | 
				
			||||||
 | 
								ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n",
 | 
				
			||||||
 | 
									    sta->addr, sta->smps_mode);
 | 
				
			||||||
 | 
								smps = WMI_PEER_SMPS_PS_NONE;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							arsta->smps = smps;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
 | 
				
			||||||
 | 
							/* FIXME: Not implemented. Probably the only way to do it would
 | 
				
			||||||
 | 
							 * be to re-assoc the peer. */
 | 
				
			||||||
 | 
							changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED;
 | 
				
			||||||
 | 
							ath10k_dbg(ATH10K_DBG_MAC,
 | 
				
			||||||
 | 
								   "mac sta rc update for %pM: changing supported rates not implemented\n",
 | 
				
			||||||
 | 
								   sta->addr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arsta->changed |= changed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock_bh(&ar->data_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ieee80211_queue_work(hw, &arsta->update_wk);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct ieee80211_ops ath10k_ops = {
 | 
					static const struct ieee80211_ops ath10k_ops = {
 | 
				
			||||||
	.tx				= ath10k_tx,
 | 
						.tx				= ath10k_tx,
 | 
				
			||||||
	.start				= ath10k_start,
 | 
						.start				= ath10k_start,
 | 
				
			||||||
| 
						 | 
					@ -3663,6 +4083,8 @@ static const struct ieee80211_ops ath10k_ops = {
 | 
				
			||||||
	.restart_complete		= ath10k_restart_complete,
 | 
						.restart_complete		= ath10k_restart_complete,
 | 
				
			||||||
	.get_survey			= ath10k_get_survey,
 | 
						.get_survey			= ath10k_get_survey,
 | 
				
			||||||
	.set_bitrate_mask		= ath10k_set_bitrate_mask,
 | 
						.set_bitrate_mask		= ath10k_set_bitrate_mask,
 | 
				
			||||||
 | 
						.channel_switch_beacon		= ath10k_channel_switch_beacon,
 | 
				
			||||||
 | 
						.sta_rc_update			= ath10k_sta_rc_update,
 | 
				
			||||||
#ifdef CONFIG_PM
 | 
					#ifdef CONFIG_PM
 | 
				
			||||||
	.suspend			= ath10k_suspend,
 | 
						.suspend			= ath10k_suspend,
 | 
				
			||||||
	.resume				= ath10k_resume,
 | 
						.resume				= ath10k_resume,
 | 
				
			||||||
| 
						 | 
					@ -4038,10 +4460,12 @@ int ath10k_mac_register(struct ath10k *ar)
 | 
				
			||||||
	ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
 | 
						ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ar->hw->vif_data_size = sizeof(struct ath10k_vif);
 | 
						ar->hw->vif_data_size = sizeof(struct ath10k_vif);
 | 
				
			||||||
 | 
						ar->hw->sta_data_size = sizeof(struct ath10k_sta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
 | 
						ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 | 
						ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 | 
				
			||||||
 | 
						ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
 | 
				
			||||||
	ar->hw->wiphy->max_remain_on_channel_duration = 5000;
 | 
						ar->hw->wiphy->max_remain_on_channel_duration = 5000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
 | 
						ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,8 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
 | 
				
			||||||
					     int num);
 | 
										     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)
 | 
				
			||||||
	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)
 | 
				
			||||||
	 * 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)
 | 
				
			||||||
	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)
 | 
				
			||||||
	 * 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 @@ err_deinit_irq:
 | 
				
			||||||
	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 @@ err:
 | 
				
			||||||
	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)
 | 
				
			||||||
	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)
 | 
				
			||||||
	/* 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)
 | 
				
			||||||
	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 @@ out:
 | 
				
			||||||
	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)
 | 
				
			||||||
	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)
 | 
				
			||||||
		   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 = {
 | 
				
			||||||
	.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 = {
 | 
				
			||||||
	.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 = {
 | 
				
			||||||
	.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 @@ err_pull:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
	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,
 | 
				
			||||||
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,
 | 
				
			||||||
	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)
 | 
				
			||||||
			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)
 | 
				
			||||||
		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) {
 | 
				
			||||||
 | 
								if (!arvif->beacon_sent)
 | 
				
			||||||
				ath10k_warn("SWBA overrun on vdev %d\n",
 | 
									ath10k_warn("SWBA overrun on vdev %d\n",
 | 
				
			||||||
					    arvif->vdev_id);
 | 
										    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)
 | 
				
			||||||
	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,
 | 
				
			||||||
				   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)
 | 
				
			||||||
		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,
 | 
				
			||||||
	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 {
 | 
				
			||||||
	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 {
 | 
				
			||||||
	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 {
 | 
				
			||||||
	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 {
 | 
				
			||||||
	__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);
 | 
				
			||||||
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,
 | 
				
			||||||
			       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)
 | 
				
			||||||
	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 @@
 | 
				
			||||||
/* 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)
 | 
				
			||||||
	 *		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)
 | 
				
			||||||
		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 ®DomainPairs[i];
 | 
								return ®DomainPairs[i];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -954,7 +954,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
 | 
				
			||||||
		country = ath6kl_regd_find_country_by_rd((u16) reg_code);
 | 
							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 \
 | 
				
			||||||
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,
 | 
				
			||||||
	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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ath_dbg(common, ANI, "Initialize ANI\n");
 | 
						ath_dbg(common, ANI, "Initialize ANI\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (AR_SREV_9300_20_OR_LATER(ah)) {
 | 
				
			||||||
		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
 | 
							ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
 | 
				
			||||||
		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
 | 
							ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
 | 
				
			||||||
		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
 | 
							ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
 | 
				
			||||||
		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
 | 
							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 @@
 | 
				
			||||||
/* 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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 {
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	 * 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,
 | 
				
			||||||
	 * 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 = conf->listen_interval *
 | 
					 | 
				
			||||||
			ATH_DEFAULT_BMISS_LIMIT / 2;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
	bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
 | 
						bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
 | 
				
			||||||
	if (bs.bs_bmissthreshold > 15)
 | 
						if (bs.bs_bmissthreshold > 15)
 | 
				
			||||||
		bs.bs_bmissthreshold = 15;
 | 
							bs.bs_bmissthreshold = 15;
 | 
				
			||||||
	else if (bs.bs_bmissthreshold <= 0)
 | 
						else if (bs.bs_bmissthreshold <= 0)
 | 
				
			||||||
		bs.bs_bmissthreshold = 1;
 | 
							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,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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 =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										244
									
								
								drivers/net/wireless/ath/ath9k/common-init.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								drivers/net/wireless/ath/ath9k/common-init.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,244 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2008-2011 Atheros Communications Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
				
			||||||
 | 
					 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
				
			||||||
 | 
					 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* We use the hw_value as an index into our private channel structure */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CHAN2G(_freq, _idx)  { \
 | 
				
			||||||
 | 
						.band = IEEE80211_BAND_2GHZ, \
 | 
				
			||||||
 | 
						.center_freq = (_freq), \
 | 
				
			||||||
 | 
						.hw_value = (_idx), \
 | 
				
			||||||
 | 
						.max_power = 20, \
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CHAN5G(_freq, _idx) { \
 | 
				
			||||||
 | 
						.band = IEEE80211_BAND_5GHZ, \
 | 
				
			||||||
 | 
						.center_freq = (_freq), \
 | 
				
			||||||
 | 
						.hw_value = (_idx), \
 | 
				
			||||||
 | 
						.max_power = 20, \
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Some 2 GHz radios are actually tunable on 2312-2732
 | 
				
			||||||
 | 
					 * on 5 MHz steps, we support the channels which we know
 | 
				
			||||||
 | 
					 * we have calibration data for all cards though to make
 | 
				
			||||||
 | 
					 * this static */
 | 
				
			||||||
 | 
					static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
 | 
				
			||||||
 | 
						CHAN2G(2412, 0), /* Channel 1 */
 | 
				
			||||||
 | 
						CHAN2G(2417, 1), /* Channel 2 */
 | 
				
			||||||
 | 
						CHAN2G(2422, 2), /* Channel 3 */
 | 
				
			||||||
 | 
						CHAN2G(2427, 3), /* Channel 4 */
 | 
				
			||||||
 | 
						CHAN2G(2432, 4), /* Channel 5 */
 | 
				
			||||||
 | 
						CHAN2G(2437, 5), /* Channel 6 */
 | 
				
			||||||
 | 
						CHAN2G(2442, 6), /* Channel 7 */
 | 
				
			||||||
 | 
						CHAN2G(2447, 7), /* Channel 8 */
 | 
				
			||||||
 | 
						CHAN2G(2452, 8), /* Channel 9 */
 | 
				
			||||||
 | 
						CHAN2G(2457, 9), /* Channel 10 */
 | 
				
			||||||
 | 
						CHAN2G(2462, 10), /* Channel 11 */
 | 
				
			||||||
 | 
						CHAN2G(2467, 11), /* Channel 12 */
 | 
				
			||||||
 | 
						CHAN2G(2472, 12), /* Channel 13 */
 | 
				
			||||||
 | 
						CHAN2G(2484, 13), /* Channel 14 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Some 5 GHz radios are actually tunable on XXXX-YYYY
 | 
				
			||||||
 | 
					 * on 5 MHz steps, we support the channels which we know
 | 
				
			||||||
 | 
					 * we have calibration data for all cards though to make
 | 
				
			||||||
 | 
					 * this static */
 | 
				
			||||||
 | 
					static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
 | 
				
			||||||
 | 
						/* _We_ call this UNII 1 */
 | 
				
			||||||
 | 
						CHAN5G(5180, 14), /* Channel 36 */
 | 
				
			||||||
 | 
						CHAN5G(5200, 15), /* Channel 40 */
 | 
				
			||||||
 | 
						CHAN5G(5220, 16), /* Channel 44 */
 | 
				
			||||||
 | 
						CHAN5G(5240, 17), /* Channel 48 */
 | 
				
			||||||
 | 
						/* _We_ call this UNII 2 */
 | 
				
			||||||
 | 
						CHAN5G(5260, 18), /* Channel 52 */
 | 
				
			||||||
 | 
						CHAN5G(5280, 19), /* Channel 56 */
 | 
				
			||||||
 | 
						CHAN5G(5300, 20), /* Channel 60 */
 | 
				
			||||||
 | 
						CHAN5G(5320, 21), /* Channel 64 */
 | 
				
			||||||
 | 
						/* _We_ call this "Middle band" */
 | 
				
			||||||
 | 
						CHAN5G(5500, 22), /* Channel 100 */
 | 
				
			||||||
 | 
						CHAN5G(5520, 23), /* Channel 104 */
 | 
				
			||||||
 | 
						CHAN5G(5540, 24), /* Channel 108 */
 | 
				
			||||||
 | 
						CHAN5G(5560, 25), /* Channel 112 */
 | 
				
			||||||
 | 
						CHAN5G(5580, 26), /* Channel 116 */
 | 
				
			||||||
 | 
						CHAN5G(5600, 27), /* Channel 120 */
 | 
				
			||||||
 | 
						CHAN5G(5620, 28), /* Channel 124 */
 | 
				
			||||||
 | 
						CHAN5G(5640, 29), /* Channel 128 */
 | 
				
			||||||
 | 
						CHAN5G(5660, 30), /* Channel 132 */
 | 
				
			||||||
 | 
						CHAN5G(5680, 31), /* Channel 136 */
 | 
				
			||||||
 | 
						CHAN5G(5700, 32), /* Channel 140 */
 | 
				
			||||||
 | 
						/* _We_ call this UNII 3 */
 | 
				
			||||||
 | 
						CHAN5G(5745, 33), /* Channel 149 */
 | 
				
			||||||
 | 
						CHAN5G(5765, 34), /* Channel 153 */
 | 
				
			||||||
 | 
						CHAN5G(5785, 35), /* Channel 157 */
 | 
				
			||||||
 | 
						CHAN5G(5805, 36), /* Channel 161 */
 | 
				
			||||||
 | 
						CHAN5G(5825, 37), /* Channel 165 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Atheros hardware rate code addition for short premble */
 | 
				
			||||||
 | 
					#define SHPCHECK(__hw_rate, __flags) \
 | 
				
			||||||
 | 
						((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RATE(_bitrate, _hw_rate, _flags) {              \
 | 
				
			||||||
 | 
						.bitrate        = (_bitrate),                   \
 | 
				
			||||||
 | 
						.flags          = (_flags),                     \
 | 
				
			||||||
 | 
						.hw_value       = (_hw_rate),                   \
 | 
				
			||||||
 | 
						.hw_value_short = (SHPCHECK(_hw_rate, _flags))  \
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ieee80211_rate ath9k_legacy_rates[] = {
 | 
				
			||||||
 | 
						RATE(10, 0x1b, 0),
 | 
				
			||||||
 | 
						RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
 | 
				
			||||||
 | 
						RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
 | 
				
			||||||
 | 
						RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
 | 
				
			||||||
 | 
						RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ |
 | 
				
			||||||
 | 
								IEEE80211_RATE_SUPPORTS_10MHZ)),
 | 
				
			||||||
 | 
						RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ |
 | 
				
			||||||
 | 
								IEEE80211_RATE_SUPPORTS_10MHZ)),
 | 
				
			||||||
 | 
						RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ |
 | 
				
			||||||
 | 
								 IEEE80211_RATE_SUPPORTS_10MHZ)),
 | 
				
			||||||
 | 
						RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ |
 | 
				
			||||||
 | 
								 IEEE80211_RATE_SUPPORTS_10MHZ)),
 | 
				
			||||||
 | 
						RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ |
 | 
				
			||||||
 | 
								 IEEE80211_RATE_SUPPORTS_10MHZ)),
 | 
				
			||||||
 | 
						RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ |
 | 
				
			||||||
 | 
								 IEEE80211_RATE_SUPPORTS_10MHZ)),
 | 
				
			||||||
 | 
						RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ |
 | 
				
			||||||
 | 
								 IEEE80211_RATE_SUPPORTS_10MHZ)),
 | 
				
			||||||
 | 
						RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ |
 | 
				
			||||||
 | 
								 IEEE80211_RATE_SUPPORTS_10MHZ)),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ath9k_cmn_init_channels_rates(struct ath_common *common)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ath_hw *ah = (struct ath_hw *)common->ah;
 | 
				
			||||||
 | 
						void *channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
 | 
				
			||||||
 | 
							     ARRAY_SIZE(ath9k_5ghz_chantable) !=
 | 
				
			||||||
 | 
							     ATH9K_NUM_CHANNELS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
 | 
				
			||||||
 | 
							channels = devm_kzalloc(ah->dev,
 | 
				
			||||||
 | 
								sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!channels)
 | 
				
			||||||
 | 
							    return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memcpy(channels, ath9k_2ghz_chantable,
 | 
				
			||||||
 | 
							       sizeof(ath9k_2ghz_chantable));
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_2GHZ].channels = channels;
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_2GHZ].n_channels =
 | 
				
			||||||
 | 
								ARRAY_SIZE(ath9k_2ghz_chantable);
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
 | 
				
			||||||
 | 
								ARRAY_SIZE(ath9k_legacy_rates);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
 | 
				
			||||||
 | 
							channels = devm_kzalloc(ah->dev,
 | 
				
			||||||
 | 
								sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!channels)
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memcpy(channels, ath9k_5ghz_chantable,
 | 
				
			||||||
 | 
							       sizeof(ath9k_5ghz_chantable));
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_5GHZ].channels = channels;
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_5GHZ].n_channels =
 | 
				
			||||||
 | 
								ARRAY_SIZE(ath9k_5ghz_chantable);
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_5GHZ].bitrates =
 | 
				
			||||||
 | 
								ath9k_legacy_rates + 4;
 | 
				
			||||||
 | 
							common->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
 | 
				
			||||||
 | 
								ARRAY_SIZE(ath9k_legacy_rates) - 4;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(ath9k_cmn_init_channels_rates);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ath9k_cmn_setup_ht_cap(struct ath_hw *ah,
 | 
				
			||||||
 | 
								    struct ieee80211_sta_ht_cap *ht_info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ath_common *common = ath9k_hw_common(ah);
 | 
				
			||||||
 | 
						u8 tx_streams, rx_streams;
 | 
				
			||||||
 | 
						int i, max_streams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ht_info->ht_supported = true;
 | 
				
			||||||
 | 
						ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 | 
				
			||||||
 | 
							       IEEE80211_HT_CAP_SM_PS |
 | 
				
			||||||
 | 
							       IEEE80211_HT_CAP_SGI_40 |
 | 
				
			||||||
 | 
							       IEEE80211_HT_CAP_DSSSCCK40;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
 | 
				
			||||||
 | 
							ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
 | 
				
			||||||
 | 
							ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
 | 
				
			||||||
 | 
						ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (AR_SREV_9271(ah) || AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah))
 | 
				
			||||||
 | 
							max_streams = 1;
 | 
				
			||||||
 | 
						else if (AR_SREV_9462(ah))
 | 
				
			||||||
 | 
							max_streams = 2;
 | 
				
			||||||
 | 
						else if (AR_SREV_9300_20_OR_LATER(ah))
 | 
				
			||||||
 | 
							max_streams = 3;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							max_streams = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (AR_SREV_9280_20_OR_LATER(ah)) {
 | 
				
			||||||
 | 
							if (max_streams >= 2)
 | 
				
			||||||
 | 
								ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
 | 
				
			||||||
 | 
							ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set up supported mcs set */
 | 
				
			||||||
 | 
						memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
 | 
				
			||||||
 | 
						tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams);
 | 
				
			||||||
 | 
						rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
 | 
				
			||||||
 | 
							tx_streams, rx_streams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tx_streams != rx_streams) {
 | 
				
			||||||
 | 
							ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
 | 
				
			||||||
 | 
							ht_info->mcs.tx_params |= ((tx_streams - 1) <<
 | 
				
			||||||
 | 
									IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < rx_streams; i++)
 | 
				
			||||||
 | 
							ht_info->mcs.rx_mask[i] = 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ath9k_cmn_reload_chainmask(struct ath_hw *ah)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ath_common *common = ath9k_hw_common(ah);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
 | 
				
			||||||
 | 
							ath9k_cmn_setup_ht_cap(ah,
 | 
				
			||||||
 | 
								&common->sbands[IEEE80211_BAND_2GHZ].ht_cap);
 | 
				
			||||||
 | 
						if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
 | 
				
			||||||
 | 
							ath9k_cmn_setup_ht_cap(ah,
 | 
				
			||||||
 | 
								&common->sbands[IEEE80211_BAND_5GHZ].ht_cap);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(ath9k_cmn_reload_chainmask);
 | 
				
			||||||
							
								
								
									
										20
									
								
								drivers/net/wireless/ath/ath9k/common-init.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								drivers/net/wireless/ath/ath9k/common-init.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2009-2011 Atheros Communications Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
				
			||||||
 | 
					 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
				
			||||||
 | 
					 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ath9k_cmn_init_channels_rates(struct ath_common *common);
 | 
				
			||||||
 | 
					void ath9k_cmn_setup_ht_cap(struct ath_hw *ah,
 | 
				
			||||||
 | 
								    struct ieee80211_sta_ht_cap *ht_info);
 | 
				
			||||||
 | 
					void ath9k_cmn_reload_chainmask(struct ath_hw *ah);
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,8 @@
 | 
				
			||||||
#include "hw.h"
 | 
					#include "hw.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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	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 {
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	 * 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 = ATH_DEFAULT_BMISS_LIMIT / 2;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
	bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
 | 
						bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
 | 
				
			||||||
	if (bs.bs_bmissthreshold > 15)
 | 
						if (bs.bs_bmissthreshold > 15)
 | 
				
			||||||
		bs.bs_bmissthreshold = 15;
 | 
							bs.bs_bmissthreshold = 15;
 | 
				
			||||||
	else if (bs.bs_bmissthreshold <= 0)
 | 
						else if (bs.bs_bmissthreshold <= 0)
 | 
				
			||||||
		bs.bs_bmissthreshold = 1;
 | 
							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,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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;
 | 
				
			||||||
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,
 | 
				
			||||||
       }
 | 
					       }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
	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)
 | 
				
			||||||
	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)
 | 
				
			||||||
	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 = {
 | 
				
			||||||
	.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 @@ err:
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	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 = {
 | 
				
			||||||
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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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);
 | 
				
			||||||
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
 | 
				
			||||||
/*     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)
 | 
				
			||||||
	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,
 | 
				
			||||||
	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)
 | 
				
			||||||
	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)
 | 
				
			||||||
	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)
 | 
				
			||||||
	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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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)
 | 
				
			||||||
		 * 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)
 | 
				
			||||||
			 * 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)
 | 
				
			||||||
			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)
 | 
				
			||||||
		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,
 | 
				
			||||||
	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)
 | 
				
			||||||
	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,
 | 
				
			||||||
			     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,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* 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)
 | 
				
			||||||
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,
 | 
				
			||||||
				      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)
 | 
				
			||||||
			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)
 | 
				
			||||||
	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 ®DomainPairs[i];
 | 
								return ®DomainPairs[i];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
| 
						 | 
					@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
 | 
				
			||||||
	printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
 | 
						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
 | 
				
			||||||
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)
 | 
				
			||||||
	return -EOPNOTSUPP;
 | 
						return -EOPNOTSUPP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
 | 
				
			||||||
 | 
								      struct station_info *sinfo)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wmi_notify_req_cmd cmd = {
 | 
				
			||||||
 | 
							.cid = cid,
 | 
				
			||||||
 | 
							.interval_usec = 0,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wil6210_mbox_hdr_wmi wmi;
 | 
				
			||||||
 | 
							struct wmi_notify_req_done_event evt;
 | 
				
			||||||
 | 
						} __packed reply;
 | 
				
			||||||
 | 
						struct wil_net_stats *stats = &wil->sta[cid].stats;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
 | 
				
			||||||
 | 
							      WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wil_dbg_wmi(wil, "Link status for CID %d: {\n"
 | 
				
			||||||
 | 
							    "  MCS %d TSF 0x%016llx\n"
 | 
				
			||||||
 | 
							    "  BF status 0x%08x SNR 0x%08x SQI %d%%\n"
 | 
				
			||||||
 | 
							    "  Tx Tpt %d goodput %d Rx goodput %d\n"
 | 
				
			||||||
 | 
							    "  Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
 | 
				
			||||||
 | 
							    cid, le16_to_cpu(reply.evt.bf_mcs),
 | 
				
			||||||
 | 
							    le64_to_cpu(reply.evt.tsf), reply.evt.status,
 | 
				
			||||||
 | 
							    le32_to_cpu(reply.evt.snr_val),
 | 
				
			||||||
 | 
							    reply.evt.sqi,
 | 
				
			||||||
 | 
							    le32_to_cpu(reply.evt.tx_tpt),
 | 
				
			||||||
 | 
							    le32_to_cpu(reply.evt.tx_goodput),
 | 
				
			||||||
 | 
							    le32_to_cpu(reply.evt.rx_goodput),
 | 
				
			||||||
 | 
							    le16_to_cpu(reply.evt.my_rx_sector),
 | 
				
			||||||
 | 
							    le16_to_cpu(reply.evt.my_tx_sector),
 | 
				
			||||||
 | 
							    le16_to_cpu(reply.evt.other_rx_sector),
 | 
				
			||||||
 | 
							    le16_to_cpu(reply.evt.other_tx_sector));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sinfo->generation = wil->sinfo_gen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sinfo->filled = STATION_INFO_RX_BYTES |
 | 
				
			||||||
 | 
								STATION_INFO_TX_BYTES |
 | 
				
			||||||
 | 
								STATION_INFO_RX_PACKETS |
 | 
				
			||||||
 | 
								STATION_INFO_TX_PACKETS |
 | 
				
			||||||
 | 
								STATION_INFO_RX_BITRATE |
 | 
				
			||||||
 | 
								STATION_INFO_TX_BITRATE |
 | 
				
			||||||
 | 
								STATION_INFO_RX_DROP_MISC |
 | 
				
			||||||
 | 
								STATION_INFO_TX_FAILED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
 | 
				
			||||||
 | 
						sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
 | 
				
			||||||
 | 
						sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
 | 
				
			||||||
 | 
						sinfo->rxrate.mcs = stats->last_mcs_rx;
 | 
				
			||||||
 | 
						sinfo->rx_bytes = stats->rx_bytes;
 | 
				
			||||||
 | 
						sinfo->rx_packets = stats->rx_packets;
 | 
				
			||||||
 | 
						sinfo->rx_dropped_misc = stats->rx_dropped;
 | 
				
			||||||
 | 
						sinfo->tx_bytes = stats->tx_bytes;
 | 
				
			||||||
 | 
						sinfo->tx_packets = stats->tx_packets;
 | 
				
			||||||
 | 
						sinfo->tx_failed = stats->tx_errors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (test_bit(wil_status_fwconnected, &wil->status)) {
 | 
				
			||||||
 | 
							sinfo->filled |= STATION_INFO_SIGNAL;
 | 
				
			||||||
 | 
							sinfo->signal = reply.evt.sqi;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int wil_cfg80211_get_station(struct wiphy *wiphy,
 | 
					static int wil_cfg80211_get_station(struct wiphy *wiphy,
 | 
				
			||||||
				    struct net_device *ndev,
 | 
									    struct net_device *ndev,
 | 
				
			||||||
				    u8 *mac, struct station_info *sinfo)
 | 
									    u8 *mac, struct station_info *sinfo)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 | 
						struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct wmi_notify_req_cmd cmd = {
 | 
					 | 
				
			||||||
		.cid = 0,
 | 
					 | 
				
			||||||
		.interval_usec = 0,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (memcmp(mac, wil->dst_addr[0], ETH_ALEN))
 | 
						int cid = wil_find_cid(wil, mac);
 | 
				
			||||||
		return -ENOENT;
 | 
					
 | 
				
			||||||
 | 
						wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid);
 | 
				
			||||||
 | 
						if (cid < 0)
 | 
				
			||||||
 | 
							return cid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = wil_cid_fill_sinfo(wil, cid, sinfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
 | 
					 | 
				
			||||||
	rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
 | 
					 | 
				
			||||||
		      WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20);
 | 
					 | 
				
			||||||
	if (rc)
 | 
					 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	sinfo->generation = wil->sinfo_gen;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sinfo->filled |= STATION_INFO_TX_BITRATE;
 | 
					 | 
				
			||||||
	sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
 | 
					 | 
				
			||||||
	sinfo->txrate.mcs = wil->stats.bf_mcs;
 | 
					 | 
				
			||||||
	sinfo->filled |= STATION_INFO_RX_BITRATE;
 | 
					 | 
				
			||||||
	sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
 | 
					 | 
				
			||||||
	sinfo->rxrate.mcs = wil->stats.last_mcs_rx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (test_bit(wil_status_fwconnected, &wil->status)) {
 | 
					 | 
				
			||||||
		sinfo->filled |= STATION_INFO_SIGNAL;
 | 
					 | 
				
			||||||
		sinfo->signal = 12; /* TODO: provide real value */
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
					/*
 | 
				
			||||||
 | 
					 * 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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
	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 = {
 | 
				
			||||||
	/* 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)
 | 
				
			||||||
	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 @@
 | 
				
			||||||
/* 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,
 | 
				
			||||||
			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)
 | 
				
			||||||
	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 = {
 | 
				
			||||||
	.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,7 +461,12 @@ 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)
 | 
				
			||||||
 | 
								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);
 | 
									   dbg_txdesc_index, vring->size);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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,13 +54,52 @@ 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 wil_sta_info *sta = &wil->sta[cid];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sta->status != wil_sta_unused) {
 | 
				
			||||||
 | 
							wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
 | 
				
			||||||
 | 
							sta->status = wil_sta_unused;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < WIL_STA_TID_NUM; i++) {
 | 
				
			||||||
 | 
							struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
 | 
				
			||||||
 | 
							sta->tid_rx[i] = NULL;
 | 
				
			||||||
 | 
							wil_tid_ampdu_rx_free(wil, r);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
 | 
				
			||||||
 | 
							if (wil->vring2cid_tid[i][0] == cid)
 | 
				
			||||||
 | 
								wil_vring_fini_tx(wil, i);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						memset(&sta->stats, 0, sizeof(sta->stats));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int cid = -ENOENT;
 | 
				
			||||||
	struct net_device *ndev = wil_to_ndev(wil);
 | 
						struct net_device *ndev = wil_to_ndev(wil);
 | 
				
			||||||
 | 
						struct wireless_dev *wdev = wil->wdev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wil_dbg_misc(wil, "%s()\n", __func__);
 | 
						might_sleep();
 | 
				
			||||||
 | 
						if (bssid) {
 | 
				
			||||||
 | 
							cid = wil_find_cid(wil, bssid);
 | 
				
			||||||
 | 
							wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							wil_dbg_misc(wil, "%s(all)\n", __func__);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cid >= 0) /* disconnect 1 peer */
 | 
				
			||||||
 | 
							wil_disconnect_cid(wil, cid);
 | 
				
			||||||
 | 
						else /* disconnect all */
 | 
				
			||||||
 | 
							for (cid = 0; cid < WIL6210_MAX_CID; cid++)
 | 
				
			||||||
 | 
								wil_disconnect_cid(wil, cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* link state */
 | 
				
			||||||
 | 
						switch (wdev->iftype) {
 | 
				
			||||||
 | 
						case NL80211_IFTYPE_STATION:
 | 
				
			||||||
 | 
						case NL80211_IFTYPE_P2P_CLIENT:
 | 
				
			||||||
		wil_link_off(wil);
 | 
							wil_link_off(wil);
 | 
				
			||||||
		if (test_bit(wil_status_fwconnected, &wil->status)) {
 | 
							if (test_bit(wil_status_fwconnected, &wil->status)) {
 | 
				
			||||||
			clear_bit(wil_status_fwconnected, &wil->status);
 | 
								clear_bit(wil_status_fwconnected, &wil->status);
 | 
				
			||||||
| 
						 | 
					@ -71,10 +112,17 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
 | 
				
			||||||
						GFP_KERNEL);
 | 
											GFP_KERNEL);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		clear_bit(wil_status_fwconnecting, &wil->status);
 | 
							clear_bit(wil_status_fwconnecting, &wil->status);
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
 | 
							wil_dbg_misc(wil, "clear_bit(wil_status_dontscan)\n");
 | 
				
			||||||
		wil_vring_fini_tx(wil, i);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		clear_bit(wil_status_dontscan, &wil->status);
 | 
							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)
 | 
				
			||||||
	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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										177
									
								
								drivers/net/wireless/ath/wil6210/rx_reorder.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								drivers/net/wireless/ath/wil6210/rx_reorder.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,177 @@
 | 
				
			||||||
 | 
					#include "wil6210.h"
 | 
				
			||||||
 | 
					#include "txrx.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SEQ_MODULO 0x1000
 | 
				
			||||||
 | 
					#define SEQ_MASK   0xfff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int seq_less(u16 sq1, u16 sq2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline u16 seq_inc(u16 sq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (sq + 1) & SEQ_MASK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline u16 seq_sub(u16 sq1, u16 sq2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (sq1 - sq2) & SEQ_MASK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return seq_sub(seq, r->ssn) % r->buf_size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wil_release_reorder_frame(struct wil6210_priv *wil,
 | 
				
			||||||
 | 
									      struct wil_tid_ampdu_rx *r,
 | 
				
			||||||
 | 
									      int index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net_device *ndev = wil_to_ndev(wil);
 | 
				
			||||||
 | 
						struct sk_buff *skb = r->reorder_buf[index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!skb)
 | 
				
			||||||
 | 
							goto no_frame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* release the frame from the reorder ring buffer */
 | 
				
			||||||
 | 
						r->stored_mpdu_num--;
 | 
				
			||||||
 | 
						r->reorder_buf[index] = NULL;
 | 
				
			||||||
 | 
						wil_netif_rx_any(skb, ndev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					no_frame:
 | 
				
			||||||
 | 
						r->head_seq_num = seq_inc(r->head_seq_num);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wil_release_reorder_frames(struct wil6210_priv *wil,
 | 
				
			||||||
 | 
									       struct wil_tid_ampdu_rx *r,
 | 
				
			||||||
 | 
									       u16 hseq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (seq_less(r->head_seq_num, hseq)) {
 | 
				
			||||||
 | 
							index = reorder_index(r, r->head_seq_num);
 | 
				
			||||||
 | 
							wil_release_reorder_frame(wil, r, index);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wil_reorder_release(struct wil6210_priv *wil,
 | 
				
			||||||
 | 
									struct wil_tid_ampdu_rx *r)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int index = reorder_index(r, r->head_seq_num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (r->reorder_buf[index]) {
 | 
				
			||||||
 | 
							wil_release_reorder_frame(wil, r, index);
 | 
				
			||||||
 | 
							index = reorder_index(r, r->head_seq_num);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net_device *ndev = wil_to_ndev(wil);
 | 
				
			||||||
 | 
						struct vring_rx_desc *d = wil_skb_rxdesc(skb);
 | 
				
			||||||
 | 
						int tid = wil_rxdesc_tid(d);
 | 
				
			||||||
 | 
						int cid = wil_rxdesc_cid(d);
 | 
				
			||||||
 | 
						int mid = wil_rxdesc_mid(d);
 | 
				
			||||||
 | 
						u16 seq = wil_rxdesc_seq(d);
 | 
				
			||||||
 | 
						struct wil_sta_info *sta = &wil->sta[cid];
 | 
				
			||||||
 | 
						struct wil_tid_ampdu_rx *r = sta->tid_rx[tid];
 | 
				
			||||||
 | 
						u16 hseq;
 | 
				
			||||||
 | 
						int index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
 | 
				
			||||||
 | 
							     mid, cid, tid, seq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!r) {
 | 
				
			||||||
 | 
							wil_netif_rx_any(skb, ndev);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hseq = r->head_seq_num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock(&r->reorder_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* frame with out of date sequence number */
 | 
				
			||||||
 | 
						if (seq_less(seq, r->head_seq_num)) {
 | 
				
			||||||
 | 
							dev_kfree_skb(skb);
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If frame the sequence number exceeds our buffering window
 | 
				
			||||||
 | 
						 * size release some previous frames to make room for this one.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
 | 
				
			||||||
 | 
							hseq = seq_inc(seq_sub(seq, r->buf_size));
 | 
				
			||||||
 | 
							/* release stored frames up to new head to stack */
 | 
				
			||||||
 | 
							wil_release_reorder_frames(wil, r, hseq);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Now the new frame is always in the range of the reordering buffer */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						index = reorder_index(r, seq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* check if we already stored this frame */
 | 
				
			||||||
 | 
						if (r->reorder_buf[index]) {
 | 
				
			||||||
 | 
							dev_kfree_skb(skb);
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If the current MPDU is in the right order and nothing else
 | 
				
			||||||
 | 
						 * is stored we can process it directly, no need to buffer it.
 | 
				
			||||||
 | 
						 * If it is first but there's something stored, we may be able
 | 
				
			||||||
 | 
						 * to release frames after this one.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (seq == r->head_seq_num && r->stored_mpdu_num == 0) {
 | 
				
			||||||
 | 
							r->head_seq_num = seq_inc(r->head_seq_num);
 | 
				
			||||||
 | 
							wil_netif_rx_any(skb, ndev);
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* put the frame in the reordering buffer */
 | 
				
			||||||
 | 
						r->reorder_buf[index] = skb;
 | 
				
			||||||
 | 
						r->reorder_time[index] = jiffies;
 | 
				
			||||||
 | 
						r->stored_mpdu_num++;
 | 
				
			||||||
 | 
						wil_reorder_release(wil, r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						spin_unlock(&r->reorder_lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
 | 
				
			||||||
 | 
											int size, u16 ssn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!r)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r->reorder_buf =
 | 
				
			||||||
 | 
							kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL);
 | 
				
			||||||
 | 
						r->reorder_time =
 | 
				
			||||||
 | 
							kcalloc(size, sizeof(unsigned long), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!r->reorder_buf || !r->reorder_time) {
 | 
				
			||||||
 | 
							kfree(r->reorder_buf);
 | 
				
			||||||
 | 
							kfree(r->reorder_time);
 | 
				
			||||||
 | 
							kfree(r);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_init(&r->reorder_lock);
 | 
				
			||||||
 | 
						r->ssn = ssn;
 | 
				
			||||||
 | 
						r->head_seq_num = ssn;
 | 
				
			||||||
 | 
						r->buf_size = size;
 | 
				
			||||||
 | 
						r->stored_mpdu_num = 0;
 | 
				
			||||||
 | 
						return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
 | 
				
			||||||
 | 
								   struct wil_tid_ampdu_rx *r)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!r)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size);
 | 
				
			||||||
 | 
						kfree(r->reorder_buf);
 | 
				
			||||||
 | 
						kfree(r->reorder_time);
 | 
				
			||||||
 | 
						kfree(r);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -344,6 +344,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
 | 
				
			||||||
	u16 dmalen;
 | 
						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,
 | 
				
			||||||
	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)
 | 
				
			||||||
 * 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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)
 | 
				
			||||||
			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,
 | 
				
			||||||
	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,14 +655,85 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
 | 
				
			||||||
static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
 | 
					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 (v->va)
 | 
						if (cid < 0)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: fix for multiple TID */
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
 | 
				
			||||||
 | 
							if (wil->vring2cid_tid[i][0] == cid) {
 | 
				
			||||||
 | 
								struct vring *v = &wil->vring_tx[i];
 | 
				
			||||||
 | 
								wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
 | 
				
			||||||
 | 
									     __func__, eth->h_dest, i);
 | 
				
			||||||
 | 
								if (v->va) {
 | 
				
			||||||
				return v;
 | 
									return v;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
 | 
				
			||||||
 | 
									return NULL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wil_set_da_for_vring(struct wil6210_priv *wil,
 | 
				
			||||||
 | 
									 struct sk_buff *skb, int vring_index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ethhdr *eth = (void *)skb->data;
 | 
				
			||||||
 | 
						int cid = wil->vring2cid_tid[vring_index][0];
 | 
				
			||||||
 | 
						memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
 | 
				
			||||||
 | 
								struct sk_buff *skb);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Find 1-st vring and return it; set dest address for this vring in skb
 | 
				
			||||||
 | 
					 * duplicate skb and send it to other active vrings
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
 | 
				
			||||||
 | 
									       struct sk_buff *skb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vring *v, *v2;
 | 
				
			||||||
 | 
						struct sk_buff *skb2;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* find 1-st vring */
 | 
				
			||||||
 | 
						for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
 | 
				
			||||||
 | 
							v = &wil->vring_tx[i];
 | 
				
			||||||
 | 
							if (v->va)
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wil_err(wil, "Tx while no vrings active?\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					found:
 | 
				
			||||||
 | 
						wil_dbg_txrx(wil, "BCAST -> ring %d\n", i);
 | 
				
			||||||
 | 
						wil_set_da_for_vring(wil, skb, i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* find other active vrings and duplicate skb for each */
 | 
				
			||||||
 | 
						for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
 | 
				
			||||||
 | 
							v2 = &wil->vring_tx[i];
 | 
				
			||||||
 | 
							if (!v2->va)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							skb2 = skb_copy(skb, GFP_ATOMIC);
 | 
				
			||||||
 | 
							if (skb2) {
 | 
				
			||||||
 | 
								wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
 | 
				
			||||||
 | 
								wil_set_da_for_vring(wil, skb2, i);
 | 
				
			||||||
 | 
								wil_tx_vring(wil, v2, skb2);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								wil_err(wil, "skb_copy failed\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return v;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
 | 
					static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
 | 
				
			||||||
			   int vring_index)
 | 
								   int vring_index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
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)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* find vring */
 | 
						/* find vring */
 | 
				
			||||||
 | 
						if (is_unicast_ether_addr(eth->h_dest)) {
 | 
				
			||||||
		vring = wil_find_tx_vring(wil, skb);
 | 
							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)
 | 
				
			||||||
	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)
 | 
				
			||||||
		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)
 | 
				
			||||||
	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 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 {
 | 
				
			||||||
	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 {
 | 
				
			||||||
	/* 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);
 | 
				
			||||||
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);
 | 
				
			||||||
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)
 | 
				
			||||||
	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)
 | 
				
			||||||
			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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 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)
 | 
				
			||||||
	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,
 | 
				
			||||||
	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,
 | 
				
			||||||
		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,
 | 
				
			||||||
	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,
 | 
				
			||||||
			      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)
 | 
				
			||||||
	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)
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.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)
 | 
				
			||||||
	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 @@
 | 
				
			||||||
#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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* 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,
 | 
				
			||||||
			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
 | 
				
			||||||
# 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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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,
 | 
				
			||||||
	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)
 | 
				
			||||||
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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		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)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	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 @@ data_ready:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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 @@ rx_error:
 | 
				
			||||||
	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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -337,7 +337,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 | 
				
			||||||
			/* iv16 */
 | 
								/* iv16 */
 | 
				
			||||||
			memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3);
 | 
								memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			iv_len = min((size_t) info->control.hw_key->iv_len,
 | 
								iv_len = min_t(size_t, info->control.hw_key->iv_len,
 | 
				
			||||||
				     ARRAY_SIZE(txhdr->iv));
 | 
									     ARRAY_SIZE(txhdr->iv));
 | 
				
			||||||
			memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
 | 
								memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -978,7 +978,7 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
 | 
				
			||||||
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
 | 
						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 b43legacy_plcp_hdr6));
 | 
							  0x200 - sizeof(struct b43legacy_plcp_hdr6));
 | 
				
			||||||
	rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
 | 
						rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1155,7 +1155,7 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
 | 
				
			||||||
	b43legacy_write_probe_resp_plcp(dev, 0x350, size,
 | 
						b43legacy_write_probe_resp_plcp(dev, 0x350, size,
 | 
				
			||||||
					&b43legacy_b_ratetable[3]);
 | 
										&b43legacy_b_ratetable[3]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size = min((size_t)size,
 | 
						size = min_t(size_t, size,
 | 
				
			||||||
		   0x200 - sizeof(struct b43legacy_plcp_hdr6));
 | 
							   0x200 - sizeof(struct b43legacy_plcp_hdr6));
 | 
				
			||||||
	b43legacy_write_template_common(dev, probe_resp_data,
 | 
						b43legacy_write_template_common(dev, probe_resp_data,
 | 
				
			||||||
					size, ram_offset,
 | 
										size, ram_offset,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,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:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -254,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
 | 
				
			||||||
				   B43legacy_TX4_MAC_KEYALG_SHIFT) &
 | 
									   B43legacy_TX4_MAC_KEYALG_SHIFT) &
 | 
				
			||||||
				   B43legacy_TX4_MAC_KEYALG;
 | 
									   B43legacy_TX4_MAC_KEYALG;
 | 
				
			||||||
			wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control);
 | 
								wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control);
 | 
				
			||||||
			iv_len = min((size_t)info->control.hw_key->iv_len,
 | 
								iv_len = min_t(size_t, info->control.hw_key->iv_len,
 | 
				
			||||||
				     ARRAY_SIZE(txhdr->iv));
 | 
									     ARRAY_SIZE(txhdr->iv));
 | 
				
			||||||
			memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
 | 
								memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,6 +53,12 @@
 | 
				
			||||||
/* Maximum milliseconds to wait for F2 to come up */
 | 
					/* Maximum milliseconds to wait for F2 to come up */
 | 
				
			||||||
#define SDIO_WAIT_F2RDY	3000
 | 
					#define SDIO_WAIT_F2RDY	3000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BRCMF_DEFAULT_TXGLOM_SIZE	32  /* max tx frames in glom chain */
 | 
				
			||||||
 | 
					#define BRCMF_DEFAULT_RXGLOM_SIZE	32  /* max rx frames in glom chain */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
 | 
				
			||||||
 | 
					module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0);
 | 
				
			||||||
 | 
					MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
 | 
					static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -487,7 +493,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
 | 
				
			||||||
	struct mmc_request mmc_req;
 | 
						struct mmc_request mmc_req;
 | 
				
			||||||
	struct mmc_command mmc_cmd;
 | 
						struct mmc_command mmc_cmd;
 | 
				
			||||||
	struct mmc_data mmc_dat;
 | 
						struct mmc_data mmc_dat;
 | 
				
			||||||
	struct sg_table st;
 | 
					 | 
				
			||||||
	struct scatterlist *sgl;
 | 
						struct scatterlist *sgl;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -532,16 +537,11 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
 | 
				
			||||||
	pkt_offset = 0;
 | 
						pkt_offset = 0;
 | 
				
			||||||
	pkt_next = target_list->next;
 | 
						pkt_next = target_list->next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sg_alloc_table(&st, max_seg_cnt, GFP_KERNEL)) {
 | 
					 | 
				
			||||||
		ret = -ENOMEM;
 | 
					 | 
				
			||||||
		goto exit;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&mmc_req, 0, sizeof(struct mmc_request));
 | 
						memset(&mmc_req, 0, sizeof(struct mmc_request));
 | 
				
			||||||
	memset(&mmc_cmd, 0, sizeof(struct mmc_command));
 | 
						memset(&mmc_cmd, 0, sizeof(struct mmc_command));
 | 
				
			||||||
	memset(&mmc_dat, 0, sizeof(struct mmc_data));
 | 
						memset(&mmc_dat, 0, sizeof(struct mmc_data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mmc_dat.sg = st.sgl;
 | 
						mmc_dat.sg = sdiodev->sgtable.sgl;
 | 
				
			||||||
	mmc_dat.blksz = func_blk_sz;
 | 
						mmc_dat.blksz = func_blk_sz;
 | 
				
			||||||
	mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
 | 
						mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
 | 
				
			||||||
	mmc_cmd.opcode = SD_IO_RW_EXTENDED;
 | 
						mmc_cmd.opcode = SD_IO_RW_EXTENDED;
 | 
				
			||||||
| 
						 | 
					@ -557,7 +557,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
 | 
				
			||||||
	while (seg_sz) {
 | 
						while (seg_sz) {
 | 
				
			||||||
		req_sz = 0;
 | 
							req_sz = 0;
 | 
				
			||||||
		sg_cnt = 0;
 | 
							sg_cnt = 0;
 | 
				
			||||||
		sgl = st.sgl;
 | 
							sgl = sdiodev->sgtable.sgl;
 | 
				
			||||||
		/* prep sg table */
 | 
							/* prep sg table */
 | 
				
			||||||
		while (pkt_next != (struct sk_buff *)target_list) {
 | 
							while (pkt_next != (struct sk_buff *)target_list) {
 | 
				
			||||||
			pkt_data = pkt_next->data + pkt_offset;
 | 
								pkt_data = pkt_next->data + pkt_offset;
 | 
				
			||||||
| 
						 | 
					@ -639,7 +639,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit:
 | 
					exit:
 | 
				
			||||||
	sg_free_table(&st);
 | 
						sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents);
 | 
				
			||||||
	while ((pkt_next = __skb_dequeue(&local_list)) != NULL)
 | 
						while ((pkt_next = __skb_dequeue(&local_list)) != NULL)
 | 
				
			||||||
		brcmu_pkt_buf_free_skb(pkt_next);
 | 
							brcmu_pkt_buf_free_skb(pkt_next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -863,6 +863,29 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint nents;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sdiodev->sg_support)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz);
 | 
				
			||||||
 | 
						nents += (nents >> 4) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						WARN_ON(nents > sdiodev->max_segment_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						brcmf_dbg(TRACE, "nents=%d\n", nents);
 | 
				
			||||||
 | 
						err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							brcmf_err("allocation failed: disable scatter-gather");
 | 
				
			||||||
 | 
							sdiodev->sg_support = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdiodev->txglomsz = brcmf_sdiod_txglomsz;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
 | 
					static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (sdiodev->bus) {
 | 
						if (sdiodev->bus) {
 | 
				
			||||||
| 
						 | 
					@ -880,6 +903,7 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)
 | 
				
			||||||
	sdio_disable_func(sdiodev->func[1]);
 | 
						sdio_disable_func(sdiodev->func[1]);
 | 
				
			||||||
	sdio_release_host(sdiodev->func[1]);
 | 
						sdio_release_host(sdiodev->func[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sg_free_table(&sdiodev->sgtable);
 | 
				
			||||||
	sdiodev->sbwad = 0;
 | 
						sdiodev->sbwad = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -935,6 +959,11 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
 | 
				
			||||||
					   SG_MAX_SINGLE_ALLOC);
 | 
										   SG_MAX_SINGLE_ALLOC);
 | 
				
			||||||
	sdiodev->max_segment_size = host->max_seg_size;
 | 
						sdiodev->max_segment_size = host->max_seg_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* allocate scatter-gather table. sg support
 | 
				
			||||||
 | 
						 * will be disabled upon allocation failure.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						brcmf_sdiod_sgtable_alloc(sdiodev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* try to attach to the target device */
 | 
						/* try to attach to the target device */
 | 
				
			||||||
	sdiodev->bus = brcmf_sdio_probe(sdiodev);
 | 
						sdiodev->bus = brcmf_sdio_probe(sdiodev);
 | 
				
			||||||
	if (!sdiodev->bus) {
 | 
						if (!sdiodev->bus) {
 | 
				
			||||||
| 
						 | 
					@ -1072,9 +1101,7 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
 | 
				
			||||||
	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 | 
						struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	brcmf_dbg(SDIO, "\n");
 | 
						brcmf_dbg(SDIO, "Enter\n");
 | 
				
			||||||
 | 
					 | 
				
			||||||
	atomic_set(&sdiodev->suspend, true);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
 | 
						sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
 | 
				
			||||||
	if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
 | 
						if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
 | 
				
			||||||
| 
						 | 
					@ -1082,9 +1109,12 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atomic_set(&sdiodev->suspend, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
 | 
						ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		brcmf_err("Failed to set pm_flags\n");
 | 
							brcmf_err("Failed to set pm_flags\n");
 | 
				
			||||||
 | 
							atomic_set(&sdiodev->suspend, false);
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1098,6 +1128,7 @@ static int brcmf_ops_sdio_resume(struct device *dev)
 | 
				
			||||||
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 | 
						struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 | 
				
			||||||
	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 | 
						struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						brcmf_dbg(SDIO, "Enter\n");
 | 
				
			||||||
	brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
 | 
						brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
 | 
				
			||||||
	atomic_set(&sdiodev->suspend, false);
 | 
						atomic_set(&sdiodev->suspend, false);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1040,12 +1040,12 @@ void brcmf_detach(struct device *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	brcmf_cfg80211_detach(drvr->config);
 | 
						brcmf_cfg80211_detach(drvr->config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						brcmf_fws_deinit(drvr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	brcmf_bus_detach(drvr);
 | 
						brcmf_bus_detach(drvr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	brcmf_proto_detach(drvr);
 | 
						brcmf_proto_detach(drvr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	brcmf_fws_deinit(drvr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	brcmf_debugfs_detach(drvr);
 | 
						brcmf_debugfs_detach(drvr);
 | 
				
			||||||
	bus_if->drvr = NULL;
 | 
						bus_if->drvr = NULL;
 | 
				
			||||||
	kfree(drvr);
 | 
						kfree(drvr);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,8 +113,6 @@ struct rte_console {
 | 
				
			||||||
#define BRCMF_TXBOUND	20	/* Default for max tx frames in
 | 
					#define BRCMF_TXBOUND	20	/* Default for max tx frames in
 | 
				
			||||||
				 one scheduling */
 | 
									 one scheduling */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BRCMF_DEFAULT_TXGLOM_SIZE	32  /* max tx frames in glom chain */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define BRCMF_TXMINMAX	1	/* Max tx frames if rx still pending */
 | 
					#define BRCMF_TXMINMAX	1	/* Max tx frames if rx still pending */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MEMBLOCK	2048	/* Block size used for downloading
 | 
					#define MEMBLOCK	2048	/* Block size used for downloading
 | 
				
			||||||
| 
						 | 
					@ -304,7 +302,6 @@ struct rte_console {
 | 
				
			||||||
/* Flags for SDH calls */
 | 
					/* Flags for SDH calls */
 | 
				
			||||||
#define F2SYNC	(SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 | 
					#define F2SYNC	(SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BRCMF_IDLE_IMMEDIATE	(-1)	/* Enter idle immediately */
 | 
					 | 
				
			||||||
#define BRCMF_IDLE_ACTIVE	0	/* Do not request any SD clock change
 | 
					#define BRCMF_IDLE_ACTIVE	0	/* Do not request any SD clock change
 | 
				
			||||||
					 * when idle
 | 
										 * when idle
 | 
				
			||||||
					 */
 | 
										 */
 | 
				
			||||||
| 
						 | 
					@ -511,10 +508,6 @@ static const uint max_roundup = 512;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALIGNMENT  4
 | 
					#define ALIGNMENT  4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int brcmf_sdio_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE;
 | 
					 | 
				
			||||||
module_param_named(txglomsz, brcmf_sdio_txglomsz, int, 0);
 | 
					 | 
				
			||||||
MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum brcmf_sdio_frmtype {
 | 
					enum brcmf_sdio_frmtype {
 | 
				
			||||||
	BRCMF_SDIO_FT_NORMAL,
 | 
						BRCMF_SDIO_FT_NORMAL,
 | 
				
			||||||
	BRCMF_SDIO_FT_SUPER,
 | 
						BRCMF_SDIO_FT_SUPER,
 | 
				
			||||||
| 
						 | 
					@ -770,8 +763,6 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PKT_AVAILABLE()		(intstatus & I_HMB_FRAME_IND)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define HOSTINTMASK		(I_HMB_SW_MASK | I_CHIPACTIVE)
 | 
					#define HOSTINTMASK		(I_HMB_SW_MASK | I_CHIPACTIVE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Turn backplane clock on or off */
 | 
					/* Turn backplane clock on or off */
 | 
				
			||||||
| 
						 | 
					@ -870,7 +861,6 @@ static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif				/* defined (DEBUG) */
 | 
					#endif				/* defined (DEBUG) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bus->activity = true;
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		clkreq = 0;
 | 
							clkreq = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1240,6 +1230,28 @@ static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 | 
				
			||||||
	bus->cur_read.len = 0;
 | 
						bus->cur_read.len = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void brcmf_sdio_txfail(struct brcmf_sdio *bus)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct brcmf_sdio_dev *sdiodev = bus->sdiodev;
 | 
				
			||||||
 | 
						u8 i, hi, lo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* On failure, abort the command and terminate the frame */
 | 
				
			||||||
 | 
						brcmf_err("sdio error, abort command and terminate frame\n");
 | 
				
			||||||
 | 
						bus->sdcnt.tx_sderrs++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						brcmf_sdiod_abort(sdiodev, SDIO_FUNC_2);
 | 
				
			||||||
 | 
						brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL);
 | 
				
			||||||
 | 
						bus->sdcnt.f1regdata++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 3; i++) {
 | 
				
			||||||
 | 
							hi = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL);
 | 
				
			||||||
 | 
							lo = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL);
 | 
				
			||||||
 | 
							bus->sdcnt.f1regdata += 2;
 | 
				
			||||||
 | 
							if ((hi == 0) && (lo == 0))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* return total length of buffer chain */
 | 
					/* return total length of buffer chain */
 | 
				
			||||||
static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)
 | 
					static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -2110,7 +2122,7 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
 | 
				
			||||||
		memcpy(pkt_pad->data,
 | 
							memcpy(pkt_pad->data,
 | 
				
			||||||
		       pkt->data + pkt->len - tail_chop,
 | 
							       pkt->data + pkt->len - tail_chop,
 | 
				
			||||||
		       tail_chop);
 | 
							       tail_chop);
 | 
				
			||||||
		*(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
 | 
							*(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
 | 
				
			||||||
		skb_trim(pkt, pkt->len - tail_chop);
 | 
							skb_trim(pkt, pkt->len - tail_chop);
 | 
				
			||||||
		skb_trim(pkt_pad, tail_pad + tail_chop);
 | 
							skb_trim(pkt_pad, tail_pad + tail_chop);
 | 
				
			||||||
		__skb_queue_after(pktq, pkt, pkt_pad);
 | 
							__skb_queue_after(pktq, pkt, pkt_pad);
 | 
				
			||||||
| 
						 | 
					@ -2158,7 +2170,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 | 
				
			||||||
		 * already properly aligned and does not
 | 
							 * already properly aligned and does not
 | 
				
			||||||
		 * need an sdpcm header.
 | 
							 * need an sdpcm header.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
 | 
							if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* align packet data pointer */
 | 
							/* align packet data pointer */
 | 
				
			||||||
| 
						 | 
					@ -2192,10 +2204,10 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 | 
				
			||||||
		if (BRCMF_BYTES_ON() &&
 | 
							if (BRCMF_BYTES_ON() &&
 | 
				
			||||||
		    ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
 | 
							    ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
 | 
				
			||||||
		     (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
 | 
							     (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
 | 
				
			||||||
			brcmf_dbg_hex_dump(true, pkt_next, hd_info.len,
 | 
								brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len,
 | 
				
			||||||
					   "Tx Frame:\n");
 | 
										   "Tx Frame:\n");
 | 
				
			||||||
		else if (BRCMF_HDRS_ON())
 | 
							else if (BRCMF_HDRS_ON())
 | 
				
			||||||
			brcmf_dbg_hex_dump(true, pkt_next,
 | 
								brcmf_dbg_hex_dump(true, pkt_next->data,
 | 
				
			||||||
					   head_pad + bus->tx_hdrlen,
 | 
										   head_pad + bus->tx_hdrlen,
 | 
				
			||||||
					   "Tx Header:\n");
 | 
										   "Tx Header:\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2222,11 +2234,11 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
 | 
				
			||||||
	u8 *hdr;
 | 
						u8 *hdr;
 | 
				
			||||||
	u32 dat_offset;
 | 
						u32 dat_offset;
 | 
				
			||||||
	u16 tail_pad;
 | 
						u16 tail_pad;
 | 
				
			||||||
	u32 dummy_flags, chop_len;
 | 
						u16 dummy_flags, chop_len;
 | 
				
			||||||
	struct sk_buff *pkt_next, *tmp, *pkt_prev;
 | 
						struct sk_buff *pkt_next, *tmp, *pkt_prev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	skb_queue_walk_safe(pktq, pkt_next, tmp) {
 | 
						skb_queue_walk_safe(pktq, pkt_next, tmp) {
 | 
				
			||||||
		dummy_flags = *(u32 *)(pkt_next->cb);
 | 
							dummy_flags = *(u16 *)(pkt_next->cb);
 | 
				
			||||||
		if (dummy_flags & ALIGN_SKB_FLAG) {
 | 
							if (dummy_flags & ALIGN_SKB_FLAG) {
 | 
				
			||||||
			chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
 | 
								chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
 | 
				
			||||||
			if (chop_len) {
 | 
								if (chop_len) {
 | 
				
			||||||
| 
						 | 
					@ -2255,7 +2267,6 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 | 
				
			||||||
			    uint chan)
 | 
								    uint chan)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	struct sk_buff *pkt_next, *tmp;
 | 
						struct sk_buff *pkt_next, *tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	brcmf_dbg(TRACE, "Enter\n");
 | 
						brcmf_dbg(TRACE, "Enter\n");
 | 
				
			||||||
| 
						 | 
					@ -2268,28 +2279,9 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
 | 
				
			||||||
	ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
 | 
						ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);
 | 
				
			||||||
	bus->sdcnt.f2txdata++;
 | 
						bus->sdcnt.f2txdata++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0)
 | 
				
			||||||
		/* On failure, abort the command and terminate the frame */
 | 
							brcmf_sdio_txfail(bus);
 | 
				
			||||||
		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
 | 
					 | 
				
			||||||
			  ret);
 | 
					 | 
				
			||||||
		bus->sdcnt.tx_sderrs++;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
 | 
					 | 
				
			||||||
		brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 | 
					 | 
				
			||||||
				  SFC_WF_TERM, NULL);
 | 
					 | 
				
			||||||
		bus->sdcnt.f1regdata++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (i = 0; i < 3; i++) {
 | 
					 | 
				
			||||||
			u8 hi, lo;
 | 
					 | 
				
			||||||
			hi = brcmf_sdiod_regrb(bus->sdiodev,
 | 
					 | 
				
			||||||
					       SBSDIO_FUNC1_WFRAMEBCHI, NULL);
 | 
					 | 
				
			||||||
			lo = brcmf_sdiod_regrb(bus->sdiodev,
 | 
					 | 
				
			||||||
					       SBSDIO_FUNC1_WFRAMEBCLO, NULL);
 | 
					 | 
				
			||||||
			bus->sdcnt.f1regdata += 2;
 | 
					 | 
				
			||||||
			if ((hi == 0) && (lo == 0))
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sdio_release_host(bus->sdiodev->func[1]);
 | 
						sdio_release_host(bus->sdiodev->func[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
| 
						 | 
					@ -2322,7 +2314,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 | 
				
			||||||
		__skb_queue_head_init(&pktq);
 | 
							__skb_queue_head_init(&pktq);
 | 
				
			||||||
		if (bus->txglom)
 | 
							if (bus->txglom)
 | 
				
			||||||
			pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
 | 
								pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
 | 
				
			||||||
					brcmf_sdio_txglomsz);
 | 
										bus->sdiodev->txglomsz);
 | 
				
			||||||
		pkt_num = min_t(u32, pkt_num,
 | 
							pkt_num = min_t(u32, pkt_num,
 | 
				
			||||||
				brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol));
 | 
									brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol));
 | 
				
			||||||
		spin_lock_bh(&bus->txqlock);
 | 
							spin_lock_bh(&bus->txqlock);
 | 
				
			||||||
| 
						 | 
					@ -2341,7 +2333,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 | 
				
			||||||
		cnt += i;
 | 
							cnt += i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* In poll mode, need to check for other events */
 | 
							/* In poll mode, need to check for other events */
 | 
				
			||||||
		if (!bus->intr && cnt) {
 | 
							if (!bus->intr) {
 | 
				
			||||||
			/* Check device status, signal pending interrupt */
 | 
								/* Check device status, signal pending interrupt */
 | 
				
			||||||
			sdio_claim_host(bus->sdiodev->func[1]);
 | 
								sdio_claim_host(bus->sdiodev->func[1]);
 | 
				
			||||||
			ret = r_sdreg32(bus, &intstatus,
 | 
								ret = r_sdreg32(bus, &intstatus,
 | 
				
			||||||
| 
						 | 
					@ -2447,12 +2439,21 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void atomic_orr(int val, atomic_t *v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int old_val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						old_val = atomic_read(v);
 | 
				
			||||||
 | 
						while (atomic_cmpxchg(v, old_val, val | old_val) != old_val)
 | 
				
			||||||
 | 
							old_val = atomic_read(v);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
 | 
					static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct brcmf_core *buscore;
 | 
						struct brcmf_core *buscore;
 | 
				
			||||||
	u32 addr;
 | 
						u32 addr;
 | 
				
			||||||
	unsigned long val;
 | 
						unsigned long val;
 | 
				
			||||||
	int n, ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
 | 
						buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV);
 | 
				
			||||||
	addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
 | 
						addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus);
 | 
				
			||||||
| 
						 | 
					@ -2460,7 +2461,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
 | 
				
			||||||
	val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
 | 
						val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);
 | 
				
			||||||
	bus->sdcnt.f1regdata++;
 | 
						bus->sdcnt.f1regdata++;
 | 
				
			||||||
	if (ret != 0)
 | 
						if (ret != 0)
 | 
				
			||||||
		val = 0;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	val &= bus->hostintmask;
 | 
						val &= bus->hostintmask;
 | 
				
			||||||
	atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
 | 
						atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
 | 
				
			||||||
| 
						 | 
					@ -2469,13 +2470,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
 | 
				
			||||||
	if (val) {
 | 
						if (val) {
 | 
				
			||||||
		brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
 | 
							brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);
 | 
				
			||||||
		bus->sdcnt.f1regdata++;
 | 
							bus->sdcnt.f1regdata++;
 | 
				
			||||||
	}
 | 
							atomic_orr(val, &bus->intstatus);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		atomic_set(&bus->intstatus, 0);
 | 
					 | 
				
			||||||
	} else if (val) {
 | 
					 | 
				
			||||||
		for_each_set_bit(n, &val, 32)
 | 
					 | 
				
			||||||
			set_bit(n, (unsigned long *)&bus->intstatus.counter);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
| 
						 | 
					@ -2485,10 +2480,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 newstatus = 0;
 | 
						u32 newstatus = 0;
 | 
				
			||||||
	unsigned long intstatus;
 | 
						unsigned long intstatus;
 | 
				
			||||||
	uint rxlimit = bus->rxbound;	/* Rx frames to read before resched */
 | 
					 | 
				
			||||||
	uint txlimit = bus->txbound;	/* Tx frames to send before resched */
 | 
						uint txlimit = bus->txbound;	/* Tx frames to send before resched */
 | 
				
			||||||
	uint framecnt = 0;	/* Temporary counter of tx/rx frames */
 | 
						uint framecnt;			/* Temporary counter of tx/rx frames */
 | 
				
			||||||
	int err = 0, n;
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	brcmf_dbg(TRACE, "Enter\n");
 | 
						brcmf_dbg(TRACE, "Enter\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2585,58 +2579,30 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 | 
				
			||||||
		intstatus &= ~I_HMB_FRAME_IND;
 | 
							intstatus &= ~I_HMB_FRAME_IND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* On frame indication, read available frames */
 | 
						/* On frame indication, read available frames */
 | 
				
			||||||
	if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) {
 | 
						if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) {
 | 
				
			||||||
		framecnt = brcmf_sdio_readframes(bus, rxlimit);
 | 
							brcmf_sdio_readframes(bus, bus->rxbound);
 | 
				
			||||||
		if (!bus->rxpending)
 | 
							if (!bus->rxpending)
 | 
				
			||||||
			intstatus &= ~I_HMB_FRAME_IND;
 | 
								intstatus &= ~I_HMB_FRAME_IND;
 | 
				
			||||||
		rxlimit -= min(framecnt, rxlimit);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Keep still-pending events for next scheduling */
 | 
						/* Keep still-pending events for next scheduling */
 | 
				
			||||||
	if (intstatus) {
 | 
						if (intstatus)
 | 
				
			||||||
		for_each_set_bit(n, &intstatus, 32)
 | 
							atomic_orr(intstatus, &bus->intstatus);
 | 
				
			||||||
			set_bit(n, (unsigned long *)&bus->intstatus.counter);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	brcmf_sdio_clrintr(bus);
 | 
						brcmf_sdio_clrintr(bus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data_ok(bus) && bus->ctrl_frame_stat &&
 | 
						if (data_ok(bus) && bus->ctrl_frame_stat &&
 | 
				
			||||||
	    (bus->clkstate == CLK_AVAIL)) {
 | 
						    (bus->clkstate == CLK_AVAIL)) {
 | 
				
			||||||
		int i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sdio_claim_host(bus->sdiodev->func[1]);
 | 
							sdio_claim_host(bus->sdiodev->func[1]);
 | 
				
			||||||
		err = brcmf_sdiod_send_buf(bus->sdiodev, bus->ctrl_frame_buf,
 | 
							err = brcmf_sdiod_send_buf(bus->sdiodev, bus->ctrl_frame_buf,
 | 
				
			||||||
					   (u32)bus->ctrl_frame_len);
 | 
										   (u32)bus->ctrl_frame_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (err < 0) {
 | 
							if (err < 0)
 | 
				
			||||||
			/* On failure, abort the command and
 | 
								brcmf_sdio_txfail(bus);
 | 
				
			||||||
				terminate the frame */
 | 
							else
 | 
				
			||||||
			brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
 | 
					 | 
				
			||||||
				  err);
 | 
					 | 
				
			||||||
			bus->sdcnt.tx_sderrs++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 | 
					 | 
				
			||||||
					  SFC_WF_TERM, &err);
 | 
					 | 
				
			||||||
			bus->sdcnt.f1regdata++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			for (i = 0; i < 3; i++) {
 | 
					 | 
				
			||||||
				u8 hi, lo;
 | 
					 | 
				
			||||||
				hi = brcmf_sdiod_regrb(bus->sdiodev,
 | 
					 | 
				
			||||||
						       SBSDIO_FUNC1_WFRAMEBCHI,
 | 
					 | 
				
			||||||
						       &err);
 | 
					 | 
				
			||||||
				lo = brcmf_sdiod_regrb(bus->sdiodev,
 | 
					 | 
				
			||||||
						       SBSDIO_FUNC1_WFRAMEBCLO,
 | 
					 | 
				
			||||||
						       &err);
 | 
					 | 
				
			||||||
				bus->sdcnt.f1regdata += 2;
 | 
					 | 
				
			||||||
				if ((hi == 0) && (lo == 0))
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
 | 
								bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
 | 
				
			||||||
		}
 | 
					
 | 
				
			||||||
		sdio_release_host(bus->sdiodev->func[1]);
 | 
							sdio_release_host(bus->sdiodev->func[1]);
 | 
				
			||||||
		bus->ctrl_frame_stat = false;
 | 
							bus->ctrl_frame_stat = false;
 | 
				
			||||||
		brcmf_sdio_wait_event_wakeup(bus);
 | 
							brcmf_sdio_wait_event_wakeup(bus);
 | 
				
			||||||
| 
						 | 
					@ -2647,8 +2613,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 | 
				
			||||||
		 && data_ok(bus)) {
 | 
							 && data_ok(bus)) {
 | 
				
			||||||
		framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :
 | 
							framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :
 | 
				
			||||||
					    txlimit;
 | 
										    txlimit;
 | 
				
			||||||
		framecnt = brcmf_sdio_sendfromq(bus, framecnt);
 | 
							brcmf_sdio_sendfromq(bus, framecnt);
 | 
				
			||||||
		txlimit -= framecnt;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
 | 
						if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
 | 
				
			||||||
| 
						 | 
					@ -2658,19 +2623,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
 | 
				
			||||||
		   atomic_read(&bus->ipend) > 0 ||
 | 
							   atomic_read(&bus->ipend) > 0 ||
 | 
				
			||||||
		   (!atomic_read(&bus->fcstate) &&
 | 
							   (!atomic_read(&bus->fcstate) &&
 | 
				
			||||||
		    brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
 | 
							    brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
 | 
				
			||||||
		    data_ok(bus)) || PKT_AVAILABLE()) {
 | 
							    data_ok(bus))) {
 | 
				
			||||||
		atomic_inc(&bus->dpc_tskcnt);
 | 
							atomic_inc(&bus->dpc_tskcnt);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* If we're done for now, turn off clock request. */
 | 
					 | 
				
			||||||
	if ((bus->clkstate != CLK_PENDING)
 | 
					 | 
				
			||||||
	    && bus->idletime == BRCMF_IDLE_IMMEDIATE) {
 | 
					 | 
				
			||||||
		bus->activity = false;
 | 
					 | 
				
			||||||
		brcmf_dbg(SDIO, "idle state\n");
 | 
					 | 
				
			||||||
		sdio_claim_host(bus->sdiodev->func[1]);
 | 
					 | 
				
			||||||
		brcmf_sdio_bus_sleep(bus, true, false);
 | 
					 | 
				
			||||||
		sdio_release_host(bus->sdiodev->func[1]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
 | 
					static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
 | 
				
			||||||
| 
						 | 
					@ -2685,15 +2640,13 @@ static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
 | 
				
			||||||
static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
 | 
					static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret = -EBADE;
 | 
						int ret = -EBADE;
 | 
				
			||||||
	uint datalen, prec;
 | 
						uint prec;
 | 
				
			||||||
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 | 
						struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 | 
				
			||||||
	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 | 
						struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 | 
				
			||||||
	struct brcmf_sdio *bus = sdiodev->bus;
 | 
						struct brcmf_sdio *bus = sdiodev->bus;
 | 
				
			||||||
	ulong flags;
 | 
						ulong flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	brcmf_dbg(TRACE, "Enter\n");
 | 
						brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	datalen = pkt->len;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add space for the header */
 | 
						/* Add space for the header */
 | 
				
			||||||
	skb_push(pkt, bus->tx_hdrlen);
 | 
						skb_push(pkt, bus->tx_hdrlen);
 | 
				
			||||||
| 
						 | 
					@ -2708,6 +2661,8 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Priority based enq */
 | 
						/* Priority based enq */
 | 
				
			||||||
	spin_lock_irqsave(&bus->txqlock, flags);
 | 
						spin_lock_irqsave(&bus->txqlock, flags);
 | 
				
			||||||
 | 
						/* reset bus_flags in packet cb */
 | 
				
			||||||
 | 
						*(u16 *)(pkt->cb) = 0;
 | 
				
			||||||
	if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
 | 
						if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
 | 
				
			||||||
		skb_pull(pkt, bus->tx_hdrlen);
 | 
							skb_pull(pkt, bus->tx_hdrlen);
 | 
				
			||||||
		brcmf_err("out of bus->txq !!!\n");
 | 
							brcmf_err("out of bus->txq !!!\n");
 | 
				
			||||||
| 
						 | 
					@ -2817,37 +2772,14 @@ break2:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int brcmf_sdio_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 | 
					static int brcmf_sdio_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bus->ctrl_frame_stat = false;
 | 
						bus->ctrl_frame_stat = false;
 | 
				
			||||||
	ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len);
 | 
						ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0)
 | 
				
			||||||
		/* On failure, abort the command and terminate the frame */
 | 
							brcmf_sdio_txfail(bus);
 | 
				
			||||||
		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
 | 
						else
 | 
				
			||||||
			  ret);
 | 
					 | 
				
			||||||
		bus->sdcnt.tx_sderrs++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
 | 
					 | 
				
			||||||
				  SFC_WF_TERM, NULL);
 | 
					 | 
				
			||||||
		bus->sdcnt.f1regdata++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (i = 0; i < 3; i++) {
 | 
					 | 
				
			||||||
			u8 hi, lo;
 | 
					 | 
				
			||||||
			hi = brcmf_sdiod_regrb(bus->sdiodev,
 | 
					 | 
				
			||||||
					       SBSDIO_FUNC1_WFRAMEBCHI, NULL);
 | 
					 | 
				
			||||||
			lo = brcmf_sdiod_regrb(bus->sdiodev,
 | 
					 | 
				
			||||||
					       SBSDIO_FUNC1_WFRAMEBCLO, NULL);
 | 
					 | 
				
			||||||
			bus->sdcnt.f1regdata += 2;
 | 
					 | 
				
			||||||
			if (hi == 0 && lo == 0)
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
 | 
							bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
| 
						 | 
					@ -2947,15 +2879,6 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 | 
				
			||||||
		} while (ret < 0 && retries++ < TXRETRIES);
 | 
							} while (ret < 0 && retries++ < TXRETRIES);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) &&
 | 
					 | 
				
			||||||
	    atomic_read(&bus->dpc_tskcnt) == 0) {
 | 
					 | 
				
			||||||
		bus->activity = false;
 | 
					 | 
				
			||||||
		sdio_claim_host(bus->sdiodev->func[1]);
 | 
					 | 
				
			||||||
		brcmf_dbg(INFO, "idle\n");
 | 
					 | 
				
			||||||
		brcmf_sdio_clkctl(bus, CLK_NONE, true);
 | 
					 | 
				
			||||||
		sdio_release_host(bus->sdiodev->func[1]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		bus->sdcnt.tx_ctlerrs++;
 | 
							bus->sdcnt.tx_ctlerrs++;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -3753,8 +3676,8 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
 | 
				
			||||||
					      datawork);
 | 
										      datawork);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (atomic_read(&bus->dpc_tskcnt)) {
 | 
						while (atomic_read(&bus->dpc_tskcnt)) {
 | 
				
			||||||
 | 
							atomic_set(&bus->dpc_tskcnt, 0);
 | 
				
			||||||
		brcmf_sdio_dpc(bus);
 | 
							brcmf_sdio_dpc(bus);
 | 
				
			||||||
		atomic_dec(&bus->dpc_tskcnt);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -180,6 +180,8 @@ struct brcmf_sdio_dev {
 | 
				
			||||||
	uint max_request_size;
 | 
						uint max_request_size;
 | 
				
			||||||
	ushort max_segment_count;
 | 
						ushort max_segment_count;
 | 
				
			||||||
	uint max_segment_size;
 | 
						uint max_segment_size;
 | 
				
			||||||
 | 
						uint txglomsz;
 | 
				
			||||||
 | 
						struct sg_table sgtable;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* sdio core registers */
 | 
					/* sdio core registers */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
#include <linux/etherdevice.h>
 | 
					#include <linux/etherdevice.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <net/cfg80211.h>
 | 
					#include <net/cfg80211.h>
 | 
				
			||||||
#include <net/netlink.h>
 | 
					#include <net/netlink.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -251,6 +252,10 @@ struct parsed_vndr_ies {
 | 
				
			||||||
	struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
 | 
						struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int brcmf_roamoff;
 | 
				
			||||||
 | 
					module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
 | 
				
			||||||
 | 
					MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Quarter dBm units to mW
 | 
					/* Quarter dBm units to mW
 | 
				
			||||||
 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
 | 
					 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
 | 
				
			||||||
 * Table is offset so the last entry is largest mW value that fits in
 | 
					 * Table is offset so the last entry is largest mW value that fits in
 | 
				
			||||||
| 
						 | 
					@ -4444,7 +4449,9 @@ static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
 | 
				
			||||||
	u32 event = e->event_code;
 | 
						u32 event = e->event_code;
 | 
				
			||||||
	u16 flags = e->flags;
 | 
						u16 flags = e->flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
 | 
						if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
 | 
				
			||||||
 | 
						    (event == BRCMF_E_DISASSOC_IND) ||
 | 
				
			||||||
 | 
						    ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
 | 
				
			||||||
		brcmf_dbg(CONN, "Processing link down\n");
 | 
							brcmf_dbg(CONN, "Processing link down\n");
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -4688,6 +4695,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
 | 
				
			||||||
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
 | 
						struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
 | 
				
			||||||
	struct ieee80211_channel *chan;
 | 
						struct ieee80211_channel *chan;
 | 
				
			||||||
	s32 err = 0;
 | 
						s32 err = 0;
 | 
				
			||||||
 | 
						u16 reason;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ifp->vif->mode == WL_MODE_AP) {
 | 
						if (ifp->vif->mode == WL_MODE_AP) {
 | 
				
			||||||
		err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
 | 
							err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
 | 
				
			||||||
| 
						 | 
					@ -4709,10 +4717,16 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
 | 
				
			||||||
		if (!brcmf_is_ibssmode(ifp->vif)) {
 | 
							if (!brcmf_is_ibssmode(ifp->vif)) {
 | 
				
			||||||
			brcmf_bss_connect_done(cfg, ndev, e, false);
 | 
								brcmf_bss_connect_done(cfg, ndev, e, false);
 | 
				
			||||||
			if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
 | 
								if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
 | 
				
			||||||
					       &ifp->vif->sme_state))
 | 
										       &ifp->vif->sme_state)) {
 | 
				
			||||||
				cfg80211_disconnected(ndev, 0, NULL, 0,
 | 
									reason = 0;
 | 
				
			||||||
 | 
									if (((e->event_code == BRCMF_E_DEAUTH_IND) ||
 | 
				
			||||||
 | 
									     (e->event_code == BRCMF_E_DISASSOC_IND)) &&
 | 
				
			||||||
 | 
									    (e->reason != WLAN_REASON_UNSPECIFIED))
 | 
				
			||||||
 | 
										reason = e->reason;
 | 
				
			||||||
 | 
									cfg80211_disconnected(ndev, reason, NULL, 0,
 | 
				
			||||||
						      GFP_KERNEL);
 | 
											      GFP_KERNEL);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		brcmf_link_down(ifp->vif);
 | 
							brcmf_link_down(ifp->vif);
 | 
				
			||||||
		brcmf_init_prof(ndev_to_prof(ndev));
 | 
							brcmf_init_prof(ndev_to_prof(ndev));
 | 
				
			||||||
		if (ndev != cfg_to_ndev(cfg))
 | 
							if (ndev != cfg_to_ndev(cfg))
 | 
				
			||||||
| 
						 | 
					@ -4905,10 +4919,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->scan_request = NULL;
 | 
						cfg->scan_request = NULL;
 | 
				
			||||||
	cfg->pwr_save = true;
 | 
						cfg->pwr_save = true;
 | 
				
			||||||
	cfg->roam_on = true;	/* roam on & off switch.
 | 
						cfg->active_scan = true;	/* we do active scan per default */
 | 
				
			||||||
				 we enable roam per default */
 | 
					 | 
				
			||||||
	cfg->active_scan = true;	/* we do active scan for
 | 
					 | 
				
			||||||
				 specific scan per default */
 | 
					 | 
				
			||||||
	cfg->dongle_up = false;		/* dongle is not up yet */
 | 
						cfg->dongle_up = false;		/* dongle is not up yet */
 | 
				
			||||||
	err = brcmf_init_priv_mem(cfg);
 | 
						err = brcmf_init_priv_mem(cfg);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
| 
						 | 
					@ -5029,7 +5040,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static s32
 | 
					static s32
 | 
				
			||||||
brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
 | 
					brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	s32 err = 0;
 | 
						s32 err = 0;
 | 
				
			||||||
	__le32 roamtrigger[2];
 | 
						__le32 roamtrigger[2];
 | 
				
			||||||
| 
						 | 
					@ -5039,7 +5050,7 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
 | 
				
			||||||
	 * Setup timeout if Beacons are lost and roam is
 | 
						 * Setup timeout if Beacons are lost and roam is
 | 
				
			||||||
	 * off to report link down
 | 
						 * off to report link down
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (roamvar) {
 | 
						if (brcmf_roamoff) {
 | 
				
			||||||
		err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
 | 
							err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
 | 
				
			||||||
		if (err) {
 | 
							if (err) {
 | 
				
			||||||
			brcmf_err("bcn_timeout error (%d)\n", err);
 | 
								brcmf_err("bcn_timeout error (%d)\n", err);
 | 
				
			||||||
| 
						 | 
					@ -5051,8 +5062,9 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
 | 
				
			||||||
	 * Enable/Disable built-in roaming to allow supplicant
 | 
						 * Enable/Disable built-in roaming to allow supplicant
 | 
				
			||||||
	 * to take care of roaming
 | 
						 * to take care of roaming
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
 | 
						brcmf_dbg(INFO, "Internal Roaming = %s\n",
 | 
				
			||||||
	err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
 | 
							  brcmf_roamoff ? "Off" : "On");
 | 
				
			||||||
 | 
						err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		brcmf_err("roam_off error (%d)\n", err);
 | 
							brcmf_err("roam_off error (%d)\n", err);
 | 
				
			||||||
		goto dongle_rom_out;
 | 
							goto dongle_rom_out;
 | 
				
			||||||
| 
						 | 
					@ -5294,6 +5306,8 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
 | 
				
			||||||
	u32 band_list[3];
 | 
						u32 band_list[3];
 | 
				
			||||||
	u32 nmode;
 | 
						u32 nmode;
 | 
				
			||||||
	u32 bw_cap[2] = { 0, 0 };
 | 
						u32 bw_cap[2] = { 0, 0 };
 | 
				
			||||||
 | 
						u32 rxchain;
 | 
				
			||||||
 | 
						u32 nchain;
 | 
				
			||||||
	s8 phy;
 | 
						s8 phy;
 | 
				
			||||||
	s32 err;
 | 
						s32 err;
 | 
				
			||||||
	u32 nband;
 | 
						u32 nband;
 | 
				
			||||||
| 
						 | 
					@ -5330,6 +5344,16 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
 | 
				
			||||||
	brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
 | 
						brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
 | 
				
			||||||
		  bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
 | 
							  bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							brcmf_err("rxchain error (%d)\n", err);
 | 
				
			||||||
 | 
							nchain = 1;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							for (nchain = 0; rxchain; nchain++)
 | 
				
			||||||
 | 
								rxchain = rxchain & (rxchain - 1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						brcmf_dbg(INFO, "nchain=%d\n", nchain);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = brcmf_construct_reginfo(cfg, bw_cap);
 | 
						err = brcmf_construct_reginfo(cfg, bw_cap);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
 | 
							brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
 | 
				
			||||||
| 
						 | 
					@ -5358,10 +5382,7 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
 | 
				
			||||||
		band->ht_cap.ht_supported = true;
 | 
							band->ht_cap.ht_supported = true;
 | 
				
			||||||
		band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
 | 
							band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
 | 
				
			||||||
		band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
 | 
							band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
 | 
				
			||||||
		/* An HT shall support all EQM rates for one spatial
 | 
							memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
 | 
				
			||||||
		 * stream
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		band->ht_cap.mcs.rx_mask[0] = 0xff;
 | 
					 | 
				
			||||||
		band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 | 
							band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 | 
				
			||||||
		bands[band->band] = band;
 | 
							bands[band->band] = band;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -5408,7 +5429,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
 | 
				
			||||||
	brcmf_dbg(INFO, "power save set to %s\n",
 | 
						brcmf_dbg(INFO, "power save set to %s\n",
 | 
				
			||||||
		  (power_mode ? "enabled" : "disabled"));
 | 
							  (power_mode ? "enabled" : "disabled"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
 | 
						err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto default_conf_out;
 | 
							goto default_conf_out;
 | 
				
			||||||
	err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
 | 
						err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -402,7 +402,6 @@ struct brcmf_cfg80211_info {
 | 
				
			||||||
	bool ibss_starter;
 | 
						bool ibss_starter;
 | 
				
			||||||
	bool pwr_save;
 | 
						bool pwr_save;
 | 
				
			||||||
	bool dongle_up;
 | 
						bool dongle_up;
 | 
				
			||||||
	bool roam_on;
 | 
					 | 
				
			||||||
	bool scan_tried;
 | 
						bool scan_tried;
 | 
				
			||||||
	u8 *dcmd_buf;
 | 
						u8 *dcmd_buf;
 | 
				
			||||||
	u8 *extra_buf;
 | 
						u8 *extra_buf;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -202,8 +202,8 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* calculate the block size */
 | 
							/* calculate the block size */
 | 
				
			||||||
		tx_size = block_size = min((size_t)(firmware->size - put),
 | 
							tx_size = block_size = min_t(size_t, firmware->size - put,
 | 
				
			||||||
			(size_t)DOWNLOAD_BLOCK_SIZE);
 | 
										DOWNLOAD_BLOCK_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		memcpy(buf, &firmware->data[put], block_size);
 | 
							memcpy(buf, &firmware->data[put], block_size);
 | 
				
			||||||
		if (block_size < DOWNLOAD_BLOCK_SIZE) {
 | 
							if (block_size < DOWNLOAD_BLOCK_SIZE) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -677,6 +677,8 @@ static const struct pcmcia_device_id hostap_cs_ids[] = {
 | 
				
			||||||
	PCMCIA_DEVICE_PROD_ID12(
 | 
						PCMCIA_DEVICE_PROD_ID12(
 | 
				
			||||||
		"ZoomAir 11Mbps High", "Rate wireless Networking",
 | 
							"ZoomAir 11Mbps High", "Rate wireless Networking",
 | 
				
			||||||
		0x273fe3db, 0x32a1eaee),
 | 
							0x273fe3db, 0x32a1eaee),
 | 
				
			||||||
 | 
						PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card",
 | 
				
			||||||
 | 
							0xa37434e9, 0x9762e8f1),
 | 
				
			||||||
	PCMCIA_DEVICE_PROD_ID123(
 | 
						PCMCIA_DEVICE_PROD_ID123(
 | 
				
			||||||
		"Pretec", "CompactWLAN Card 802.11b", "2.5",
 | 
							"Pretec", "CompactWLAN Card 802.11b", "2.5",
 | 
				
			||||||
		0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
 | 
							0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7065,7 +7065,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev,
 | 
				
			||||||
	if (wrqu->data.length > IW_ESSID_MAX_SIZE)
 | 
						if (wrqu->data.length > IW_ESSID_MAX_SIZE)
 | 
				
			||||||
		return -E2BIG;
 | 
							return -E2BIG;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
 | 
						wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
 | 
				
			||||||
	memset(priv->nick, 0, sizeof(priv->nick));
 | 
						memset(priv->nick, 0, sizeof(priv->nick));
 | 
				
			||||||
	memcpy(priv->nick, extra, wrqu->data.length);
 | 
						memcpy(priv->nick, extra, wrqu->data.length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9169,7 +9169,7 @@ static int ipw_wx_set_nick(struct net_device *dev,
 | 
				
			||||||
	if (wrqu->data.length > IW_ESSID_MAX_SIZE)
 | 
						if (wrqu->data.length > IW_ESSID_MAX_SIZE)
 | 
				
			||||||
		return -E2BIG;
 | 
							return -E2BIG;
 | 
				
			||||||
	mutex_lock(&priv->mutex);
 | 
						mutex_lock(&priv->mutex);
 | 
				
			||||||
	wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
 | 
						wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
 | 
				
			||||||
	memset(priv->nick, 0, sizeof(priv->nick));
 | 
						memset(priv->nick, 0, sizeof(priv->nick));
 | 
				
			||||||
	memcpy(priv->nick, extra, wrqu->data.length);
 | 
						memcpy(priv->nick, extra, wrqu->data.length);
 | 
				
			||||||
	IPW_DEBUG_TRACE("<<\n");
 | 
						IPW_DEBUG_TRACE("<<\n");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1248,14 +1248,7 @@ il3945_rx_handle(struct il_priv *il)
 | 
				
			||||||
		len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
 | 
							len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
 | 
				
			||||||
		len += sizeof(u32);	/* account for status word */
 | 
							len += sizeof(u32);	/* account for status word */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Reclaim a command buffer only if this packet is a response
 | 
							reclaim = il_need_reclaim(il, pkt);
 | 
				
			||||||
		 *   to a (driver-originated) command.
 | 
					 | 
				
			||||||
		 * If the packet (e.g. Rx frame) originated from uCode,
 | 
					 | 
				
			||||||
		 *   there is no command buffer to reclaim.
 | 
					 | 
				
			||||||
		 * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
 | 
					 | 
				
			||||||
		 *   but apparently a few don't get set; catch them here. */
 | 
					 | 
				
			||||||
		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
 | 
					 | 
				
			||||||
		    pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Based on type of command response or notification,
 | 
							/* Based on type of command response or notification,
 | 
				
			||||||
		 *   handle those that need handling via function in
 | 
							 *   handle those that need handling via function in
 | 
				
			||||||
| 
						 | 
					@ -1495,12 +1488,14 @@ il3945_irq_tasklet(struct il_priv *il)
 | 
				
			||||||
	if (inta & CSR_INT_BIT_WAKEUP) {
 | 
						if (inta & CSR_INT_BIT_WAKEUP) {
 | 
				
			||||||
		D_ISR("Wakeup interrupt\n");
 | 
							D_ISR("Wakeup interrupt\n");
 | 
				
			||||||
		il_rx_queue_update_write_ptr(il, &il->rxq);
 | 
							il_rx_queue_update_write_ptr(il, &il->rxq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							spin_lock_irqsave(&il->lock, flags);
 | 
				
			||||||
		il_txq_update_write_ptr(il, &il->txq[0]);
 | 
							il_txq_update_write_ptr(il, &il->txq[0]);
 | 
				
			||||||
		il_txq_update_write_ptr(il, &il->txq[1]);
 | 
							il_txq_update_write_ptr(il, &il->txq[1]);
 | 
				
			||||||
		il_txq_update_write_ptr(il, &il->txq[2]);
 | 
							il_txq_update_write_ptr(il, &il->txq[2]);
 | 
				
			||||||
		il_txq_update_write_ptr(il, &il->txq[3]);
 | 
							il_txq_update_write_ptr(il, &il->txq[3]);
 | 
				
			||||||
		il_txq_update_write_ptr(il, &il->txq[4]);
 | 
							il_txq_update_write_ptr(il, &il->txq[4]);
 | 
				
			||||||
		il_txq_update_write_ptr(il, &il->txq[5]);
 | 
							spin_unlock_irqrestore(&il->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		il->isr_stats.wakeup++;
 | 
							il->isr_stats.wakeup++;
 | 
				
			||||||
		handled |= CSR_INT_BIT_WAKEUP;
 | 
							handled |= CSR_INT_BIT_WAKEUP;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -92,7 +92,6 @@ il4965_check_abort_status(struct il_priv *il, u8 frame_count, u32 status)
 | 
				
			||||||
 * EEPROM
 | 
					 * EEPROM
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct il_mod_params il4965_mod_params = {
 | 
					struct il_mod_params il4965_mod_params = {
 | 
				
			||||||
	.amsdu_size_8K = 1,
 | 
					 | 
				
			||||||
	.restart_fw = 1,
 | 
						.restart_fw = 1,
 | 
				
			||||||
	/* the rest are 0 by default */
 | 
						/* the rest are 0 by default */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -4274,17 +4273,7 @@ il4965_rx_handle(struct il_priv *il)
 | 
				
			||||||
		len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
 | 
							len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
 | 
				
			||||||
		len += sizeof(u32);	/* account for status word */
 | 
							len += sizeof(u32);	/* account for status word */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Reclaim a command buffer only if this packet is a response
 | 
							reclaim = il_need_reclaim(il, pkt);
 | 
				
			||||||
		 *   to a (driver-originated) command.
 | 
					 | 
				
			||||||
		 * If the packet (e.g. Rx frame) originated from uCode,
 | 
					 | 
				
			||||||
		 *   there is no command buffer to reclaim.
 | 
					 | 
				
			||||||
		 * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
 | 
					 | 
				
			||||||
		 *   but apparently a few don't get set; catch them here. */
 | 
					 | 
				
			||||||
		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
 | 
					 | 
				
			||||||
		    (pkt->hdr.cmd != N_RX_PHY) && (pkt->hdr.cmd != N_RX) &&
 | 
					 | 
				
			||||||
		    (pkt->hdr.cmd != N_RX_MPDU) &&
 | 
					 | 
				
			||||||
		    (pkt->hdr.cmd != N_COMPRESSED_BA) &&
 | 
					 | 
				
			||||||
		    (pkt->hdr.cmd != N_STATS) && (pkt->hdr.cmd != C_TX);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Based on type of command response or notification,
 | 
							/* Based on type of command response or notification,
 | 
				
			||||||
		 *   handle those that need handling via function in
 | 
							 *   handle those that need handling via function in
 | 
				
			||||||
| 
						 | 
					@ -6876,6 +6865,6 @@ module_param_named(11n_disable, il4965_mod_params.disable_11n, int, S_IRUGO);
 | 
				
			||||||
MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
 | 
					MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
 | 
				
			||||||
module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int,
 | 
					module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int,
 | 
				
			||||||
		   S_IRUGO);
 | 
							   S_IRUGO);
 | 
				
			||||||
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
 | 
					MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0 [disabled])");
 | 
				
			||||||
module_param_named(fw_restart, il4965_mod_params.restart_fw, int, S_IRUGO);
 | 
					module_param_named(fw_restart, il4965_mod_params.restart_fw, int, S_IRUGO);
 | 
				
			||||||
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
 | 
					MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2271,6 +2271,7 @@ struct il_spectrum_notification {
 | 
				
			||||||
#define IL_POWER_VEC_SIZE 5
 | 
					#define IL_POWER_VEC_SIZE 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK		cpu_to_le16(BIT(0))
 | 
					#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK		cpu_to_le16(BIT(0))
 | 
				
			||||||
 | 
					#define IL_POWER_SLEEP_OVER_DTIM_MSK		cpu_to_le16(BIT(2))
 | 
				
			||||||
#define IL_POWER_PCI_PM_MSK			cpu_to_le16(BIT(3))
 | 
					#define IL_POWER_PCI_PM_MSK			cpu_to_le16(BIT(3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct il3945_powertable_cmd {
 | 
					struct il3945_powertable_cmd {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1078,29 +1078,82 @@ EXPORT_SYMBOL(il_get_channel_info);
 | 
				
			||||||
 * Setting power level allows the card to go to sleep when not busy.
 | 
					 * Setting power level allows the card to go to sleep when not busy.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * We calculate a sleep command based on the required latency, which
 | 
					 * We calculate a sleep command based on the required latency, which
 | 
				
			||||||
 * we get from mac80211. In order to handle thermal throttling, we can
 | 
					 * we get from mac80211.
 | 
				
			||||||
 * also use pre-defined power levels.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					#define SLP_VEC(X0, X1, X2, X3, X4) { \
 | 
				
			||||||
 * This defines the old power levels. They are still used by default
 | 
							cpu_to_le32(X0), \
 | 
				
			||||||
 * (level 1) and for thermal throttle (levels 3 through 5)
 | 
							cpu_to_le32(X1), \
 | 
				
			||||||
 */
 | 
							cpu_to_le32(X2), \
 | 
				
			||||||
 | 
							cpu_to_le32(X3), \
 | 
				
			||||||
struct il_power_vec_entry {
 | 
							cpu_to_le32(X4)  \
 | 
				
			||||||
	struct il_powertable_cmd cmd;
 | 
					}
 | 
				
			||||||
	u8 no_dtim;		/* number of skip dtim */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
il_power_sleep_cam_cmd(struct il_priv *il, struct il_powertable_cmd *cmd)
 | 
					il_build_powertable_cmd(struct il_priv *il, struct il_powertable_cmd *cmd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						const __le32 interval[3][IL_POWER_VEC_SIZE] = {
 | 
				
			||||||
 | 
							SLP_VEC(2, 2, 4, 6, 0xFF),
 | 
				
			||||||
 | 
							SLP_VEC(2, 4, 7, 10, 10),
 | 
				
			||||||
 | 
							SLP_VEC(4, 7, 10, 10, 0xFF)
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						int i, dtim_period, no_dtim;
 | 
				
			||||||
 | 
						u32 max_sleep;
 | 
				
			||||||
 | 
						bool skip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(cmd, 0, sizeof(*cmd));
 | 
						memset(cmd, 0, sizeof(*cmd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (il->power_data.pci_pm)
 | 
						if (il->power_data.pci_pm)
 | 
				
			||||||
		cmd->flags |= IL_POWER_PCI_PM_MSK;
 | 
							cmd->flags |= IL_POWER_PCI_PM_MSK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	D_POWER("Sleep command for CAM\n");
 | 
						/* if no Power Save, we are done */
 | 
				
			||||||
 | 
						if (il->power_data.ps_disabled)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd->flags = IL_POWER_DRIVER_ALLOW_SLEEP_MSK;
 | 
				
			||||||
 | 
						cmd->keep_alive_seconds = 0;
 | 
				
			||||||
 | 
						cmd->debug_flags = 0;
 | 
				
			||||||
 | 
						cmd->rx_data_timeout = cpu_to_le32(25 * 1024);
 | 
				
			||||||
 | 
						cmd->tx_data_timeout = cpu_to_le32(25 * 1024);
 | 
				
			||||||
 | 
						cmd->keep_alive_beacons = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dtim_period = il->vif ? il->vif->bss_conf.dtim_period : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dtim_period <= 2) {
 | 
				
			||||||
 | 
							memcpy(cmd->sleep_interval, interval[0], sizeof(interval[0]));
 | 
				
			||||||
 | 
							no_dtim = 2;
 | 
				
			||||||
 | 
						} else if (dtim_period <= 10) {
 | 
				
			||||||
 | 
							memcpy(cmd->sleep_interval, interval[1], sizeof(interval[1]));
 | 
				
			||||||
 | 
							no_dtim = 2;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							memcpy(cmd->sleep_interval, interval[2], sizeof(interval[2]));
 | 
				
			||||||
 | 
							no_dtim = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dtim_period == 0) {
 | 
				
			||||||
 | 
							dtim_period = 1;
 | 
				
			||||||
 | 
							skip = false;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							skip = !!no_dtim;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (skip) {
 | 
				
			||||||
 | 
							__le32 tmp = cmd->sleep_interval[IL_POWER_VEC_SIZE - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							max_sleep = le32_to_cpu(tmp);
 | 
				
			||||||
 | 
							if (max_sleep == 0xFF)
 | 
				
			||||||
 | 
								max_sleep = dtim_period * (skip + 1);
 | 
				
			||||||
 | 
							else if (max_sleep >  dtim_period)
 | 
				
			||||||
 | 
								max_sleep = (max_sleep / dtim_period) * dtim_period;
 | 
				
			||||||
 | 
							cmd->flags |= IL_POWER_SLEEP_OVER_DTIM_MSK;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							max_sleep = dtim_period;
 | 
				
			||||||
 | 
							cmd->flags &= ~IL_POWER_SLEEP_OVER_DTIM_MSK;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < IL_POWER_VEC_SIZE; i++)
 | 
				
			||||||
 | 
							if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
 | 
				
			||||||
 | 
								cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
| 
						 | 
					@ -1173,7 +1226,8 @@ il_power_update_mode(struct il_priv *il, bool force)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct il_powertable_cmd cmd;
 | 
						struct il_powertable_cmd cmd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	il_power_sleep_cam_cmd(il, &cmd);
 | 
						il_build_powertable_cmd(il, &cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return il_power_set_mode(il, &cmd, force);
 | 
						return il_power_set_mode(il, &cmd, force);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(il_power_update_mode);
 | 
					EXPORT_SYMBOL(il_power_update_mode);
 | 
				
			||||||
| 
						 | 
					@ -5081,6 +5135,7 @@ set_ch_out:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) {
 | 
						if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) {
 | 
				
			||||||
 | 
							il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS);
 | 
				
			||||||
		ret = il_power_update_mode(il, false);
 | 
							ret = il_power_update_mode(il, false);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			D_MAC80211("Error setting sleep level\n");
 | 
								D_MAC80211("Error setting sleep level\n");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1123,6 +1123,7 @@ struct il_power_mgr {
 | 
				
			||||||
	struct il_powertable_cmd sleep_cmd_next;
 | 
						struct il_powertable_cmd sleep_cmd_next;
 | 
				
			||||||
	int debug_sleep_level_override;
 | 
						int debug_sleep_level_override;
 | 
				
			||||||
	bool pci_pm;
 | 
						bool pci_pm;
 | 
				
			||||||
 | 
						bool ps_disabled;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct il_priv {
 | 
					struct il_priv {
 | 
				
			||||||
| 
						 | 
					@ -1597,7 +1598,7 @@ struct il_mod_params {
 | 
				
			||||||
	int disable_hw_scan;	/* def: 0 = use h/w scan */
 | 
						int disable_hw_scan;	/* def: 0 = use h/w scan */
 | 
				
			||||||
	int num_of_queues;	/* def: HW dependent */
 | 
						int num_of_queues;	/* def: HW dependent */
 | 
				
			||||||
	int disable_11n;	/* def: 0 = 11n capabilities enabled */
 | 
						int disable_11n;	/* def: 0 = 11n capabilities enabled */
 | 
				
			||||||
	int amsdu_size_8K;	/* def: 1 = enable 8K amsdu size */
 | 
						int amsdu_size_8K;	/* def: 0 = disable 8K amsdu size */
 | 
				
			||||||
	int antenna;		/* def: 0 = both antennas (use diversity) */
 | 
						int antenna;		/* def: 0 = both antennas (use diversity) */
 | 
				
			||||||
	int restart_fw;		/* def: 1 = restart firmware */
 | 
						int restart_fw;		/* def: 1 = restart firmware */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1978,6 +1979,20 @@ void il_wr_prph(struct il_priv *il, u32 addr, u32 val);
 | 
				
			||||||
u32 il_read_targ_mem(struct il_priv *il, u32 addr);
 | 
					u32 il_read_targ_mem(struct il_priv *il, u32 addr);
 | 
				
			||||||
void il_write_targ_mem(struct il_priv *il, u32 addr, u32 val);
 | 
					void il_write_targ_mem(struct il_priv *il, u32 addr, u32 val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool il_need_reclaim(struct il_priv *il, struct il_rx_pkt *pkt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Reclaim a command buffer only if this packet is a response
 | 
				
			||||||
 | 
						 * to a (driver-originated) command. If the packet (e.g. Rx frame)
 | 
				
			||||||
 | 
						 * originated from uCode, there is no command buffer to reclaim.
 | 
				
			||||||
 | 
						 * Ucode should set SEQ_RX_FRAME bit if ucode-originated, but
 | 
				
			||||||
 | 
						 * apparently a few don't get set; catch them here.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						return !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
 | 
				
			||||||
 | 
						       pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX &&
 | 
				
			||||||
 | 
						       pkt->hdr.cmd != N_RX_PHY && pkt->hdr.cmd != N_RX &&
 | 
				
			||||||
 | 
						       pkt->hdr.cmd != N_RX_MPDU && pkt->hdr.cmd != N_COMPRESSED_BA;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void
 | 
					static inline void
 | 
				
			||||||
_il_write8(struct il_priv *il, u32 ofs, u8 val)
 | 
					_il_write8(struct il_priv *il, u32 ofs, u8 val)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -109,7 +109,7 @@ extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct iwl_ucode_capabilities;
 | 
					struct iwl_ucode_capabilities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct ieee80211_ops iwlagn_hw_ops;
 | 
					extern const struct ieee80211_ops iwlagn_hw_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
 | 
					static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -480,7 +480,7 @@ do {									\
 | 
				
			||||||
} while (0)
 | 
					} while (0)
 | 
				
			||||||
#endif				/* CONFIG_IWLWIFI_DEBUG */
 | 
					#endif				/* CONFIG_IWLWIFI_DEBUG */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const char *iwl_dvm_cmd_strings[REPLY_MAX];
 | 
					extern const char *const iwl_dvm_cmd_strings[REPLY_MAX];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
 | 
					static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -317,7 +317,7 @@ static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
 | 
				
			||||||
	.nrg_th_cca = 62,
 | 
						.nrg_th_cca = 62,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
 | 
					static const struct iwl_sensitivity_ranges iwl5150_sensitivity = {
 | 
				
			||||||
	.min_nrg_cck = 95,
 | 
						.min_nrg_cck = 95,
 | 
				
			||||||
	.auto_corr_min_ofdm = 90,
 | 
						.auto_corr_min_ofdm = 90,
 | 
				
			||||||
	.auto_corr_min_ofdm_mrc = 170,
 | 
						.auto_corr_min_ofdm_mrc = 170,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1582,7 +1582,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
 | 
				
			||||||
	IWL_DEBUG_MAC80211(priv, "leave\n");
 | 
						IWL_DEBUG_MAC80211(priv, "leave\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ieee80211_ops iwlagn_hw_ops = {
 | 
					const struct ieee80211_ops iwlagn_hw_ops = {
 | 
				
			||||||
	.tx = iwlagn_mac_tx,
 | 
						.tx = iwlagn_mac_tx,
 | 
				
			||||||
	.start = iwlagn_mac_start,
 | 
						.start = iwlagn_mac_start,
 | 
				
			||||||
	.stop = iwlagn_mac_stop,
 | 
						.stop = iwlagn_mac_stop,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IWL_CMD_ENTRY(x) [x] = #x
 | 
					#define IWL_CMD_ENTRY(x) [x] = #x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
 | 
					const char *const iwl_dvm_cmd_strings[REPLY_MAX] = {
 | 
				
			||||||
	IWL_CMD_ENTRY(REPLY_ALIVE),
 | 
						IWL_CMD_ENTRY(REPLY_ALIVE),
 | 
				
			||||||
	IWL_CMD_ENTRY(REPLY_ERROR),
 | 
						IWL_CMD_ENTRY(REPLY_ERROR),
 | 
				
			||||||
	IWL_CMD_ENTRY(REPLY_ECHO),
 | 
						IWL_CMD_ENTRY(REPLY_ECHO),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -404,6 +404,38 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data,
 | 
				
			||||||
 | 
									   struct iwl_ucode_capabilities *capa)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct iwl_ucode_api *ucode_api = (void *)data;
 | 
				
			||||||
 | 
						u32 api_index = le32_to_cpu(ucode_api->api_index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (api_index >= IWL_API_ARRAY_SIZE) {
 | 
				
			||||||
 | 
							IWL_ERR(drv, "api_index larger than supported by driver\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						capa->api[api_index] = le32_to_cpu(ucode_api->api_flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data,
 | 
				
			||||||
 | 
									      struct iwl_ucode_capabilities *capa)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct iwl_ucode_capa *ucode_capa = (void *)data;
 | 
				
			||||||
 | 
						u32 api_index = le32_to_cpu(ucode_capa->api_index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (api_index >= IWL_CAPABILITIES_ARRAY_SIZE) {
 | 
				
			||||||
 | 
							IWL_ERR(drv, "api_index larger than supported by driver\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						capa->capa[api_index] = le32_to_cpu(ucode_capa->api_capa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
 | 
					static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
 | 
				
			||||||
				    const struct firmware *ucode_raw,
 | 
									    const struct firmware *ucode_raw,
 | 
				
			||||||
				    struct iwl_firmware_pieces *pieces)
 | 
									    struct iwl_firmware_pieces *pieces)
 | 
				
			||||||
| 
						 | 
					@ -638,6 +670,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			capa->flags = le32_to_cpup((__le32 *)tlv_data);
 | 
								capa->flags = le32_to_cpup((__le32 *)tlv_data);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case IWL_UCODE_TLV_API_CHANGES_SET:
 | 
				
			||||||
 | 
								if (tlv_len != sizeof(struct iwl_ucode_api))
 | 
				
			||||||
 | 
									goto invalid_tlv_len;
 | 
				
			||||||
 | 
								if (iwl_set_ucode_api_flags(drv, tlv_data, capa))
 | 
				
			||||||
 | 
									goto tlv_error;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case IWL_UCODE_TLV_ENABLED_CAPABILITIES:
 | 
				
			||||||
 | 
								if (tlv_len != sizeof(struct iwl_ucode_capa))
 | 
				
			||||||
 | 
									goto invalid_tlv_len;
 | 
				
			||||||
 | 
								if (iwl_set_ucode_capabilities(drv, tlv_data, capa))
 | 
				
			||||||
 | 
									goto tlv_error;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
 | 
							case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
 | 
				
			||||||
			if (tlv_len != sizeof(u32))
 | 
								if (tlv_len != sizeof(u32))
 | 
				
			||||||
				goto invalid_tlv_len;
 | 
									goto invalid_tlv_len;
 | 
				
			||||||
| 
						 | 
					@ -728,6 +772,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
 | 
				
			||||||
			if (tlv_len != sizeof(u32))
 | 
								if (tlv_len != sizeof(u32))
 | 
				
			||||||
				goto invalid_tlv_len;
 | 
									goto invalid_tlv_len;
 | 
				
			||||||
			drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
 | 
								drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
 | 
				
			||||||
 | 
								drv->fw.valid_tx_ant = (drv->fw.phy_config &
 | 
				
			||||||
 | 
											FW_PHY_CFG_TX_CHAIN) >>
 | 
				
			||||||
 | 
											FW_PHY_CFG_TX_CHAIN_POS;
 | 
				
			||||||
 | 
								drv->fw.valid_rx_ant = (drv->fw.phy_config &
 | 
				
			||||||
 | 
											FW_PHY_CFG_RX_CHAIN) >>
 | 
				
			||||||
 | 
											FW_PHY_CFG_RX_CHAIN_POS;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		 case IWL_UCODE_TLV_SECURE_SEC_RT:
 | 
							 case IWL_UCODE_TLV_SECURE_SEC_RT:
 | 
				
			||||||
			iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
 | 
								iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
 | 
				
			||||||
| 
						 | 
					@ -1301,8 +1351,7 @@ MODULE_PARM_DESC(antenna_coupling,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
 | 
					module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
 | 
				
			||||||
MODULE_PARM_DESC(wd_disable,
 | 
					MODULE_PARM_DESC(wd_disable,
 | 
				
			||||||
		"Disable stuck queue watchdog timer 0=system default, "
 | 
							"Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)");
 | 
				
			||||||
		"1=disable, 2=enable (default: 0)");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
 | 
					module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
 | 
				
			||||||
MODULE_PARM_DESC(nvm_file, "NVM file name");
 | 
					MODULE_PARM_DESC(nvm_file, "NVM file name");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,6 +70,20 @@
 | 
				
			||||||
#define DRV_COPYRIGHT	"Copyright(c) 2003- 2014 Intel Corporation"
 | 
					#define DRV_COPYRIGHT	"Copyright(c) 2003- 2014 Intel Corporation"
 | 
				
			||||||
#define DRV_AUTHOR     "<ilw@linux.intel.com>"
 | 
					#define DRV_AUTHOR     "<ilw@linux.intel.com>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* radio config bits (actual values from NVM definition) */
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_DASH_MSK(x)   (x & 0x3)         /* bits 0-1   */
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_TYPE_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(x)   (x & 0xF)
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_DASH_MSK_FAMILY_8000(x)   ((x >> 4) & 0xF)
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_STEP_MSK_FAMILY_8000(x)   ((x >> 8) & 0xF)
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_TYPE_MSK_FAMILY_8000(x)   ((x >> 12) & 0xFFF)
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(x) ((x >> 24) & 0xF)
 | 
				
			||||||
 | 
					#define NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(x) ((x >> 28) & 0xF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * DOC: Driver system flows - drv component
 | 
					 * DOC: Driver system flows - drv component
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,16 +81,17 @@ struct iwl_nvm_data {
 | 
				
			||||||
	bool sku_cap_band_24GHz_enable;
 | 
						bool sku_cap_band_24GHz_enable;
 | 
				
			||||||
	bool sku_cap_band_52GHz_enable;
 | 
						bool sku_cap_band_52GHz_enable;
 | 
				
			||||||
	bool sku_cap_11n_enable;
 | 
						bool sku_cap_11n_enable;
 | 
				
			||||||
 | 
						bool sku_cap_11ac_enable;
 | 
				
			||||||
	bool sku_cap_amt_enable;
 | 
						bool sku_cap_amt_enable;
 | 
				
			||||||
	bool sku_cap_ipan_enable;
 | 
						bool sku_cap_ipan_enable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u8 radio_cfg_type;
 | 
						u16 radio_cfg_type;
 | 
				
			||||||
	u8 radio_cfg_step;
 | 
						u8 radio_cfg_step;
 | 
				
			||||||
	u8 radio_cfg_dash;
 | 
						u8 radio_cfg_dash;
 | 
				
			||||||
	u8 radio_cfg_pnum;
 | 
						u8 radio_cfg_pnum;
 | 
				
			||||||
	u8 valid_tx_ant, valid_rx_ant;
 | 
						u8 valid_tx_ant, valid_rx_ant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u16 nvm_version;
 | 
						u32 nvm_version;
 | 
				
			||||||
	s8 max_tx_pwr_half_dbm;
 | 
						s8 max_tx_pwr_half_dbm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
 | 
						struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,6 +126,8 @@ enum iwl_ucode_tlv_type {
 | 
				
			||||||
	IWL_UCODE_TLV_SECURE_SEC_WOWLAN	= 26,
 | 
						IWL_UCODE_TLV_SECURE_SEC_WOWLAN	= 26,
 | 
				
			||||||
	IWL_UCODE_TLV_NUM_OF_CPU	= 27,
 | 
						IWL_UCODE_TLV_NUM_OF_CPU	= 27,
 | 
				
			||||||
	IWL_UCODE_TLV_CSCHEME		= 28,
 | 
						IWL_UCODE_TLV_CSCHEME		= 28,
 | 
				
			||||||
 | 
						IWL_UCODE_TLV_API_CHANGES_SET	= 29,
 | 
				
			||||||
 | 
						IWL_UCODE_TLV_ENABLED_CAPABILITIES	= 30,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct iwl_ucode_tlv {
 | 
					struct iwl_ucode_tlv {
 | 
				
			||||||
| 
						 | 
					@ -158,4 +160,19 @@ struct iwl_tlv_ucode_header {
 | 
				
			||||||
	u8 data[0];
 | 
						u8 data[0];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ucode TLVs
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * ability to get extension for: flags & capabilities from ucode binaries files
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct iwl_ucode_api {
 | 
				
			||||||
 | 
						__le32 api_index;
 | 
				
			||||||
 | 
						__le32 api_flags;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct iwl_ucode_capa {
 | 
				
			||||||
 | 
						__le32 api_index;
 | 
				
			||||||
 | 
						__le32 api_capa;
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif  /* __iwl_fw_file_h__ */
 | 
					#endif  /* __iwl_fw_file_h__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -92,8 +92,8 @@
 | 
				
			||||||
 * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
 | 
					 * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
 | 
				
			||||||
 * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
 | 
					 * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
 | 
				
			||||||
 *	containing CAM (Continuous Active Mode) indication.
 | 
					 *	containing CAM (Continuous Active Mode) indication.
 | 
				
			||||||
 * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
 | 
					 * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and
 | 
				
			||||||
 *	single bound interface).
 | 
					 *	P2P client interfaces simultaneously if they are in different bindings.
 | 
				
			||||||
 * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
 | 
					 * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
 | 
				
			||||||
 * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
 | 
					 * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
 | 
				
			||||||
 * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
 | 
					 * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients
 | 
				
			||||||
| 
						 | 
					@ -118,7 +118,7 @@ enum iwl_ucode_tlv_flag {
 | 
				
			||||||
	IWL_UCODE_TLV_FLAGS_SCHED_SCAN		= BIT(17),
 | 
						IWL_UCODE_TLV_FLAGS_SCHED_SCAN		= BIT(17),
 | 
				
			||||||
	IWL_UCODE_TLV_FLAGS_STA_KEY_CMD		= BIT(19),
 | 
						IWL_UCODE_TLV_FLAGS_STA_KEY_CMD		= BIT(19),
 | 
				
			||||||
	IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD	= BIT(20),
 | 
						IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD	= BIT(20),
 | 
				
			||||||
	IWL_UCODE_TLV_FLAGS_P2P_PS		= BIT(21),
 | 
						IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM	= BIT(22),
 | 
				
			||||||
	IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT	= BIT(24),
 | 
						IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT	= BIT(24),
 | 
				
			||||||
	IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD	= BIT(26),
 | 
						IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD	= BIT(26),
 | 
				
			||||||
	IWL_UCODE_TLV_FLAGS_BCAST_FILTERING	= BIT(29),
 | 
						IWL_UCODE_TLV_FLAGS_BCAST_FILTERING	= BIT(29),
 | 
				
			||||||
| 
						 | 
					@ -165,11 +165,15 @@ enum iwl_ucode_sec {
 | 
				
			||||||
 * just an offset to the HW address.
 | 
					 * just an offset to the HW address.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define IWL_UCODE_SECTION_MAX 12
 | 
					#define IWL_UCODE_SECTION_MAX 12
 | 
				
			||||||
 | 
					#define IWL_API_ARRAY_SIZE	1
 | 
				
			||||||
 | 
					#define IWL_CAPABILITIES_ARRAY_SIZE	1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct iwl_ucode_capabilities {
 | 
					struct iwl_ucode_capabilities {
 | 
				
			||||||
	u32 max_probe_length;
 | 
						u32 max_probe_length;
 | 
				
			||||||
	u32 standard_phy_calibration_size;
 | 
						u32 standard_phy_calibration_size;
 | 
				
			||||||
	u32 flags;
 | 
						u32 flags;
 | 
				
			||||||
 | 
						u32 api[IWL_API_ARRAY_SIZE];
 | 
				
			||||||
 | 
						u32 capa[IWL_CAPABILITIES_ARRAY_SIZE];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* one for each uCode image (inst/data, init/runtime/wowlan) */
 | 
					/* one for each uCode image (inst/data, init/runtime/wowlan) */
 | 
				
			||||||
| 
						 | 
					@ -288,22 +292,12 @@ struct iwl_fw {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX];
 | 
						struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX];
 | 
				
			||||||
	u32 phy_config;
 | 
						u32 phy_config;
 | 
				
			||||||
 | 
						u8 valid_tx_ant;
 | 
				
			||||||
 | 
						u8 valid_rx_ant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool mvm_fw;
 | 
						bool mvm_fw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
 | 
						struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return (fw->phy_config & FW_PHY_CFG_TX_CHAIN) >>
 | 
					 | 
				
			||||||
		FW_PHY_CFG_TX_CHAIN_POS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline u8 iwl_fw_valid_rx_ant(const struct iwl_fw *fw)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return (fw->phy_config & FW_PHY_CFG_RX_CHAIN) >>
 | 
					 | 
				
			||||||
		FW_PHY_CFG_RX_CHAIN_POS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  /* __iwl_fw_h__ */
 | 
					#endif  /* __iwl_fw_h__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,7 +96,7 @@ enum iwl_disable_11n {
 | 
				
			||||||
 *	use IWL_[DIS,EN]ABLE_HT_* constants
 | 
					 *	use IWL_[DIS,EN]ABLE_HT_* constants
 | 
				
			||||||
 * @amsdu_size_8K: enable 8K amsdu size, default = 0
 | 
					 * @amsdu_size_8K: enable 8K amsdu size, default = 0
 | 
				
			||||||
 * @restart_fw: restart firmware, default = 1
 | 
					 * @restart_fw: restart firmware, default = 1
 | 
				
			||||||
 * @wd_disable: enable stuck queue check, default = 0
 | 
					 * @wd_disable: disable stuck queue check, default = 1
 | 
				
			||||||
 * @bt_coex_active: enable bt coex, default = true
 | 
					 * @bt_coex_active: enable bt coex, default = true
 | 
				
			||||||
 * @led_mode: system default, default = 0
 | 
					 * @led_mode: system default, default = 0
 | 
				
			||||||
 * @power_save: disable power save, default = false
 | 
					 * @power_save: disable power save, default = false
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,6 +84,27 @@ enum wkp_nvm_offsets {
 | 
				
			||||||
	XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
 | 
						XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum family_8000_nvm_offsets {
 | 
				
			||||||
 | 
						/* NVM HW-Section offset (in words) definitions */
 | 
				
			||||||
 | 
						HW_ADDR0_FAMILY_8000 = 0x12,
 | 
				
			||||||
 | 
						HW_ADDR1_FAMILY_8000 = 0x16,
 | 
				
			||||||
 | 
						MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* NVM SW-Section offset (in words) definitions */
 | 
				
			||||||
 | 
						NVM_SW_SECTION_FAMILY_8000 = 0x1C0,
 | 
				
			||||||
 | 
						NVM_VERSION_FAMILY_8000 = 0,
 | 
				
			||||||
 | 
						RADIO_CFG_FAMILY_8000 = 2,
 | 
				
			||||||
 | 
						SKU_FAMILY_8000 = 4,
 | 
				
			||||||
 | 
						N_HW_ADDRS_FAMILY_8000 = 5,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* NVM REGULATORY -Section offset (in words) definitions */
 | 
				
			||||||
 | 
						NVM_CHANNELS_FAMILY_8000 = 0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* NVM calibration section offset (in words) definitions */
 | 
				
			||||||
 | 
						NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8,
 | 
				
			||||||
 | 
						XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* SKU Capabilities (actual values from NVM definition) */
 | 
					/* SKU Capabilities (actual values from NVM definition) */
 | 
				
			||||||
enum nvm_sku_bits {
 | 
					enum nvm_sku_bits {
 | 
				
			||||||
	NVM_SKU_CAP_BAND_24GHZ	= BIT(0),
 | 
						NVM_SKU_CAP_BAND_24GHZ	= BIT(0),
 | 
				
			||||||
| 
						 | 
					@ -92,14 +113,6 @@ enum nvm_sku_bits {
 | 
				
			||||||
	NVM_SKU_CAP_11AC_ENABLE	= BIT(3),
 | 
						NVM_SKU_CAP_11AC_ENABLE	= BIT(3),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* radio config bits (actual values from NVM definition) */
 | 
					 | 
				
			||||||
#define NVM_RF_CFG_DASH_MSK(x)   (x & 0x3)         /* bits 0-1   */
 | 
					 | 
				
			||||||
#define NVM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
 | 
					 | 
				
			||||||
#define NVM_RF_CFG_TYPE_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
 | 
					 | 
				
			||||||
#define NVM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
 | 
					 | 
				
			||||||
#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
 | 
					 | 
				
			||||||
#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * These are the channel numbers in the order that they are stored in the NVM
 | 
					 * These are the channel numbers in the order that they are stored in the NVM
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -112,7 +125,17 @@ static const u8 iwl_nvm_channels[] = {
 | 
				
			||||||
	149, 153, 157, 161, 165
 | 
						149, 153, 157, 161, 165
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const u8 iwl_nvm_channels_family_8000[] = {
 | 
				
			||||||
 | 
						/* 2.4 GHz */
 | 
				
			||||||
 | 
						1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
 | 
				
			||||||
 | 
						/* 5 GHz */
 | 
				
			||||||
 | 
						36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
 | 
				
			||||||
 | 
						96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
 | 
				
			||||||
 | 
						149, 153, 157, 161, 165, 169, 173, 177, 181
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IWL_NUM_CHANNELS	ARRAY_SIZE(iwl_nvm_channels)
 | 
					#define IWL_NUM_CHANNELS	ARRAY_SIZE(iwl_nvm_channels)
 | 
				
			||||||
 | 
					#define IWL_NUM_CHANNELS_FAMILY_8000	ARRAY_SIZE(iwl_nvm_channels_family_8000)
 | 
				
			||||||
#define NUM_2GHZ_CHANNELS	14
 | 
					#define NUM_2GHZ_CHANNELS	14
 | 
				
			||||||
#define FIRST_2GHZ_HT_MINUS	5
 | 
					#define FIRST_2GHZ_HT_MINUS	5
 | 
				
			||||||
#define LAST_2GHZ_HT_PLUS	9
 | 
					#define LAST_2GHZ_HT_PLUS	9
 | 
				
			||||||
| 
						 | 
					@ -179,8 +202,18 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 | 
				
			||||||
	struct ieee80211_channel *channel;
 | 
						struct ieee80211_channel *channel;
 | 
				
			||||||
	u16 ch_flags;
 | 
						u16 ch_flags;
 | 
				
			||||||
	bool is_5ghz;
 | 
						bool is_5ghz;
 | 
				
			||||||
 | 
						int num_of_ch;
 | 
				
			||||||
 | 
						const u8 *nvm_chan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) {
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
 | 
				
			||||||
 | 
							num_of_ch = IWL_NUM_CHANNELS;
 | 
				
			||||||
 | 
							nvm_chan = &iwl_nvm_channels[0];
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
 | 
				
			||||||
 | 
							nvm_chan = &iwl_nvm_channels_family_8000[0];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
 | 
				
			||||||
		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 | 
							ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (ch_idx >= NUM_2GHZ_CHANNELS &&
 | 
							if (ch_idx >= NUM_2GHZ_CHANNELS &&
 | 
				
			||||||
| 
						 | 
					@ -190,7 +223,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 | 
				
			||||||
		if (!(ch_flags & NVM_CHANNEL_VALID)) {
 | 
							if (!(ch_flags & NVM_CHANNEL_VALID)) {
 | 
				
			||||||
			IWL_DEBUG_EEPROM(dev,
 | 
								IWL_DEBUG_EEPROM(dev,
 | 
				
			||||||
					 "Ch. %d Flags %x [%sGHz] - No traffic\n",
 | 
										 "Ch. %d Flags %x [%sGHz] - No traffic\n",
 | 
				
			||||||
					 iwl_nvm_channels[ch_idx],
 | 
										 nvm_chan[ch_idx],
 | 
				
			||||||
					 ch_flags,
 | 
										 ch_flags,
 | 
				
			||||||
					 (ch_idx >= NUM_2GHZ_CHANNELS) ?
 | 
										 (ch_idx >= NUM_2GHZ_CHANNELS) ?
 | 
				
			||||||
					 "5.2" : "2.4");
 | 
										 "5.2" : "2.4");
 | 
				
			||||||
| 
						 | 
					@ -200,7 +233,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 | 
				
			||||||
		channel = &data->channels[n_channels];
 | 
							channel = &data->channels[n_channels];
 | 
				
			||||||
		n_channels++;
 | 
							n_channels++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		channel->hw_value = iwl_nvm_channels[ch_idx];
 | 
							channel->hw_value = nvm_chan[ch_idx];
 | 
				
			||||||
		channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
 | 
							channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
 | 
				
			||||||
				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
 | 
									IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
 | 
				
			||||||
		channel->center_freq =
 | 
							channel->center_freq =
 | 
				
			||||||
| 
						 | 
					@ -211,11 +244,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 | 
				
			||||||
		channel->flags = IEEE80211_CHAN_NO_HT40;
 | 
							channel->flags = IEEE80211_CHAN_NO_HT40;
 | 
				
			||||||
		if (ch_idx < NUM_2GHZ_CHANNELS &&
 | 
							if (ch_idx < NUM_2GHZ_CHANNELS &&
 | 
				
			||||||
		    (ch_flags & NVM_CHANNEL_40MHZ)) {
 | 
							    (ch_flags & NVM_CHANNEL_40MHZ)) {
 | 
				
			||||||
			if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS)
 | 
								if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
 | 
				
			||||||
				channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
 | 
									channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
 | 
				
			||||||
			if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS)
 | 
								if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
 | 
				
			||||||
				channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
 | 
									channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
 | 
				
			||||||
		} else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT &&
 | 
							} else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT &&
 | 
				
			||||||
			   (ch_flags & NVM_CHANNEL_40MHZ)) {
 | 
								   (ch_flags & NVM_CHANNEL_40MHZ)) {
 | 
				
			||||||
			if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
 | 
								if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
 | 
				
			||||||
				channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
 | 
									channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
 | 
				
			||||||
| 
						 | 
					@ -307,14 +340,23 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 | 
					static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 | 
				
			||||||
			    struct iwl_nvm_data *data, const __le16 *nvm_sw,
 | 
								    struct iwl_nvm_data *data,
 | 
				
			||||||
			    bool enable_vht, u8 tx_chains, u8 rx_chains)
 | 
								    const __le16 *ch_section, bool enable_vht,
 | 
				
			||||||
 | 
								    u8 tx_chains, u8 rx_chains)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int n_channels = iwl_init_channel_map(dev, cfg, data,
 | 
						int n_channels;
 | 
				
			||||||
			&nvm_sw[NVM_CHANNELS]);
 | 
					 | 
				
			||||||
	int n_used = 0;
 | 
						int n_used = 0;
 | 
				
			||||||
	struct ieee80211_supported_band *sband;
 | 
						struct ieee80211_supported_band *sband;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 | 
				
			||||||
 | 
							n_channels = iwl_init_channel_map(
 | 
				
			||||||
 | 
									dev, cfg, data,
 | 
				
			||||||
 | 
									&ch_section[NVM_CHANNELS]);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							n_channels = iwl_init_channel_map(
 | 
				
			||||||
 | 
									dev, cfg, data,
 | 
				
			||||||
 | 
									&ch_section[NVM_CHANNELS_FAMILY_8000]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sband = &data->bands[IEEE80211_BAND_2GHZ];
 | 
						sband = &data->bands[IEEE80211_BAND_2GHZ];
 | 
				
			||||||
	sband->band = IEEE80211_BAND_2GHZ;
 | 
						sband->band = IEEE80211_BAND_2GHZ;
 | 
				
			||||||
	sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
 | 
						sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
 | 
				
			||||||
| 
						 | 
					@ -340,67 +382,150 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 | 
				
			||||||
			    n_used, n_channels);
 | 
								    n_used, n_channels);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct iwl_nvm_data *
 | 
					static int iwl_get_sku(const struct iwl_cfg *cfg,
 | 
				
			||||||
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 | 
							       const __le16 *nvm_sw)
 | 
				
			||||||
		   const __le16 *nvm_hw, const __le16 *nvm_sw,
 | 
					 | 
				
			||||||
		   const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct iwl_nvm_data *data;
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 | 
				
			||||||
	u8 hw_addr[ETH_ALEN];
 | 
							return le16_to_cpup(nvm_sw + SKU);
 | 
				
			||||||
	u16 radio_cfg, sku;
 | 
						else
 | 
				
			||||||
 | 
							return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data = kzalloc(sizeof(*data) +
 | 
					static int iwl_get_nvm_version(const struct iwl_cfg *cfg,
 | 
				
			||||||
		       sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
 | 
								       const __le16 *nvm_sw)
 | 
				
			||||||
		       GFP_KERNEL);
 | 
					{
 | 
				
			||||||
	if (!data)
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 | 
				
			||||||
		return NULL;
 | 
							return le16_to_cpup(nvm_sw + NVM_VERSION);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return le32_to_cpup((__le32 *)(nvm_sw +
 | 
				
			||||||
 | 
										       NVM_VERSION_FAMILY_8000));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION);
 | 
					static int iwl_get_radio_cfg(const struct iwl_cfg *cfg,
 | 
				
			||||||
 | 
								     const __le16 *nvm_sw)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 | 
				
			||||||
 | 
							return le16_to_cpup(nvm_sw + RADIO_CFG);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG);
 | 
					#define N_HW_ADDRS_MASK_FAMILY_8000	0xF
 | 
				
			||||||
 | 
					static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg,
 | 
				
			||||||
 | 
								      const __le16 *nvm_sw)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 | 
				
			||||||
 | 
							return le16_to_cpup(nvm_sw + N_HW_ADDRS);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000))
 | 
				
			||||||
 | 
							       & N_HW_ADDRS_MASK_FAMILY_8000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
 | 
				
			||||||
 | 
								      struct iwl_nvm_data *data,
 | 
				
			||||||
 | 
								      u32 radio_cfg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
 | 
				
			||||||
		data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
 | 
							data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
 | 
				
			||||||
		data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
 | 
							data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
 | 
				
			||||||
		data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
 | 
							data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
 | 
				
			||||||
		data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
 | 
							data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
 | 
				
			||||||
	data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
 | 
							return;
 | 
				
			||||||
	data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sku = le16_to_cpup(nvm_sw + SKU);
 | 
					 | 
				
			||||||
	data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
 | 
					 | 
				
			||||||
	data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
 | 
					 | 
				
			||||||
	data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
 | 
					 | 
				
			||||||
	if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
 | 
					 | 
				
			||||||
		data->sku_cap_11n_enable = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* check overrides (some devices have wrong NVM) */
 | 
					 | 
				
			||||||
	if (cfg->valid_tx_ant)
 | 
					 | 
				
			||||||
		data->valid_tx_ant = cfg->valid_tx_ant;
 | 
					 | 
				
			||||||
	if (cfg->valid_rx_ant)
 | 
					 | 
				
			||||||
		data->valid_rx_ant = cfg->valid_rx_ant;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!data->valid_tx_ant || !data->valid_rx_ant) {
 | 
					 | 
				
			||||||
		IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
 | 
					 | 
				
			||||||
			    data->valid_tx_ant, data->valid_rx_ant);
 | 
					 | 
				
			||||||
		kfree(data);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS);
 | 
						/* set the radio configuration for family 8000 */
 | 
				
			||||||
 | 
						data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg);
 | 
				
			||||||
 | 
						data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg);
 | 
				
			||||||
 | 
						data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg);
 | 
				
			||||||
 | 
						data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
 | 
					static void iwl_set_hw_address(const struct iwl_cfg *cfg,
 | 
				
			||||||
	data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
 | 
								       struct iwl_nvm_data *data,
 | 
				
			||||||
 | 
								       const __le16 *nvm_sec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 hw_addr[ETH_ALEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 | 
				
			||||||
 | 
							memcpy(hw_addr, nvm_sec + HW_ADDR, ETH_ALEN);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							memcpy(hw_addr, nvm_sec + MAC_ADDRESS_OVERRIDE_FAMILY_8000,
 | 
				
			||||||
 | 
							       ETH_ALEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The byte order is little endian 16 bit, meaning 214365 */
 | 
						/* The byte order is little endian 16 bit, meaning 214365 */
 | 
				
			||||||
	memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN);
 | 
					 | 
				
			||||||
	data->hw_addr[0] = hw_addr[1];
 | 
						data->hw_addr[0] = hw_addr[1];
 | 
				
			||||||
	data->hw_addr[1] = hw_addr[0];
 | 
						data->hw_addr[1] = hw_addr[0];
 | 
				
			||||||
	data->hw_addr[2] = hw_addr[3];
 | 
						data->hw_addr[2] = hw_addr[3];
 | 
				
			||||||
	data->hw_addr[3] = hw_addr[2];
 | 
						data->hw_addr[3] = hw_addr[2];
 | 
				
			||||||
	data->hw_addr[4] = hw_addr[5];
 | 
						data->hw_addr[4] = hw_addr[5];
 | 
				
			||||||
	data->hw_addr[5] = hw_addr[4];
 | 
						data->hw_addr[5] = hw_addr[4];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE,
 | 
					struct iwl_nvm_data *
 | 
				
			||||||
			tx_chains, rx_chains);
 | 
					iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 | 
				
			||||||
 | 
							   const __le16 *nvm_hw, const __le16 *nvm_sw,
 | 
				
			||||||
 | 
							   const __le16 *nvm_calib, const __le16 *regulatory,
 | 
				
			||||||
 | 
							   const __le16 *mac_override, u8 tx_chains, u8 rx_chains)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct iwl_nvm_data *data;
 | 
				
			||||||
 | 
						u32 sku;
 | 
				
			||||||
 | 
						u32 radio_cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
 | 
				
			||||||
 | 
							data = kzalloc(sizeof(*data) +
 | 
				
			||||||
 | 
								       sizeof(struct ieee80211_channel) *
 | 
				
			||||||
 | 
								       IWL_NUM_CHANNELS,
 | 
				
			||||||
 | 
								       GFP_KERNEL);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							data = kzalloc(sizeof(*data) +
 | 
				
			||||||
 | 
								       sizeof(struct ieee80211_channel) *
 | 
				
			||||||
 | 
								       IWL_NUM_CHANNELS_FAMILY_8000,
 | 
				
			||||||
 | 
								       GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!data)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw);
 | 
				
			||||||
 | 
						iwl_set_radio_cfg(cfg, data, radio_cfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sku = iwl_get_sku(cfg, nvm_sw);
 | 
				
			||||||
 | 
						data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
 | 
				
			||||||
 | 
						data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
 | 
				
			||||||
 | 
						data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
 | 
				
			||||||
 | 
						data->sku_cap_11ac_enable = sku & NVM_SKU_CAP_11AC_ENABLE;
 | 
				
			||||||
 | 
						if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
 | 
				
			||||||
 | 
							data->sku_cap_11n_enable = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
 | 
				
			||||||
 | 
							/* Checking for required sections */
 | 
				
			||||||
 | 
							if (!nvm_calib) {
 | 
				
			||||||
 | 
								IWL_ERR_DEV(dev,
 | 
				
			||||||
 | 
									    "Can't parse empty Calib NVM sections\n");
 | 
				
			||||||
 | 
								kfree(data);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/* in family 8000 Xtal calibration values moved to OTP */
 | 
				
			||||||
 | 
							data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
 | 
				
			||||||
 | 
							data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
 | 
				
			||||||
 | 
							iwl_set_hw_address(cfg, data, nvm_hw);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							iwl_init_sbands(dev, cfg, data, nvm_sw,
 | 
				
			||||||
 | 
									sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
 | 
				
			||||||
 | 
									rx_chains);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* MAC address in family 8000 */
 | 
				
			||||||
 | 
							iwl_set_hw_address(cfg, data, mac_override);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							iwl_init_sbands(dev, cfg, data, regulatory,
 | 
				
			||||||
 | 
									sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,
 | 
				
			||||||
 | 
									rx_chains);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->calib_version = 255;
 | 
						data->calib_version = 255;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,6 +75,7 @@
 | 
				
			||||||
struct iwl_nvm_data *
 | 
					struct iwl_nvm_data *
 | 
				
			||||||
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 | 
					iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 | 
				
			||||||
		   const __le16 *nvm_hw, const __le16 *nvm_sw,
 | 
							   const __le16 *nvm_hw, const __le16 *nvm_sw,
 | 
				
			||||||
		   const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains);
 | 
							   const __le16 *nvm_calib, const __le16 *regulatory,
 | 
				
			||||||
 | 
							   const __le16 *mac_override, u8 tx_chains, u8 rx_chains);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __iwl_nvm_parse_h__ */
 | 
					#endif /* __iwl_nvm_parse_h__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -393,7 +393,7 @@ struct iwl_trans_config {
 | 
				
			||||||
	bool rx_buf_size_8k;
 | 
						bool rx_buf_size_8k;
 | 
				
			||||||
	bool bc_table_dword;
 | 
						bool bc_table_dword;
 | 
				
			||||||
	unsigned int queue_watchdog_timeout;
 | 
						unsigned int queue_watchdog_timeout;
 | 
				
			||||||
	const char **command_names;
 | 
						const char *const *command_names;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct iwl_trans;
 | 
					struct iwl_trans;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -591,7 +591,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 | 
				
			||||||
	    iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
 | 
						    iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
 | 
				
			||||||
	    ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
 | 
						    ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
 | 
				
			||||||
	     (vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
 | 
						     (vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
 | 
				
			||||||
	      mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)))
 | 
						      mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)))
 | 
				
			||||||
		MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
 | 
							MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
 | 
				
			||||||
					 S_IRUSR);
 | 
										 S_IRUSR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -531,6 +531,76 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#undef PRINT_STAT_LE32
 | 
					#undef PRINT_STAT_LE32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
 | 
				
			||||||
 | 
										  char __user *user_buf, size_t count,
 | 
				
			||||||
 | 
										  loff_t *ppos,
 | 
				
			||||||
 | 
										  struct iwl_mvm_frame_stats *stats)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *buff;
 | 
				
			||||||
 | 
						int pos = 0, idx, i;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						size_t bufsz = 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buff = kmalloc(bufsz, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!buff)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_bh(&mvm->drv_stats_lock);
 | 
				
			||||||
 | 
						pos += scnprintf(buff + pos, bufsz - pos,
 | 
				
			||||||
 | 
								 "Legacy/HT/VHT\t:\t%d/%d/%d\n",
 | 
				
			||||||
 | 
								 stats->legacy_frames,
 | 
				
			||||||
 | 
								 stats->ht_frames,
 | 
				
			||||||
 | 
								 stats->vht_frames);
 | 
				
			||||||
 | 
						pos += scnprintf(buff + pos, bufsz - pos, "20/40/80\t:\t%d/%d/%d\n",
 | 
				
			||||||
 | 
								 stats->bw_20_frames,
 | 
				
			||||||
 | 
								 stats->bw_40_frames,
 | 
				
			||||||
 | 
								 stats->bw_80_frames);
 | 
				
			||||||
 | 
						pos += scnprintf(buff + pos, bufsz - pos, "NGI/SGI\t\t:\t%d/%d\n",
 | 
				
			||||||
 | 
								 stats->ngi_frames,
 | 
				
			||||||
 | 
								 stats->sgi_frames);
 | 
				
			||||||
 | 
						pos += scnprintf(buff + pos, bufsz - pos, "SISO/MIMO2\t:\t%d/%d\n",
 | 
				
			||||||
 | 
								 stats->siso_frames,
 | 
				
			||||||
 | 
								 stats->mimo2_frames);
 | 
				
			||||||
 | 
						pos += scnprintf(buff + pos, bufsz - pos, "FAIL/SCSS\t:\t%d/%d\n",
 | 
				
			||||||
 | 
								 stats->fail_frames,
 | 
				
			||||||
 | 
								 stats->success_frames);
 | 
				
			||||||
 | 
						pos += scnprintf(buff + pos, bufsz - pos, "MPDUs agg\t:\t%d\n",
 | 
				
			||||||
 | 
								 stats->agg_frames);
 | 
				
			||||||
 | 
						pos += scnprintf(buff + pos, bufsz - pos, "A-MPDUs\t\t:\t%d\n",
 | 
				
			||||||
 | 
								 stats->ampdu_count);
 | 
				
			||||||
 | 
						pos += scnprintf(buff + pos, bufsz - pos, "Avg MPDUs/A-MPDU:\t%d\n",
 | 
				
			||||||
 | 
								 stats->ampdu_count > 0 ?
 | 
				
			||||||
 | 
								 (stats->agg_frames / stats->ampdu_count) : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pos += scnprintf(buff + pos, bufsz - pos, "Last Rates\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						idx = stats->last_frame_idx - 1;
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) {
 | 
				
			||||||
 | 
							idx = (idx + 1) % ARRAY_SIZE(stats->last_rates);
 | 
				
			||||||
 | 
							if (stats->last_rates[idx] == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							pos += scnprintf(buff + pos, bufsz - pos, "Rate[%d]: ",
 | 
				
			||||||
 | 
									 (int)(ARRAY_SIZE(stats->last_rates) - i));
 | 
				
			||||||
 | 
							pos += rs_pretty_print_rate(buff + pos, stats->last_rates[idx]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock_bh(&mvm->drv_stats_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos);
 | 
				
			||||||
 | 
						kfree(buff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file,
 | 
				
			||||||
 | 
										   char __user *user_buf, size_t count,
 | 
				
			||||||
 | 
										   loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct iwl_mvm *mvm = file->private_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos,
 | 
				
			||||||
 | 
										  &mvm->drv_rx_stats);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
 | 
					static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
 | 
				
			||||||
					  size_t count, loff_t *ppos)
 | 
										  size_t count, loff_t *ppos)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -591,7 +661,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (scan_rx_ant > ANT_ABC)
 | 
						if (scan_rx_ant > ANT_ABC)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw))
 | 
						if (scan_rx_ant & ~mvm->fw->valid_rx_ant)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mvm->scan_rx_ant = scan_rx_ant;
 | 
						mvm->scan_rx_ant = scan_rx_ant;
 | 
				
			||||||
| 
						 | 
					@ -907,6 +977,49 @@ static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
 | 
				
			||||||
#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
 | 
					#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
 | 
				
			||||||
	MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
 | 
						MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t
 | 
				
			||||||
 | 
					iwl_dbgfs_prph_reg_read(struct file *file,
 | 
				
			||||||
 | 
								char __user *user_buf,
 | 
				
			||||||
 | 
								size_t count, loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct iwl_mvm *mvm = file->private_data;
 | 
				
			||||||
 | 
						int pos = 0;
 | 
				
			||||||
 | 
						char buf[32];
 | 
				
			||||||
 | 
						const size_t bufsz = sizeof(buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mvm->dbgfs_prph_reg_addr)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
 | 
				
			||||||
 | 
							mvm->dbgfs_prph_reg_addr,
 | 
				
			||||||
 | 
							iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t
 | 
				
			||||||
 | 
					iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
 | 
				
			||||||
 | 
								 size_t count, loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 args;
 | 
				
			||||||
 | 
						u32 value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
 | 
				
			||||||
 | 
						/* if we only want to set the reg address - nothing more to do */
 | 
				
			||||||
 | 
						if (args == 1)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* otherwise, make sure we have both address and value */
 | 
				
			||||||
 | 
						if (args != 2)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Device wide debugfs entries */
 | 
					/* Device wide debugfs entries */
 | 
				
			||||||
MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
 | 
					MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
 | 
				
			||||||
MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
 | 
					MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
 | 
				
			||||||
| 
						 | 
					@ -916,6 +1029,7 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
 | 
				
			||||||
MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
 | 
					MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
 | 
				
			||||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
 | 
					MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
 | 
				
			||||||
MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
 | 
					MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
 | 
				
			||||||
 | 
					MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
 | 
				
			||||||
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
 | 
					MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
 | 
				
			||||||
MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
 | 
					MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
 | 
				
			||||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
 | 
					MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
 | 
				
			||||||
| 
						 | 
					@ -947,10 +1061,12 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
 | 
				
			||||||
		MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
 | 
							MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
 | 
				
			||||||
				     S_IRUSR | S_IWUSR);
 | 
									     S_IRUSR | S_IWUSR);
 | 
				
			||||||
	MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
 | 
						MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
 | 
				
			||||||
 | 
						MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
 | 
				
			||||||
	MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
 | 
						MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
 | 
				
			||||||
	MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
 | 
						MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
 | 
				
			||||||
	MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
 | 
						MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
 | 
				
			||||||
			     S_IWUSR | S_IRUSR);
 | 
								     S_IWUSR | S_IRUSR);
 | 
				
			||||||
 | 
						MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
 | 
				
			||||||
	MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
 | 
						MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 | 
					#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -257,7 +257,8 @@ enum {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Bit 17-18: (0) SS, (1) SS*2 */
 | 
					/* Bit 17-18: (0) SS, (1) SS*2 */
 | 
				
			||||||
#define RATE_MCS_STBC_POS		17
 | 
					#define RATE_MCS_STBC_POS		17
 | 
				
			||||||
#define RATE_MCS_STBC_MSK		(1 << RATE_MCS_STBC_POS)
 | 
					#define RATE_MCS_HT_STBC_MSK		(3 << RATE_MCS_STBC_POS)
 | 
				
			||||||
 | 
					#define RATE_MCS_VHT_STBC_MSK		(1 << RATE_MCS_STBC_POS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Bit 19: (0) Beamforming is off, (1) Beamforming is on */
 | 
					/* Bit 19: (0) Beamforming is off, (1) Beamforming is on */
 | 
				
			||||||
#define RATE_MCS_BF_POS			19
 | 
					#define RATE_MCS_BF_POS			19
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -306,7 +306,6 @@ struct iwl_phy_cfg_cmd {
 | 
				
			||||||
#define PHY_CFG_RX_CHAIN_B	BIT(13)
 | 
					#define PHY_CFG_RX_CHAIN_B	BIT(13)
 | 
				
			||||||
#define PHY_CFG_RX_CHAIN_C	BIT(14)
 | 
					#define PHY_CFG_RX_CHAIN_C	BIT(14)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NVM_MAX_NUM_SECTIONS	11
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Target of the NVM_ACCESS_CMD */
 | 
					/* Target of the NVM_ACCESS_CMD */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
| 
						 | 
					@ -318,8 +317,11 @@ enum {
 | 
				
			||||||
/* Section types for NVM_ACCESS_CMD */
 | 
					/* Section types for NVM_ACCESS_CMD */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	NVM_SECTION_TYPE_SW = 1,
 | 
						NVM_SECTION_TYPE_SW = 1,
 | 
				
			||||||
 | 
						NVM_SECTION_TYPE_REGULATORY = 3,
 | 
				
			||||||
	NVM_SECTION_TYPE_CALIBRATION = 4,
 | 
						NVM_SECTION_TYPE_CALIBRATION = 4,
 | 
				
			||||||
	NVM_SECTION_TYPE_PRODUCTION = 5,
 | 
						NVM_SECTION_TYPE_PRODUCTION = 5,
 | 
				
			||||||
 | 
						NVM_SECTION_TYPE_MAC_OVERRIDE = 11,
 | 
				
			||||||
 | 
						NVM_MAX_NUM_SECTIONS = 12,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -710,6 +712,7 @@ enum {
 | 
				
			||||||
	TE_V2_NOTIF_HOST_FRAG_END = BIT(5),
 | 
						TE_V2_NOTIF_HOST_FRAG_END = BIT(5),
 | 
				
			||||||
	TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6),
 | 
						TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6),
 | 
				
			||||||
	TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7),
 | 
						TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7),
 | 
				
			||||||
 | 
						T2_V2_START_IMMEDIATELY = BIT(11),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TE_V2_NOTIF_MSK = 0xff,
 | 
						TE_V2_NOTIF_MSK = 0xff,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,7 +130,6 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		palive2 = (void *)pkt->data;
 | 
							palive2 = (void *)pkt->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mvm->support_umac_log = true;
 | 
					 | 
				
			||||||
		mvm->error_event_table =
 | 
							mvm->error_event_table =
 | 
				
			||||||
			le32_to_cpu(palive2->error_event_table_ptr);
 | 
								le32_to_cpu(palive2->error_event_table_ptr);
 | 
				
			||||||
		mvm->log_event_table =
 | 
							mvm->log_event_table =
 | 
				
			||||||
| 
						 | 
					@ -141,6 +140,9 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		alive_data->valid = le16_to_cpu(palive2->status) ==
 | 
							alive_data->valid = le16_to_cpu(palive2->status) ==
 | 
				
			||||||
				    IWL_ALIVE_STATUS_OK;
 | 
									    IWL_ALIVE_STATUS_OK;
 | 
				
			||||||
 | 
							if (mvm->umac_error_event_table)
 | 
				
			||||||
 | 
								mvm->support_umac_log = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		IWL_DEBUG_FW(mvm,
 | 
							IWL_DEBUG_FW(mvm,
 | 
				
			||||||
			     "Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
 | 
								     "Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
 | 
				
			||||||
			     le16_to_cpu(palive2->status), palive2->ver_type,
 | 
								     le16_to_cpu(palive2->status), palive2->ver_type,
 | 
				
			||||||
| 
						 | 
					@ -320,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Send TX valid antennas before triggering calibrations */
 | 
						/* Send TX valid antennas before triggering calibrations */
 | 
				
			||||||
	ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
 | 
						ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -356,8 +358,6 @@ out:
 | 
				
			||||||
					GFP_KERNEL);
 | 
										GFP_KERNEL);
 | 
				
			||||||
		if (!mvm->nvm_data)
 | 
							if (!mvm->nvm_data)
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
		mvm->nvm_data->valid_rx_ant = 1;
 | 
					 | 
				
			||||||
		mvm->nvm_data->valid_tx_ant = 1;
 | 
					 | 
				
			||||||
		mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels;
 | 
							mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels;
 | 
				
			||||||
		mvm->nvm_data->bands[0].n_channels = 1;
 | 
							mvm->nvm_data->bands[0].n_channels = 1;
 | 
				
			||||||
		mvm->nvm_data->bands[0].n_bitrates = 1;
 | 
							mvm->nvm_data->bands[0].n_bitrates = 1;
 | 
				
			||||||
| 
						 | 
					@ -369,8 +369,6 @@ out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define UCODE_CALIB_TIMEOUT	(2*HZ)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int iwl_mvm_up(struct iwl_mvm *mvm)
 | 
					int iwl_mvm_up(struct iwl_mvm *mvm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret, i;
 | 
						int ret, i;
 | 
				
			||||||
| 
						 | 
					@ -422,7 +420,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
 | 
							IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
 | 
						ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -507,7 +505,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
 | 
						ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -952,7 +952,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
 | 
				
			||||||
					     TX_CMD_FLG_TSF);
 | 
										     TX_CMD_FLG_TSF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mvm->mgmt_last_antenna_idx =
 | 
						mvm->mgmt_last_antenna_idx =
 | 
				
			||||||
		iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
 | 
							iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
 | 
				
			||||||
				     mvm->mgmt_last_antenna_idx);
 | 
									     mvm->mgmt_last_antenna_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	beacon_cmd.tx.rate_n_flags =
 | 
						beacon_cmd.tx.rate_n_flags =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,6 +68,7 @@
 | 
				
			||||||
#include <linux/ip.h>
 | 
					#include <linux/ip.h>
 | 
				
			||||||
#include <linux/if_arp.h>
 | 
					#include <linux/if_arp.h>
 | 
				
			||||||
#include <net/mac80211.h>
 | 
					#include <net/mac80211.h>
 | 
				
			||||||
 | 
					#include <net/ieee80211_radiotap.h>
 | 
				
			||||||
#include <net/tcp.h>
 | 
					#include <net/tcp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "iwl-op-mode.h"
 | 
					#include "iwl-op-mode.h"
 | 
				
			||||||
| 
						 | 
					@ -280,6 +281,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hw->queues = mvm->first_agg_queue;
 | 
						hw->queues = mvm->first_agg_queue;
 | 
				
			||||||
	hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
 | 
						hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
 | 
				
			||||||
 | 
						hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
 | 
				
			||||||
 | 
									    IEEE80211_RADIOTAP_MCS_HAVE_STBC;
 | 
				
			||||||
 | 
						hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC;
 | 
				
			||||||
	hw->rate_control_algorithm = "iwl-mvm-rs";
 | 
						hw->rate_control_algorithm = "iwl-mvm-rs";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -1319,7 +1323,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
 | 
				
			||||||
	mvmvif->ap_ibss_active = true;
 | 
						mvmvif->ap_ibss_active = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* power updated needs to be done before quotas */
 | 
						/* power updated needs to be done before quotas */
 | 
				
			||||||
	mvm->bound_vif_cnt++;
 | 
					 | 
				
			||||||
	iwl_mvm_power_update_mac(mvm, vif);
 | 
						iwl_mvm_power_update_mac(mvm, vif);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = iwl_mvm_update_quotas(mvm, vif);
 | 
						ret = iwl_mvm_update_quotas(mvm, vif);
 | 
				
			||||||
| 
						 | 
					@ -1338,7 +1341,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_quota_failed:
 | 
					out_quota_failed:
 | 
				
			||||||
	mvm->bound_vif_cnt--;
 | 
					 | 
				
			||||||
	iwl_mvm_power_update_mac(mvm, vif);
 | 
						iwl_mvm_power_update_mac(mvm, vif);
 | 
				
			||||||
	mvmvif->ap_ibss_active = false;
 | 
						mvmvif->ap_ibss_active = false;
 | 
				
			||||||
	iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
 | 
						iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
 | 
				
			||||||
| 
						 | 
					@ -1375,7 +1377,6 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
 | 
				
			||||||
	iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
 | 
						iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
 | 
				
			||||||
	iwl_mvm_binding_remove_vif(mvm, vif);
 | 
						iwl_mvm_binding_remove_vif(mvm, vif);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mvm->bound_vif_cnt--;
 | 
					 | 
				
			||||||
	iwl_mvm_power_update_mac(mvm, vif);
 | 
						iwl_mvm_power_update_mac(mvm, vif);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iwl_mvm_mac_ctxt_remove(mvm, vif);
 | 
						iwl_mvm_mac_ctxt_remove(mvm, vif);
 | 
				
			||||||
| 
						 | 
					@ -1764,7 +1765,7 @@ out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
 | 
					static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
 | 
				
			||||||
				       struct ieee80211_vif *vif)
 | 
									       struct ieee80211_vif *vif)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 | 
						struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 | 
				
			||||||
| 
						 | 
					@ -1772,6 +1773,8 @@ static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
 | 
				
			||||||
	mutex_lock(&mvm->mutex);
 | 
						mutex_lock(&mvm->mutex);
 | 
				
			||||||
	iwl_mvm_sched_scan_stop(mvm);
 | 
						iwl_mvm_sched_scan_stop(mvm);
 | 
				
			||||||
	mutex_unlock(&mvm->mutex);
 | 
						mutex_unlock(&mvm->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
 | 
					static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
 | 
				
			||||||
| 
						 | 
					@ -2109,7 +2112,6 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
 | 
				
			||||||
	 * Power state must be updated before quotas,
 | 
						 * Power state must be updated before quotas,
 | 
				
			||||||
	 * otherwise fw will complain.
 | 
						 * otherwise fw will complain.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	mvm->bound_vif_cnt++;
 | 
					 | 
				
			||||||
	iwl_mvm_power_update_mac(mvm, vif);
 | 
						iwl_mvm_power_update_mac(mvm, vif);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Setting the quota at this stage is only required for monitor
 | 
						/* Setting the quota at this stage is only required for monitor
 | 
				
			||||||
| 
						 | 
					@ -2127,7 +2129,6 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 out_remove_binding:
 | 
					 out_remove_binding:
 | 
				
			||||||
	iwl_mvm_binding_remove_vif(mvm, vif);
 | 
						iwl_mvm_binding_remove_vif(mvm, vif);
 | 
				
			||||||
	mvm->bound_vif_cnt--;
 | 
					 | 
				
			||||||
	iwl_mvm_power_update_mac(mvm, vif);
 | 
						iwl_mvm_power_update_mac(mvm, vif);
 | 
				
			||||||
 out_unlock:
 | 
					 out_unlock:
 | 
				
			||||||
	mutex_unlock(&mvm->mutex);
 | 
						mutex_unlock(&mvm->mutex);
 | 
				
			||||||
| 
						 | 
					@ -2160,7 +2161,6 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iwl_mvm_binding_remove_vif(mvm, vif);
 | 
						iwl_mvm_binding_remove_vif(mvm, vif);
 | 
				
			||||||
	mvm->bound_vif_cnt--;
 | 
					 | 
				
			||||||
	iwl_mvm_power_update_mac(mvm, vif);
 | 
						iwl_mvm_power_update_mac(mvm, vif);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_unlock:
 | 
					out_unlock:
 | 
				
			||||||
| 
						 | 
					@ -2251,7 +2251,7 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ieee80211_ops iwl_mvm_hw_ops = {
 | 
					const struct ieee80211_ops iwl_mvm_hw_ops = {
 | 
				
			||||||
	.tx = iwl_mvm_mac_tx,
 | 
						.tx = iwl_mvm_mac_tx,
 | 
				
			||||||
	.ampdu_action = iwl_mvm_mac_ampdu_action,
 | 
						.ampdu_action = iwl_mvm_mac_ampdu_action,
 | 
				
			||||||
	.start = iwl_mvm_mac_start,
 | 
						.start = iwl_mvm_mac_start,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,8 +91,7 @@ enum iwl_mvm_tx_fifo {
 | 
				
			||||||
	IWL_MVM_TX_FIFO_MCAST = 5,
 | 
						IWL_MVM_TX_FIFO_MCAST = 5,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct ieee80211_ops iwl_mvm_hw_ops;
 | 
					extern const struct ieee80211_ops iwl_mvm_hw_ops;
 | 
				
			||||||
extern const struct iwl_mvm_power_ops pm_mac_ops;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct iwl_mvm_mod_params - module parameters for iwlmvm
 | 
					 * struct iwl_mvm_mod_params - module parameters for iwlmvm
 | 
				
			||||||
| 
						 | 
					@ -426,6 +425,28 @@ struct iwl_mvm_tt_mgmt {
 | 
				
			||||||
	bool throttle;
 | 
						bool throttle;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct iwl_mvm_frame_stats {
 | 
				
			||||||
 | 
						u32 legacy_frames;
 | 
				
			||||||
 | 
						u32 ht_frames;
 | 
				
			||||||
 | 
						u32 vht_frames;
 | 
				
			||||||
 | 
						u32 bw_20_frames;
 | 
				
			||||||
 | 
						u32 bw_40_frames;
 | 
				
			||||||
 | 
						u32 bw_80_frames;
 | 
				
			||||||
 | 
						u32 bw_160_frames;
 | 
				
			||||||
 | 
						u32 sgi_frames;
 | 
				
			||||||
 | 
						u32 ngi_frames;
 | 
				
			||||||
 | 
						u32 siso_frames;
 | 
				
			||||||
 | 
						u32 mimo2_frames;
 | 
				
			||||||
 | 
						u32 agg_frames;
 | 
				
			||||||
 | 
						u32 ampdu_count;
 | 
				
			||||||
 | 
						u32 success_frames;
 | 
				
			||||||
 | 
						u32 fail_frames;
 | 
				
			||||||
 | 
						u32 last_rates[IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES];
 | 
				
			||||||
 | 
						int last_frame_idx;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct iwl_mvm {
 | 
					struct iwl_mvm {
 | 
				
			||||||
	/* for logger access */
 | 
						/* for logger access */
 | 
				
			||||||
	struct device *dev;
 | 
						struct device *dev;
 | 
				
			||||||
| 
						 | 
					@ -519,6 +540,7 @@ struct iwl_mvm {
 | 
				
			||||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
 | 
					#ifdef CONFIG_IWLWIFI_DEBUGFS
 | 
				
			||||||
	struct dentry *debugfs_dir;
 | 
						struct dentry *debugfs_dir;
 | 
				
			||||||
	u32 dbgfs_sram_offset, dbgfs_sram_len;
 | 
						u32 dbgfs_sram_offset, dbgfs_sram_len;
 | 
				
			||||||
 | 
						u32 dbgfs_prph_reg_addr;
 | 
				
			||||||
	bool disable_power_off;
 | 
						bool disable_power_off;
 | 
				
			||||||
	bool disable_power_off_d3;
 | 
						bool disable_power_off_d3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -526,6 +548,9 @@ struct iwl_mvm {
 | 
				
			||||||
	struct debugfs_blob_wrapper nvm_sw_blob;
 | 
						struct debugfs_blob_wrapper nvm_sw_blob;
 | 
				
			||||||
	struct debugfs_blob_wrapper nvm_calib_blob;
 | 
						struct debugfs_blob_wrapper nvm_calib_blob;
 | 
				
			||||||
	struct debugfs_blob_wrapper nvm_prod_blob;
 | 
						struct debugfs_blob_wrapper nvm_prod_blob;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct iwl_mvm_frame_stats drv_rx_stats;
 | 
				
			||||||
 | 
						spinlock_t drv_stats_lock;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
 | 
						struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
 | 
				
			||||||
| 
						 | 
					@ -587,8 +612,6 @@ struct iwl_mvm {
 | 
				
			||||||
	u8 first_agg_queue;
 | 
						u8 first_agg_queue;
 | 
				
			||||||
	u8 last_agg_queue;
 | 
						u8 last_agg_queue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u8 bound_vif_cnt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Indicate if device power save is allowed */
 | 
						/* Indicate if device power save is allowed */
 | 
				
			||||||
	bool ps_disabled;
 | 
						bool ps_disabled;
 | 
				
			||||||
	/* Indicate if device power management is allowed */
 | 
						/* Indicate if device power management is allowed */
 | 
				
			||||||
| 
						 | 
					@ -812,6 +835,10 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* rate scaling */
 | 
					/* rate scaling */
 | 
				
			||||||
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
 | 
					int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
 | 
				
			||||||
 | 
					void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
 | 
				
			||||||
 | 
									struct iwl_mvm_frame_stats *stats,
 | 
				
			||||||
 | 
									u32 rate, bool agg);
 | 
				
			||||||
 | 
					int rs_pretty_print_rate(char *buf, const u32 rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* power management */
 | 
					/* power management */
 | 
				
			||||||
int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm);
 | 
					int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -228,14 +228,24 @@ static struct iwl_nvm_data *
 | 
				
			||||||
iwl_parse_nvm_sections(struct iwl_mvm *mvm)
 | 
					iwl_parse_nvm_sections(struct iwl_mvm *mvm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct iwl_nvm_section *sections = mvm->nvm_sections;
 | 
						struct iwl_nvm_section *sections = mvm->nvm_sections;
 | 
				
			||||||
	const __le16 *hw, *sw, *calib;
 | 
						const __le16 *hw, *sw, *calib, *regulatory, *mac_override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Checking for required sections */
 | 
						/* Checking for required sections */
 | 
				
			||||||
 | 
						if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
 | 
				
			||||||
		if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
 | 
							if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
 | 
				
			||||||
		    !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
 | 
							    !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
 | 
				
			||||||
			IWL_ERR(mvm, "Can't parse empty NVM sections\n");
 | 
								IWL_ERR(mvm, "Can't parse empty NVM sections\n");
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
 | 
				
			||||||
 | 
							    !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data ||
 | 
				
			||||||
 | 
							    !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) {
 | 
				
			||||||
 | 
								IWL_ERR(mvm,
 | 
				
			||||||
 | 
									"Can't parse empty family 8000 NVM sections\n");
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (WARN_ON(!mvm->cfg))
 | 
						if (WARN_ON(!mvm->cfg))
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
| 
						 | 
					@ -243,9 +253,14 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
 | 
				
			||||||
	hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
 | 
						hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
 | 
				
			||||||
	sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
 | 
						sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
 | 
				
			||||||
	calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
 | 
						calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
 | 
				
			||||||
 | 
						regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data;
 | 
				
			||||||
 | 
						mac_override =
 | 
				
			||||||
 | 
							(const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
 | 
						return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
 | 
				
			||||||
				  iwl_fw_valid_tx_ant(mvm->fw),
 | 
									  regulatory, mac_override,
 | 
				
			||||||
				  iwl_fw_valid_rx_ant(mvm->fw));
 | 
									  mvm->fw->valid_tx_ant,
 | 
				
			||||||
 | 
									  mvm->fw->valid_rx_ant);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_NVM_FILE_LEN	16384
 | 
					#define MAX_NVM_FILE_LEN	16384
 | 
				
			||||||
| 
						 | 
					@ -285,6 +300,8 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
 | 
					#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
 | 
				
			||||||
#define NVM_WORD2_ID(x) (x >> 12)
 | 
					#define NVM_WORD2_ID(x) (x >> 12)
 | 
				
			||||||
 | 
					#define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8))
 | 
				
			||||||
 | 
					#define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
 | 
						IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -335,8 +352,16 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
 | 
							if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
 | 
				
			||||||
 | 
								section_size =
 | 
				
			||||||
 | 
									2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
 | 
				
			||||||
			section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
 | 
								section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								section_size = 2 * NVM_WORD2_LEN_FAMILY_8000(
 | 
				
			||||||
 | 
											le16_to_cpu(file_sec->word2));
 | 
				
			||||||
 | 
								section_id = NVM_WORD1_ID_FAMILY_8000(
 | 
				
			||||||
 | 
											le16_to_cpu(file_sec->word1));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (section_size > IWL_MAX_NVM_SECTION_SIZE) {
 | 
							if (section_size > IWL_MAX_NVM_SECTION_SIZE) {
 | 
				
			||||||
			IWL_ERR(mvm, "ERROR - section too large (%d)\n",
 | 
								IWL_ERR(mvm, "ERROR - section too large (%d)\n",
 | 
				
			||||||
| 
						 | 
					@ -406,6 +431,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret, i, section;
 | 
						int ret, i, section;
 | 
				
			||||||
	u8 *nvm_buffer, *temp;
 | 
						u8 *nvm_buffer, *temp;
 | 
				
			||||||
 | 
						int nvm_to_read[NVM_MAX_NUM_SECTIONS];
 | 
				
			||||||
 | 
						int num_of_sections_to_read;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS))
 | 
						if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -418,12 +445,20 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/* list of NVM sections we are allowed/need to read */
 | 
							/* list of NVM sections we are allowed/need to read */
 | 
				
			||||||
		int nvm_to_read[] = {
 | 
							if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
 | 
				
			||||||
			mvm->cfg->nvm_hw_section_num,
 | 
								nvm_to_read[0] = mvm->cfg->nvm_hw_section_num;
 | 
				
			||||||
			NVM_SECTION_TYPE_SW,
 | 
								nvm_to_read[1] = NVM_SECTION_TYPE_SW;
 | 
				
			||||||
			NVM_SECTION_TYPE_CALIBRATION,
 | 
								nvm_to_read[2] = NVM_SECTION_TYPE_CALIBRATION;
 | 
				
			||||||
			NVM_SECTION_TYPE_PRODUCTION,
 | 
								nvm_to_read[3] = NVM_SECTION_TYPE_PRODUCTION;
 | 
				
			||||||
		};
 | 
								num_of_sections_to_read = 4;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								nvm_to_read[0] = NVM_SECTION_TYPE_SW;
 | 
				
			||||||
 | 
								nvm_to_read[1] = NVM_SECTION_TYPE_CALIBRATION;
 | 
				
			||||||
 | 
								nvm_to_read[2] = NVM_SECTION_TYPE_PRODUCTION;
 | 
				
			||||||
 | 
								nvm_to_read[3] = NVM_SECTION_TYPE_REGULATORY;
 | 
				
			||||||
 | 
								nvm_to_read[4] = NVM_SECTION_TYPE_MAC_OVERRIDE;
 | 
				
			||||||
 | 
								num_of_sections_to_read = 5;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Read From FW NVM */
 | 
							/* Read From FW NVM */
 | 
				
			||||||
		IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
 | 
							IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
 | 
				
			||||||
| 
						 | 
					@ -433,7 +468,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
 | 
				
			||||||
				     GFP_KERNEL);
 | 
									     GFP_KERNEL);
 | 
				
			||||||
		if (!nvm_buffer)
 | 
							if (!nvm_buffer)
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
		for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
 | 
							for (i = 0; i < num_of_sections_to_read; i++) {
 | 
				
			||||||
			section = nvm_to_read[i];
 | 
								section = nvm_to_read[i];
 | 
				
			||||||
			/* we override the constness for initial read */
 | 
								/* we override the constness for initial read */
 | 
				
			||||||
			ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
 | 
								ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,7 +245,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
 | 
				
			||||||
#undef RX_HANDLER
 | 
					#undef RX_HANDLER
 | 
				
			||||||
#define CMD(x) [x] = #x
 | 
					#define CMD(x) [x] = #x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
 | 
					static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
 | 
				
			||||||
	CMD(MVM_ALIVE),
 | 
						CMD(MVM_ALIVE),
 | 
				
			||||||
	CMD(REPLY_ERROR),
 | 
						CMD(REPLY_ERROR),
 | 
				
			||||||
	CMD(INIT_COMPLETE_NOTIF),
 | 
						CMD(INIT_COMPLETE_NOTIF),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue