瀏覽代碼

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem

John W. Linville 14 年之前
父節點
當前提交
204d1641d2
共有 100 個文件被更改,包括 4188 次插入1007 次删除
  1. 128 0
      Documentation/networking/nfc.txt
  2. 0 2
      drivers/Kconfig
  3. 1 0
      drivers/Makefile
  4. 6 0
      drivers/bcma/Kconfig
  5. 1 0
      drivers/bcma/Makefile
  6. 4 0
      drivers/bcma/bcma_private.h
  7. 37 1
      drivers/bcma/driver_pci.c
  8. 14 0
      drivers/bcma/driver_pci_host.c
  9. 2 1
      drivers/net/wireless/ath/carl9170/carl9170.h
  10. 1 1
      drivers/net/wireless/ath/carl9170/fw.c
  11. 18 1
      drivers/net/wireless/ath/carl9170/fwcmd.h
  12. 16 2
      drivers/net/wireless/ath/carl9170/fwdesc.h
  13. 13 2
      drivers/net/wireless/ath/carl9170/hw.h
  14. 6 5
      drivers/net/wireless/ath/carl9170/main.c
  15. 0 6
      drivers/net/wireless/ath/carl9170/phy.c
  16. 3 3
      drivers/net/wireless/ath/carl9170/version.h
  17. 11 14
      drivers/net/wireless/ath/carl9170/wlan.h
  18. 1 0
      drivers/net/wireless/b43/dma.c
  19. 1 1
      drivers/net/wireless/ipw2x00/ipw2100.c
  20. 1 0
      drivers/net/wireless/iwlwifi/Makefile
  21. 0 2
      drivers/net/wireless/iwlwifi/iwl-1000.c
  22. 11 10
      drivers/net/wireless/iwlwifi/iwl-2000.c
  23. 0 4
      drivers/net/wireless/iwlwifi/iwl-5000.c
  24. 0 5
      drivers/net/wireless/iwlwifi/iwl-6000.c
  25. 1 15
      drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
  26. 7 81
      drivers/net/wireless/iwlwifi/iwl-agn-lib.c
  27. 7 12
      drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
  28. 0 90
      drivers/net/wireless/iwlwifi/iwl-agn-tx.c
  29. 5 3
      drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
  30. 25 29
      drivers/net/wireless/iwlwifi/iwl-agn.c
  31. 1 4
      drivers/net/wireless/iwlwifi/iwl-agn.h
  32. 3 19
      drivers/net/wireless/iwlwifi/iwl-core.c
  33. 3 15
      drivers/net/wireless/iwlwifi/iwl-core.h
  34. 20 2
      drivers/net/wireless/iwlwifi/iwl-dev.h
  35. 3 10
      drivers/net/wireless/iwlwifi/iwl-hcmd.c
  36. 2 1
      drivers/net/wireless/iwlwifi/iwl-pci.c
  37. 14 5
      drivers/net/wireless/iwlwifi/iwl-prph.h
  38. 3 44
      drivers/net/wireless/iwlwifi/iwl-rx.c
  39. 132 104
      drivers/net/wireless/iwlwifi/iwl-testmode.h
  40. 423 0
      drivers/net/wireless/iwlwifi/iwl-trans.c
  41. 64 0
      drivers/net/wireless/iwlwifi/iwl-trans.h
  42. 1 138
      drivers/net/wireless/iwlwifi/iwl-tx.c
  43. 2 2
      drivers/net/wireless/mwifiex/sdio.h
  44. 1 0
      drivers/net/wireless/rt2x00/rt2400pci.c
  45. 1 0
      drivers/net/wireless/rt2x00/rt2500pci.c
  46. 1 0
      drivers/net/wireless/rt2x00/rt2500usb.c
  47. 2 0
      drivers/net/wireless/rt2x00/rt2800pci.c
  48. 3 2
      drivers/net/wireless/rt2x00/rt2800usb.c
  49. 1 0
      drivers/net/wireless/rt2x00/rt2x00.h
  50. 3 3
      drivers/net/wireless/rt2x00/rt2x00crypto.c
  51. 2 1
      drivers/net/wireless/rt2x00/rt2x00lib.h
  52. 14 0
      drivers/net/wireless/rt2x00/rt2x00mac.c
  53. 62 46
      drivers/net/wireless/rt2x00/rt2x00queue.c
  54. 2 0
      drivers/net/wireless/rt2x00/rt2x00queue.h
  55. 1 0
      drivers/net/wireless/rt2x00/rt61pci.c
  56. 1 0
      drivers/net/wireless/rt2x00/rt73usb.c
  57. 0 4
      drivers/net/wireless/rtlwifi/pci.c
  58. 0 1
      drivers/net/wireless/rtlwifi/pci.h
  59. 0 2
      drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
  60. 0 9
      drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
  61. 11 8
      drivers/net/wireless/rtlwifi/rtl8192de/hw.c
  62. 1 1
      drivers/net/wireless/rtlwifi/rtl8192de/led.c
  63. 12 18
      drivers/net/wireless/rtlwifi/rtl8192de/phy.c
  64. 8 8
      drivers/net/wireless/rtlwifi/rtl8192de/rf.c
  65. 3 3
      drivers/net/wireless/rtlwifi/rtl8192de/trx.c
  66. 0 3
      drivers/net/wireless/rtlwifi/rtl8192se/hw.c
  67. 1 1
      drivers/net/wireless/wl12xx/Kconfig
  68. 48 1
      drivers/net/wireless/wl12xx/acx.c
  69. 16 0
      drivers/net/wireless/wl12xx/acx.h
  70. 33 0
      drivers/net/wireless/wl12xx/boot.c
  71. 91 3
      drivers/net/wireless/wl12xx/cmd.c
  72. 62 0
      drivers/net/wireless/wl12xx/cmd.h
  73. 55 0
      drivers/net/wireless/wl12xx/conf.h
  74. 136 2
      drivers/net/wireless/wl12xx/debugfs.c
  75. 25 11
      drivers/net/wireless/wl12xx/event.c
  76. 3 0
      drivers/net/wireless/wl12xx/ini.h
  77. 19 0
      drivers/net/wireless/wl12xx/init.c
  78. 4 3
      drivers/net/wireless/wl12xx/io.c
  79. 14 0
      drivers/net/wireless/wl12xx/io.h
  80. 484 106
      drivers/net/wireless/wl12xx/main.c
  81. 7 5
      drivers/net/wireless/wl12xx/ps.c
  82. 34 5
      drivers/net/wireless/wl12xx/rx.c
  83. 12 0
      drivers/net/wireless/wl12xx/rx.h
  84. 30 33
      drivers/net/wireless/wl12xx/scan.c
  85. 7 10
      drivers/net/wireless/wl12xx/scan.h
  86. 28 43
      drivers/net/wireless/wl12xx/sdio.c
  87. 1 14
      drivers/net/wireless/wl12xx/spi.c
  88. 1 1
      drivers/net/wireless/wl12xx/testmode.c
  89. 29 4
      drivers/net/wireless/wl12xx/tx.c
  90. 36 2
      drivers/net/wireless/wl12xx/wl12xx.h
  91. 12 12
      drivers/nfc/Kconfig
  92. 3 0
      drivers/nfc/Makefile
  93. 1632 0
      drivers/nfc/pn533.c
  94. 3 6
      drivers/ssb/pci.c
  95. 126 0
      include/linux/nfc.h
  96. 39 0
      include/linux/nl80211.h
  97. 3 1
      include/linux/socket.h
  98. 1 1
      include/linux/ssb/ssb.h
  99. 26 0
      include/net/cfg80211.h
  100. 47 0
      include/net/mac80211.h

+ 128 - 0
Documentation/networking/nfc.txt

@@ -0,0 +1,128 @@
+Linux NFC subsystem
+===================
+
+The Near Field Communication (NFC) subsystem is required to standardize the
+NFC device drivers development and to create an unified userspace interface.
+
+This document covers the architecture overview, the device driver interface
+description and the userspace interface description.
+
+Architecture overview
+---------------------
+
+The NFC subsystem is responsible for:
+      - NFC adapters management;
+      - Polling for targets;
+      - Low-level data exchange;
+
+The subsystem is divided in some parts. The 'core' is responsible for
+providing the device driver interface. On the other side, it is also
+responsible for providing an interface to control operations and low-level
+data exchange.
+
+The control operations are available to userspace via generic netlink.
+
+The low-level data exchange interface is provided by the new socket family
+PF_NFC. The NFC_SOCKPROTO_RAW performs raw communication with NFC targets.
+
+
+             +--------------------------------------+
+             |              USER SPACE              |
+             +--------------------------------------+
+                 ^                       ^
+                 | low-level             | control
+                 | data exchange         | operations
+                 |                       |
+                 |                       v
+                 |                  +-----------+
+                 | AF_NFC           |  netlink  |
+                 | socket           +-----------+
+                 | raw                   ^
+                 |                       |
+                 v                       v
+             +---------+            +-----------+
+             | rawsock | <--------> |   core    |
+             +---------+            +-----------+
+                                         ^
+                                         |
+                                         v
+                                    +-----------+
+                                    |  driver   |
+                                    +-----------+
+
+Device Driver Interface
+-----------------------
+
+When registering on the NFC subsystem, the device driver must inform the core
+of the set of supported NFC protocols and the set of ops callbacks. The ops
+callbacks that must be implemented are the following:
+
+* start_poll - setup the device to poll for targets
+* stop_poll - stop on progress polling operation
+* activate_target - select and initialize one of the targets found
+* deactivate_target - deselect and deinitialize the selected target
+* data_exchange - send data and receive the response (transceive operation)
+
+Userspace interface
+--------------------
+
+The userspace interface is divided in control operations and low-level data
+exchange operation.
+
+CONTROL OPERATIONS:
+
+Generic netlink is used to implement the interface to the control operations.
+The operations are composed by commands and events, all listed below:
+
+* NFC_CMD_GET_DEVICE - get specific device info or dump the device list
+* NFC_CMD_START_POLL - setup a specific device to polling for targets
+* NFC_CMD_STOP_POLL - stop the polling operation in a specific device
+* NFC_CMD_GET_TARGET - dump the list of targets found by a specific device
+
+* NFC_EVENT_DEVICE_ADDED - reports an NFC device addition
+* NFC_EVENT_DEVICE_REMOVED - reports an NFC device removal
+* NFC_EVENT_TARGETS_FOUND - reports START_POLL results when 1 or more targets
+are found
+
+The user must call START_POLL to poll for NFC targets, passing the desired NFC
+protocols through NFC_ATTR_PROTOCOLS attribute. The device remains in polling
+state until it finds any target. However, the user can stop the polling
+operation by calling STOP_POLL command. In this case, it will be checked if
+the requester of STOP_POLL is the same of START_POLL.
+
+If the polling operation finds one or more targets, the event TARGETS_FOUND is
+sent (including the device id). The user must call GET_TARGET to get the list of
+all targets found by such device. Each reply message has target attributes with
+relevant information such as the supported NFC protocols.
+
+All polling operations requested through one netlink socket are stopped when
+it's closed.
+
+LOW-LEVEL DATA EXCHANGE:
+
+The userspace must use PF_NFC sockets to perform any data communication with
+targets. All NFC sockets use AF_NFC:
+
+struct sockaddr_nfc {
+       sa_family_t sa_family;
+       __u32 dev_idx;
+       __u32 target_idx;
+       __u32 nfc_protocol;
+};
+
+To establish a connection with one target, the user must create an
+NFC_SOCKPROTO_RAW socket and call the 'connect' syscall with the sockaddr_nfc
+struct correctly filled. All information comes from NFC_EVENT_TARGETS_FOUND
+netlink event. As a target can support more than one NFC protocol, the user
+must inform which protocol it wants to use.
+
+Internally, 'connect' will result in an activate_target call to the driver.
+When the socket is closed, the target is deactivated.
+
+The data format exchanged through the sockets is NFC protocol dependent. For
+instance, when communicating with MIFARE tags, the data exchanged are MIFARE
+commands and their responses.
+
+The first received package is the response to the first sent package and so
+on. In order to allow valid "empty" responses, every data received has a NULL
+header of 1 byte.

+ 0 - 2
drivers/Kconfig

@@ -94,8 +94,6 @@ source "drivers/memstick/Kconfig"
 
 
 source "drivers/leds/Kconfig"
 source "drivers/leds/Kconfig"
 
 
-source "drivers/nfc/Kconfig"
-
 source "drivers/accessibility/Kconfig"
 source "drivers/accessibility/Kconfig"
 
 
 source "drivers/infiniband/Kconfig"
 source "drivers/infiniband/Kconfig"

+ 1 - 0
drivers/Makefile

@@ -122,3 +122,4 @@ obj-y				+= ieee802154/
 obj-y				+= clk/
 obj-y				+= clk/
 
 
 obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
 obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
+obj-$(CONFIG_NFC)		+= nfc/

+ 6 - 0
drivers/bcma/Kconfig

@@ -27,6 +27,12 @@ config BCMA_HOST_PCI
 	bool "Support for BCMA on PCI-host bus"
 	bool "Support for BCMA on PCI-host bus"
 	depends on BCMA_HOST_PCI_POSSIBLE
 	depends on BCMA_HOST_PCI_POSSIBLE
 
 
+config BCMA_DRIVER_PCI_HOSTMODE
+	bool "Driver for PCI core working in hostmode"
+	depends on BCMA && MIPS
+	help
+	  PCI core hostmode operation (external PCI bus).
+
 config BCMA_DEBUG
 config BCMA_DEBUG
 	bool "BCMA debugging"
 	bool "BCMA debugging"
 	depends on BCMA
 	depends on BCMA

+ 1 - 0
drivers/bcma/Makefile

@@ -1,6 +1,7 @@
 bcma-y					+= main.o scan.o core.o sprom.o
 bcma-y					+= main.o scan.o core.o sprom.o
 bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
 bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
 bcma-y					+= driver_pci.o
 bcma-y					+= driver_pci.o
+bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)	+= driver_pci_host.o
 bcma-$(CONFIG_BCMA_HOST_PCI)		+= host_pci.o
 bcma-$(CONFIG_BCMA_HOST_PCI)		+= host_pci.o
 obj-$(CONFIG_BCMA)			+= bcma.o
 obj-$(CONFIG_BCMA)			+= bcma.o
 
 

+ 4 - 0
drivers/bcma/bcma_private.h

@@ -28,4 +28,8 @@ extern int __init bcma_host_pci_init(void);
 extern void __exit bcma_host_pci_exit(void);
 extern void __exit bcma_host_pci_exit(void);
 #endif /* CONFIG_BCMA_HOST_PCI */
 #endif /* CONFIG_BCMA_HOST_PCI */
 
 
+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+
 #endif
 #endif

+ 37 - 1
drivers/bcma/driver_pci.c

@@ -157,11 +157,47 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
  * Init.
  * Init.
  **************************************************/
  **************************************************/
 
 
-void bcma_core_pci_init(struct bcma_drv_pci *pc)
+static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
 {
 {
 	bcma_pcicore_serdes_workaround(pc);
 	bcma_pcicore_serdes_workaround(pc);
 }
 }
 
 
+static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
+{
+	struct bcma_bus *bus = pc->core->bus;
+	u16 chipid_top;
+
+	chipid_top = (bus->chipinfo.id & 0xFF00);
+	if (chipid_top != 0x4700 &&
+	    chipid_top != 0x5300)
+		return false;
+
+	if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+		return false;
+
+#if 0
+	/* TODO: on BCMA we use address from EROM instead of magic formula */
+	u32 tmp;
+	return !mips_busprobe32(tmp, (bus->mmio +
+		(pc->core->core_index * BCMA_CORE_SIZE)));
+#endif
+
+	return true;
+}
+
+void bcma_core_pci_init(struct bcma_drv_pci *pc)
+{
+	if (bcma_core_pci_is_in_hostmode(pc)) {
+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+		bcma_core_pci_hostmode_init(pc);
+#else
+		pr_err("Driver compiled without support for hostmode PCI\n");
+#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
+	} else {
+		bcma_core_pci_clientmode_init(pc);
+	}
+}
+
 int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 			  bool enable)
 			  bool enable)
 {
 {

+ 14 - 0
drivers/bcma/driver_pci_host.c

@@ -0,0 +1,14 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Core in hostmode
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+{
+	pr_err("No support for PCI core in hostmode yet\n");
+}

+ 2 - 1
drivers/net/wireless/ath/carl9170/carl9170.h

@@ -67,6 +67,8 @@
 
 
 #define PAYLOAD_MAX	(CARL9170_MAX_CMD_LEN / 4 - 1)
 #define PAYLOAD_MAX	(CARL9170_MAX_CMD_LEN / 4 - 1)
 
 
+static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 3, 2, 1, 0 };
+
 enum carl9170_rf_init_mode {
 enum carl9170_rf_init_mode {
 	CARL9170_RFI_NONE,
 	CARL9170_RFI_NONE,
 	CARL9170_RFI_WARM,
 	CARL9170_RFI_WARM,
@@ -440,7 +442,6 @@ struct ar9170 {
 enum carl9170_ps_off_override_reasons {
 enum carl9170_ps_off_override_reasons {
 	PS_OFF_VIF	= BIT(0),
 	PS_OFF_VIF	= BIT(0),
 	PS_OFF_BCN	= BIT(1),
 	PS_OFF_BCN	= BIT(1),
-	PS_OFF_5GHZ	= BIT(2),
 };
 };
 
 
 struct carl9170_ba_stats {
 struct carl9170_ba_stats {

+ 1 - 1
drivers/net/wireless/ath/carl9170/fw.c

@@ -237,7 +237,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
 		ar->disable_offload = true;
 		ar->disable_offload = true;
 	}
 	}
 
 
-	if (SUPP(CARL9170FW_PSM))
+	if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM))
 		ar->hw->flags |= IEEE80211_HW_SUPPORTS_PS;
 		ar->hw->flags |= IEEE80211_HW_SUPPORTS_PS;
 
 
 	if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE)) {
 	if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE)) {

+ 18 - 1
drivers/net/wireless/ath/carl9170/fwcmd.h

@@ -4,7 +4,7 @@
  * Firmware command interface definitions
  * Firmware command interface definitions
  *
  *
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
+ * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@ enum carl9170_cmd_oids {
 	CARL9170_CMD_BCN_CTRL		= 0x05,
 	CARL9170_CMD_BCN_CTRL		= 0x05,
 	CARL9170_CMD_READ_TSF		= 0x06,
 	CARL9170_CMD_READ_TSF		= 0x06,
 	CARL9170_CMD_RX_FILTER		= 0x07,
 	CARL9170_CMD_RX_FILTER		= 0x07,
+	CARL9170_CMD_WOL		= 0x08,
 
 
 	/* CAM */
 	/* CAM */
 	CARL9170_CMD_EKEY		= 0x10,
 	CARL9170_CMD_EKEY		= 0x10,
@@ -180,6 +181,21 @@ struct carl9170_bcn_ctrl_cmd {
 #define CARL9170_BCN_CTRL_DRAIN	0
 #define CARL9170_BCN_CTRL_DRAIN	0
 #define CARL9170_BCN_CTRL_CAB_TRIGGER	1
 #define CARL9170_BCN_CTRL_CAB_TRIGGER	1
 
 
+struct carl9170_wol_cmd {
+	__le32		flags;
+	u8		mac[6];
+	u8		bssid[6];
+	__le32		null_interval;
+	__le32		free_for_use2;
+	__le32		mask;
+	u8		pattern[32];
+} __packed;
+
+#define CARL9170_WOL_CMD_SIZE		60
+
+#define CARL9170_WOL_DISCONNECT		1
+#define CARL9170_WOL_MAGIC_PKT		2
+
 struct carl9170_cmd_head {
 struct carl9170_cmd_head {
 	union {
 	union {
 		struct {
 		struct {
@@ -203,6 +219,7 @@ struct carl9170_cmd {
 		struct carl9170_write_reg	wreg;
 		struct carl9170_write_reg	wreg;
 		struct carl9170_rf_init		rf_init;
 		struct carl9170_rf_init		rf_init;
 		struct carl9170_psm		psm;
 		struct carl9170_psm		psm;
+		struct carl9170_wol_cmd		wol;
 		struct carl9170_bcn_ctrl_cmd	bcn_ctrl;
 		struct carl9170_bcn_ctrl_cmd	bcn_ctrl;
 		struct carl9170_rx_filter_cmd	rx_filter;
 		struct carl9170_rx_filter_cmd	rx_filter;
 		u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];
 		u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN];

+ 16 - 2
drivers/net/wireless/ath/carl9170/fwdesc.h

@@ -3,7 +3,7 @@
  *
  *
  * Firmware descriptor format
  * Firmware descriptor format
  *
  *
- * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
+ * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * it under the terms of the GNU General Public License as published by
@@ -72,6 +72,9 @@ enum carl9170fw_feature_list {
 	/* Wake up on WLAN */
 	/* Wake up on WLAN */
 	CARL9170FW_WOL,
 	CARL9170FW_WOL,
 
 
+	/* Firmware supports PSM in the 5GHZ Band */
+	CARL9170FW_FIXED_5GHZ_PSM,
+
 	/* KEEP LAST */
 	/* KEEP LAST */
 	__CARL9170FW_FEATURE_NUM
 	__CARL9170FW_FEATURE_NUM
 };
 };
@@ -82,6 +85,7 @@ enum carl9170fw_feature_list {
 #define DBG_MAGIC	"DBG\0"
 #define DBG_MAGIC	"DBG\0"
 #define CHK_MAGIC	"CHK\0"
 #define CHK_MAGIC	"CHK\0"
 #define TXSQ_MAGIC	"TXSQ"
 #define TXSQ_MAGIC	"TXSQ"
+#define WOL_MAGIC	"WOL\0"
 #define LAST_MAGIC	"LAST"
 #define LAST_MAGIC	"LAST"
 
 
 #define CARL9170FW_SET_DAY(d) (((d) - 1) % 31)
 #define CARL9170FW_SET_DAY(d) (((d) - 1) % 31)
@@ -104,7 +108,7 @@ struct carl9170fw_desc_head {
 	(sizeof(struct carl9170fw_desc_head))
 	(sizeof(struct carl9170fw_desc_head))
 
 
 #define CARL9170FW_OTUS_DESC_MIN_VER		6
 #define CARL9170FW_OTUS_DESC_MIN_VER		6
-#define CARL9170FW_OTUS_DESC_CUR_VER		6
+#define CARL9170FW_OTUS_DESC_CUR_VER		7
 struct carl9170fw_otus_desc {
 struct carl9170fw_otus_desc {
 	struct carl9170fw_desc_head head;
 	struct carl9170fw_desc_head head;
 	__le32 feature_set;
 	__le32 feature_set;
@@ -186,6 +190,16 @@ struct carl9170fw_txsq_desc {
 #define CARL9170FW_TXSQ_DESC_SIZE			\
 #define CARL9170FW_TXSQ_DESC_SIZE			\
 	(sizeof(struct carl9170fw_txsq_desc))
 	(sizeof(struct carl9170fw_txsq_desc))
 
 
+#define CARL9170FW_WOL_DESC_MIN_VER			1
+#define CARL9170FW_WOL_DESC_CUR_VER			1
+struct carl9170fw_wol_desc {
+	struct carl9170fw_desc_head head;
+
+	__le32 supported_triggers;	/* CARL9170_WOL_ */
+} __packed;
+#define CARL9170FW_WOL_DESC_SIZE			\
+	(sizeof(struct carl9170fw_wol_desc))
+
 #define CARL9170FW_LAST_DESC_MIN_VER			1
 #define CARL9170FW_LAST_DESC_MIN_VER			1
 #define CARL9170FW_LAST_DESC_CUR_VER			2
 #define CARL9170FW_LAST_DESC_CUR_VER			2
 struct carl9170fw_last_desc {
 struct carl9170fw_last_desc {

+ 13 - 2
drivers/net/wireless/ath/carl9170/hw.h

@@ -4,7 +4,7 @@
  * Register map, hardware-specific definitions
  * Register map, hardware-specific definitions
  *
  *
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
+ * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * it under the terms of the GNU General Public License as published by
@@ -357,7 +357,18 @@
 
 
 #define AR9170_MAC_REG_DMA_WLAN_STATUS		(AR9170_MAC_REG_BASE + 0xd38)
 #define AR9170_MAC_REG_DMA_WLAN_STATUS		(AR9170_MAC_REG_BASE + 0xd38)
 #define	AR9170_MAC_REG_DMA_STATUS		(AR9170_MAC_REG_BASE + 0xd3c)
 #define	AR9170_MAC_REG_DMA_STATUS		(AR9170_MAC_REG_BASE + 0xd3c)
-
+#define AR9170_MAC_REG_DMA_TXQ_LAST_ADDR	(AR9170_MAC_REG_BASE + 0xd40)
+#define	AR9170_MAC_REG_DMA_TXQ0_LAST_ADDR	(AR9170_MAC_REG_BASE + 0xd40)
+#define	AR9170_MAC_REG_DMA_TXQ1_LAST_ADDR	(AR9170_MAC_REG_BASE + 0xd44)
+#define	AR9170_MAC_REG_DMA_TXQ2_LAST_ADDR	(AR9170_MAC_REG_BASE + 0xd48)
+#define	AR9170_MAC_REG_DMA_TXQ3_LAST_ADDR	(AR9170_MAC_REG_BASE + 0xd4c)
+#define	AR9170_MAC_REG_DMA_TXQ4_LAST_ADDR	(AR9170_MAC_REG_BASE + 0xd50)
+#define	AR9170_MAC_REG_DMA_TXQ0Q1_LEN		(AR9170_MAC_REG_BASE + 0xd54)
+#define	AR9170_MAC_REG_DMA_TXQ2Q3_LEN		(AR9170_MAC_REG_BASE + 0xd58)
+#define	AR9170_MAC_REG_DMA_TXQ4_LEN		(AR9170_MAC_REG_BASE + 0xd5c)
+
+#define AR9170_MAC_REG_DMA_TXQX_LAST_ADDR	(AR9170_MAC_REG_BASE + 0xd74)
+#define AR9170_MAC_REG_DMA_TXQX_FAIL_ADDR	(AR9170_MAC_REG_BASE + 0xd78)
 #define	AR9170_MAC_REG_TXRX_MPI			(AR9170_MAC_REG_BASE + 0xd7c)
 #define	AR9170_MAC_REG_TXRX_MPI			(AR9170_MAC_REG_BASE + 0xd7c)
 #define		AR9170_MAC_TXRX_MPI_TX_MPI_MASK		0x0000000f
 #define		AR9170_MAC_TXRX_MPI_TX_MPI_MASK		0x0000000f
 #define		AR9170_MAC_TXRX_MPI_TX_TO_MASK		0x0000fff0
 #define		AR9170_MAC_TXRX_MPI_TX_TO_MASK		0x0000fff0

+ 6 - 5
drivers/net/wireless/ath/carl9170/main.c

@@ -345,11 +345,11 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
 	carl9170_zap_queues(ar);
 	carl9170_zap_queues(ar);
 
 
 	/* reset QoS defaults */
 	/* reset QoS defaults */
-	CARL9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023,  0); /* BEST EFFORT */
-	CARL9170_FILL_QUEUE(ar->edcf[1], 2, 7,    15, 94); /* VIDEO */
-	CARL9170_FILL_QUEUE(ar->edcf[2], 2, 3,     7, 47); /* VOICE */
-	CARL9170_FILL_QUEUE(ar->edcf[3], 7, 15, 1023,  0); /* BACKGROUND */
-	CARL9170_FILL_QUEUE(ar->edcf[4], 2, 3,     7,  0); /* SPECIAL */
+	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_VO], 2, 3,     7, 47);
+	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_VI], 2, 7,    15, 94);
+	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_BE], 3, 15, 1023,  0);
+	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_BK], 7, 15, 1023,  0);
+	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_SPECIAL], 2, 3, 7, 0);
 
 
 	ar->current_factor = ar->current_density = -1;
 	ar->current_factor = ar->current_density = -1;
 	/* "The first key is unique." */
 	/* "The first key is unique." */
@@ -1577,6 +1577,7 @@ void *carl9170_alloc(size_t priv_size)
 		     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		     IEEE80211_HW_SUPPORTS_PS |
 		     IEEE80211_HW_SUPPORTS_PS |
 		     IEEE80211_HW_PS_NULLFUNC_STACK |
 		     IEEE80211_HW_PS_NULLFUNC_STACK |
+		     IEEE80211_HW_NEED_DTIM_PERIOD |
 		     IEEE80211_HW_SIGNAL_DBM;
 		     IEEE80211_HW_SIGNAL_DBM;
 
 
 	if (!modparam_noht) {
 	if (!modparam_noht) {

+ 0 - 6
drivers/net/wireless/ath/carl9170/phy.c

@@ -1783,12 +1783,6 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
 		}
 		}
 	}
 	}
 
 
-	/* FIXME: PSM does not work in 5GHz Band */
-	if (channel->band == IEEE80211_BAND_5GHZ)
-		ar->ps.off_override |= PS_OFF_5GHZ;
-	else
-		ar->ps.off_override &= ~PS_OFF_5GHZ;
-
 	ar->channel = channel;
 	ar->channel = channel;
 	ar->ht_settings = new_ht;
 	ar->ht_settings = new_ht;
 	return 0;
 	return 0;

+ 3 - 3
drivers/net/wireless/ath/carl9170/version.h

@@ -1,7 +1,7 @@
 #ifndef __CARL9170_SHARED_VERSION_H
 #ifndef __CARL9170_SHARED_VERSION_H
 #define __CARL9170_SHARED_VERSION_H
 #define __CARL9170_SHARED_VERSION_H
 #define CARL9170FW_VERSION_YEAR 11
 #define CARL9170FW_VERSION_YEAR 11
-#define CARL9170FW_VERSION_MONTH 1
-#define CARL9170FW_VERSION_DAY 22
-#define CARL9170FW_VERSION_GIT "1.9.2"
+#define CARL9170FW_VERSION_MONTH 6
+#define CARL9170FW_VERSION_DAY 30
+#define CARL9170FW_VERSION_GIT "1.9.4"
 #endif /* __CARL9170_SHARED_VERSION_H */
 #endif /* __CARL9170_SHARED_VERSION_H */

+ 11 - 14
drivers/net/wireless/ath/carl9170/wlan.h

@@ -4,7 +4,7 @@
  * RX/TX meta descriptor format
  * RX/TX meta descriptor format
  *
  *
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
+ * Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * it under the terms of the GNU General Public License as published by
@@ -278,7 +278,7 @@ struct ar9170_tx_frame {
 struct carl9170_tx_superframe {
 struct carl9170_tx_superframe {
 	struct carl9170_tx_superdesc s;
 	struct carl9170_tx_superdesc s;
 	struct ar9170_tx_frame f;
 	struct ar9170_tx_frame f;
-} __packed;
+} __packed __aligned(4);
 
 
 #endif /* __CARL9170FW__ */
 #endif /* __CARL9170FW__ */
 
 
@@ -328,7 +328,7 @@ struct _carl9170_tx_superframe {
 	struct _carl9170_tx_superdesc s;
 	struct _carl9170_tx_superdesc s;
 	struct _ar9170_tx_hwdesc f;
 	struct _ar9170_tx_hwdesc f;
 	u8 frame_data[0];
 	u8 frame_data[0];
-} __packed;
+} __packed __aligned(4);
 
 
 #define	CARL9170_TX_SUPERDESC_LEN		24
 #define	CARL9170_TX_SUPERDESC_LEN		24
 #define	AR9170_TX_HWDESC_LEN			8
 #define	AR9170_TX_HWDESC_LEN			8
@@ -404,16 +404,6 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
 	       (t->DAidx & 0xc0) >> 6;
 	       (t->DAidx & 0xc0) >> 6;
 }
 }
 
 
-enum ar9170_txq {
-	AR9170_TXQ_BE,
-
-	AR9170_TXQ_VI,
-	AR9170_TXQ_VO,
-	AR9170_TXQ_BK,
-
-	__AR9170_NUM_TXQ,
-};
-
 /*
 /*
  * This is an workaround for several undocumented bugs.
  * This is an workaround for several undocumented bugs.
  * Don't mess with the QoS/AC <-> HW Queue map, if you don't
  * Don't mess with the QoS/AC <-> HW Queue map, if you don't
@@ -431,7 +421,14 @@ enum ar9170_txq {
  * result, this makes the device pretty much useless
  * result, this makes the device pretty much useless
  * for any serious 802.11n setup.
  * for any serious 802.11n setup.
  */
  */
-static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 2, 1, 0, 3 };
+enum ar9170_txq {
+	AR9170_TXQ_BK = 0,	/* TXQ0 */
+	AR9170_TXQ_BE,		/* TXQ1	*/
+	AR9170_TXQ_VI,		/* TXQ2	*/
+	AR9170_TXQ_VO,		/* TXQ3 */
+
+	__AR9170_NUM_TXQ,
+};
 
 
 #define	AR9170_TXQ_DEPTH			32
 #define	AR9170_TXQ_DEPTH			32
 
 

+ 1 - 0
drivers/net/wireless/b43/dma.c

@@ -1600,6 +1600,7 @@ void b43_dma_rx(struct b43_dmaring *ring)
 		dma_rx(ring, &slot);
 		dma_rx(ring, &slot);
 		update_max_used_slots(ring, ++used_slots);
 		update_max_used_slots(ring, ++used_slots);
 	}
 	}
+	wmb();
 	ops->set_current_rxslot(ring, slot);
 	ops->set_current_rxslot(ring, slot);
 	ring->current_slot = slot;
 	ring->current_slot = slot;
 }
 }

+ 1 - 1
drivers/net/wireless/ipw2x00/ipw2100.c

@@ -287,7 +287,7 @@ static const char *command_types[] = {
 	"unused",		/* HOST_INTERRUPT_COALESCING */
 	"unused",		/* HOST_INTERRUPT_COALESCING */
 	"undefined",
 	"undefined",
 	"CARD_DISABLE_PHY_OFF",
 	"CARD_DISABLE_PHY_OFF",
-	"MSDU_TX_RATES" "undefined",
+	"MSDU_TX_RATES",
 	"undefined",
 	"undefined",
 	"SET_STATION_STAT_BITS",
 	"SET_STATION_STAT_BITS",
 	"CLEAR_STATIONS_STAT_BITS",
 	"CLEAR_STATIONS_STAT_BITS",

+ 1 - 0
drivers/net/wireless/iwlwifi/Makefile

@@ -14,6 +14,7 @@ iwlagn-objs             += iwl-6000.o
 iwlagn-objs             += iwl-1000.o
 iwlagn-objs             += iwl-1000.o
 iwlagn-objs             += iwl-2000.o
 iwlagn-objs             += iwl-2000.o
 iwlagn-objs             += iwl-pci.o
 iwlagn-objs             += iwl-pci.o
+iwlagn-objs             += iwl-trans.o
 
 
 iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
 iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o

+ 0 - 2
drivers/net/wireless/iwlwifi/iwl-1000.c

@@ -138,7 +138,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 
 
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 					BIT(IEEE80211_BAND_5GHZ);
-	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
 
 
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	if (priv->cfg->rx_with_siso_diversity)
 	if (priv->cfg->rx_with_siso_diversity)
@@ -197,7 +196,6 @@ static struct iwl_lib_ops iwl1000_lib = {
 
 
 static const struct iwl_ops iwl1000_ops = {
 static const struct iwl_ops iwl1000_ops = {
 	.lib = &iwl1000_lib,
 	.lib = &iwl1000_lib,
-	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 };
 };
 
 

+ 11 - 10
drivers/net/wireless/iwlwifi/iwl-2000.c

@@ -50,11 +50,13 @@
 #define IWL2030_UCODE_API_MAX 5
 #define IWL2030_UCODE_API_MAX 5
 #define IWL2000_UCODE_API_MAX 5
 #define IWL2000_UCODE_API_MAX 5
 #define IWL105_UCODE_API_MAX 5
 #define IWL105_UCODE_API_MAX 5
+#define IWL135_UCODE_API_MAX 5
 
 
 /* Lowest firmware API version supported */
 /* Lowest firmware API version supported */
 #define IWL2030_UCODE_API_MIN 5
 #define IWL2030_UCODE_API_MIN 5
 #define IWL2000_UCODE_API_MIN 5
 #define IWL2000_UCODE_API_MIN 5
 #define IWL105_UCODE_API_MIN 5
 #define IWL105_UCODE_API_MIN 5
+#define IWL135_UCODE_API_MIN 5
 
 
 #define IWL2030_FW_PRE "iwlwifi-2030-"
 #define IWL2030_FW_PRE "iwlwifi-2030-"
 #define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode"
 #define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode"
@@ -65,6 +67,9 @@
 #define IWL105_FW_PRE "iwlwifi-105-"
 #define IWL105_FW_PRE "iwlwifi-105-"
 #define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
 #define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
 
 
+#define IWL135_FW_PRE "iwlwifi-135-"
+#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE #api ".ucode"
+
 static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
 static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
 {
 {
 	/* want Celsius */
 	/* want Celsius */
@@ -131,7 +136,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
 
 
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 					BIT(IEEE80211_BAND_5GHZ);
-	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
 
 
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	if (priv->cfg->rx_with_siso_diversity)
 	if (priv->cfg->rx_with_siso_diversity)
@@ -193,25 +197,21 @@ static struct iwl_lib_ops iwl2000_lib = {
 
 
 static const struct iwl_ops iwl2000_ops = {
 static const struct iwl_ops iwl2000_ops = {
 	.lib = &iwl2000_lib,
 	.lib = &iwl2000_lib,
-	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 };
 };
 
 
 static const struct iwl_ops iwl2030_ops = {
 static const struct iwl_ops iwl2030_ops = {
 	.lib = &iwl2000_lib,
 	.lib = &iwl2000_lib,
-	.hcmd = &iwlagn_bt_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 };
 };
 
 
 static const struct iwl_ops iwl105_ops = {
 static const struct iwl_ops iwl105_ops = {
 	.lib = &iwl2000_lib,
 	.lib = &iwl2000_lib,
-	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 };
 };
 
 
 static const struct iwl_ops iwl135_ops = {
 static const struct iwl_ops iwl135_ops = {
 	.lib = &iwl2000_lib,
 	.lib = &iwl2000_lib,
-	.hcmd = &iwlagn_bt_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 };
 };
 
 
@@ -344,9 +344,9 @@ struct iwl_cfg iwl105_bgn_cfg = {
 };
 };
 
 
 #define IWL_DEVICE_135						\
 #define IWL_DEVICE_135						\
-	.fw_name_pre = IWL105_FW_PRE,				\
-	.ucode_api_max = IWL105_UCODE_API_MAX,			\
-	.ucode_api_min = IWL105_UCODE_API_MIN,			\
+	.fw_name_pre = IWL135_FW_PRE,				\
+	.ucode_api_max = IWL135_UCODE_API_MAX,			\
+	.ucode_api_min = IWL135_UCODE_API_MIN,			\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_ver = EEPROM_2000_EEPROM_VERSION,		\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
 	.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,	\
 	.ops = &iwl135_ops,					\
 	.ops = &iwl135_ops,					\
@@ -359,12 +359,12 @@ struct iwl_cfg iwl105_bgn_cfg = {
 	.rx_with_siso_diversity = true				\
 	.rx_with_siso_diversity = true				\
 
 
 struct iwl_cfg iwl135_bg_cfg = {
 struct iwl_cfg iwl135_bg_cfg = {
-	.name = "105 Series 1x1 BG/BT",
+	.name = "135 Series 1x1 BG/BT",
 	IWL_DEVICE_135,
 	IWL_DEVICE_135,
 };
 };
 
 
 struct iwl_cfg iwl135_bgn_cfg = {
 struct iwl_cfg iwl135_bgn_cfg = {
-	.name = "105 Series 1x1 BGN/BT",
+	.name = "135 Series 1x1 BGN/BT",
 	IWL_DEVICE_135,
 	IWL_DEVICE_135,
 	.ht_params = &iwl2000_ht_params,
 	.ht_params = &iwl2000_ht_params,
 };
 };
@@ -372,3 +372,4 @@ struct iwl_cfg iwl135_bgn_cfg = {
 MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_MAX));

+ 0 - 4
drivers/net/wireless/iwlwifi/iwl-5000.c

@@ -169,7 +169,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 
 
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 					BIT(IEEE80211_BAND_5GHZ);
-	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
 
 
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
 	priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
@@ -214,7 +213,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
 
 
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 					BIT(IEEE80211_BAND_5GHZ);
-	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
 
 
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
 	priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
@@ -379,13 +377,11 @@ static struct iwl_lib_ops iwl5150_lib = {
 
 
 static const struct iwl_ops iwl5000_ops = {
 static const struct iwl_ops iwl5000_ops = {
 	.lib = &iwl5000_lib,
 	.lib = &iwl5000_lib,
-	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 };
 };
 
 
 static const struct iwl_ops iwl5150_ops = {
 static const struct iwl_ops iwl5150_ops = {
 	.lib = &iwl5150_lib,
 	.lib = &iwl5150_lib,
-	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 };
 };
 
 

+ 0 - 5
drivers/net/wireless/iwlwifi/iwl-6000.c

@@ -157,7 +157,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
 
 
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 	priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
 					BIT(IEEE80211_BAND_5GHZ);
 					BIT(IEEE80211_BAND_5GHZ);
-	priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
 
 
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
 	if (priv->cfg->rx_with_siso_diversity)
 	if (priv->cfg->rx_with_siso_diversity)
@@ -328,27 +327,23 @@ static struct iwl_nic_ops iwl6150_nic_ops = {
 
 
 static const struct iwl_ops iwl6000_ops = {
 static const struct iwl_ops iwl6000_ops = {
 	.lib = &iwl6000_lib,
 	.lib = &iwl6000_lib,
-	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 };
 };
 
 
 static const struct iwl_ops iwl6050_ops = {
 static const struct iwl_ops iwl6050_ops = {
 	.lib = &iwl6000_lib,
 	.lib = &iwl6000_lib,
-	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 	.nic = &iwl6050_nic_ops,
 	.nic = &iwl6050_nic_ops,
 };
 };
 
 
 static const struct iwl_ops iwl6150_ops = {
 static const struct iwl_ops iwl6150_ops = {
 	.lib = &iwl6000_lib,
 	.lib = &iwl6000_lib,
-	.hcmd = &iwlagn_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 	.nic = &iwl6150_nic_ops,
 	.nic = &iwl6150_nic_ops,
 };
 };
 
 
 static const struct iwl_ops iwl6030_ops = {
 static const struct iwl_ops iwl6030_ops = {
 	.lib = &iwl6030_lib,
 	.lib = &iwl6030_lib,
-	.hcmd = &iwlagn_bt_hcmd,
 	.utils = &iwlagn_hcmd_utils,
 	.utils = &iwlagn_hcmd_utils,
 };
 };
 
 

+ 1 - 15
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c

@@ -205,7 +205,7 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
 	return max_rssi - agc - IWLAGN_RSSI_OFFSET;
 	return max_rssi - agc - IWLAGN_RSSI_OFFSET;
 }
 }
 
 
-static int iwlagn_set_pan_params(struct iwl_priv *priv)
+int iwlagn_set_pan_params(struct iwl_priv *priv)
 {
 {
 	struct iwl_wipan_params_cmd cmd;
 	struct iwl_wipan_params_cmd cmd;
 	struct iwl_rxon_context *ctx_bss, *ctx_pan;
 	struct iwl_rxon_context *ctx_bss, *ctx_pan;
@@ -297,20 +297,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
 	return ret;
 	return ret;
 }
 }
 
 
-struct iwl_hcmd_ops iwlagn_hcmd = {
-	.set_rxon_chain = iwlagn_set_rxon_chain,
-	.set_tx_ant = iwlagn_send_tx_ant_config,
-	.send_bt_config = iwl_send_bt_config,
-	.set_pan_params = iwlagn_set_pan_params,
-};
-
-struct iwl_hcmd_ops iwlagn_bt_hcmd = {
-	.set_rxon_chain = iwlagn_set_rxon_chain,
-	.set_tx_ant = iwlagn_send_tx_ant_config,
-	.send_bt_config = iwlagn_send_advance_bt_config,
-	.set_pan_params = iwlagn_set_pan_params,
-};
-
 struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
 struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
 	.build_addsta_hcmd = iwlagn_build_addsta_hcmd,
 	.build_addsta_hcmd = iwlagn_build_addsta_hcmd,
 	.gain_computation = iwlagn_gain_computation,
 	.gain_computation = iwlagn_gain_computation,

+ 7 - 81
drivers/net/wireless/iwlwifi/iwl-agn-lib.c

@@ -628,38 +628,6 @@ struct iwl_mod_params iwlagn_mod_params = {
 	/* the rest are 0 by default */
 	/* the rest are 0 by default */
 };
 };
 
 
-void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-	unsigned long flags;
-	int i;
-	spin_lock_irqsave(&rxq->lock, flags);
-	INIT_LIST_HEAD(&rxq->rx_free);
-	INIT_LIST_HEAD(&rxq->rx_used);
-	/* Fill the rx_used queue with _all_ of the Rx buffers */
-	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
-		/* In the reset function, these buffers may have been allocated
-		 * to an SKB, so we need to unmap and free potential storage */
-		if (rxq->pool[i].page != NULL) {
-			dma_unmap_page(priv->bus.dev, rxq->pool[i].page_dma,
-				PAGE_SIZE << priv->hw_params.rx_page_order,
-				DMA_FROM_DEVICE);
-			__iwl_free_pages(priv, rxq->pool[i].page);
-			rxq->pool[i].page = NULL;
-		}
-		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-	}
-
-	for (i = 0; i < RX_QUEUE_SIZE; i++)
-		rxq->queue[i] = NULL;
-
-	/* Set us so that we have processed and used all buffers, but have
-	 * not restocked the Rx queue with fresh buffers */
-	rxq->read = rxq->write = 0;
-	rxq->write_actual = 0;
-	rxq->free_count = 0;
-	spin_unlock_irqrestore(&rxq->lock, flags);
-}
-
 int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 {
 {
 	u32 rb_size;
 	u32 rb_size;
@@ -731,7 +699,6 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 	struct iwl_rx_queue *rxq = &priv->rxq;
 	struct iwl_rx_queue *rxq = &priv->rxq;
-	int ret;
 
 
 	/* nic_init */
 	/* nic_init */
 	spin_lock_irqsave(&priv->lock, flags);
 	spin_lock_irqsave(&priv->lock, flags);
@@ -747,14 +714,7 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv)
 	priv->cfg->ops->lib->apm_ops.config(priv);
 	priv->cfg->ops->lib->apm_ops.config(priv);
 
 
 	/* Allocate the RX queue, or reset if it is already allocated */
 	/* Allocate the RX queue, or reset if it is already allocated */
-	if (!rxq->bd) {
-		ret = iwl_rx_queue_alloc(priv);
-		if (ret) {
-			IWL_ERR(priv, "Unable to initialize Rx queue\n");
-			return -ENOMEM;
-		}
-	} else
-		iwlagn_rx_queue_reset(priv, rxq);
+	priv->trans.ops->rx_init(priv);
 
 
 	iwlagn_rx_replenish(priv);
 	iwlagn_rx_replenish(priv);
 
 
@@ -768,12 +728,8 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv)
 	spin_unlock_irqrestore(&priv->lock, flags);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 
 	/* Allocate or reset and init all Tx and Command queues */
 	/* Allocate or reset and init all Tx and Command queues */
-	if (!priv->txq) {
-		ret = iwlagn_txq_ctx_alloc(priv);
-		if (ret)
-			return ret;
-	} else
-		iwlagn_txq_ctx_reset(priv);
+	if (priv->trans.ops->tx_init(priv))
+		return -ENOMEM;
 
 
 	if (priv->cfg->base_params->shadow_reg_enable) {
 	if (priv->cfg->base_params->shadow_reg_enable) {
 		/* enable shadow regs in HW */
 		/* enable shadow regs in HW */
@@ -949,33 +905,6 @@ void iwlagn_rx_replenish_now(struct iwl_priv *priv)
 	iwlagn_rx_queue_restock(priv);
 	iwlagn_rx_queue_restock(priv);
 }
 }
 
 
-/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have its SKB set to NULL
- * This free routine walks the list of POOL entries and if SKB is set to
- * non NULL it is unmapped and freed
- */
-void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-	int i;
-	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
-		if (rxq->pool[i].page != NULL) {
-			dma_unmap_page(priv->bus.dev, rxq->pool[i].page_dma,
-				PAGE_SIZE << priv->hw_params.rx_page_order,
-				DMA_FROM_DEVICE);
-			__iwl_free_pages(priv, rxq->pool[i].page);
-			rxq->pool[i].page = NULL;
-		}
-	}
-
-	dma_free_coherent(priv->bus.dev, 4 * RX_QUEUE_SIZE,
-			  rxq->bd, rxq->bd_dma);
-	dma_free_coherent(priv->bus.dev,
-			  sizeof(struct iwl_rb_status),
-			  rxq->rb_stts, rxq->rb_stts_dma);
-	rxq->bd = NULL;
-	rxq->rb_stts  = NULL;
-}
-
 int iwlagn_rxq_stop(struct iwl_priv *priv)
 int iwlagn_rxq_stop(struct iwl_priv *priv)
 {
 {
 
 
@@ -1437,17 +1366,14 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 	/* set scan bit here for PAN params */
 	/* set scan bit here for PAN params */
 	set_bit(STATUS_SCAN_HW, &priv->status);
 	set_bit(STATUS_SCAN_HW, &priv->status);
 
 
-	if (priv->cfg->ops->hcmd->set_pan_params) {
-		ret = priv->cfg->ops->hcmd->set_pan_params(priv);
-		if (ret)
-			return ret;
-	}
+	ret = iwlagn_set_pan_params(priv);
+	if (ret)
+		return ret;
 
 
 	ret = iwl_send_cmd_sync(priv, &cmd);
 	ret = iwl_send_cmd_sync(priv, &cmd);
 	if (ret) {
 	if (ret) {
 		clear_bit(STATUS_SCAN_HW, &priv->status);
 		clear_bit(STATUS_SCAN_HW, &priv->status);
-		if (priv->cfg->ops->hcmd->set_pan_params)
-			priv->cfg->ops->hcmd->set_pan_params(priv);
+		iwlagn_set_pan_params(priv);
 	}
 	}
 
 
 	return ret;
 	return ret;

+ 7 - 12
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c

@@ -436,11 +436,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	if (priv->cfg->ops->hcmd->set_pan_params) {
-		ret = priv->cfg->ops->hcmd->set_pan_params(priv);
-		if (ret)
-			return ret;
-	}
+	ret = iwlagn_set_pan_params(priv);
+	if (ret)
+		return ret;
 
 
 	if (new_assoc)
 	if (new_assoc)
 		return iwlagn_rxon_connect(priv, ctx);
 		return iwlagn_rxon_connect(priv, ctx);
@@ -483,9 +481,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
 		 * set up the SM PS mode to OFF if an HT channel is
 		 * set up the SM PS mode to OFF if an HT channel is
 		 * configured.
 		 * configured.
 		 */
 		 */
-		if (priv->cfg->ops->hcmd->set_rxon_chain)
-			for_each_context(priv, ctx)
-				priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+		for_each_context(priv, ctx)
+			iwlagn_set_rxon_chain(priv, ctx);
 	}
 	}
 
 
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
@@ -741,8 +738,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
 		iwl_set_rxon_ht(priv, &priv->current_ht_config);
 		iwl_set_rxon_ht(priv, &priv->current_ht_config);
 	}
 	}
 
 
-	if (priv->cfg->ops->hcmd->set_rxon_chain)
-		priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+	iwlagn_set_rxon_chain(priv, ctx);
 
 
 	if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
 	if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
 		ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
 		ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
@@ -821,6 +817,5 @@ void iwlagn_post_scan(struct iwl_priv *priv)
 		if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
 		if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
 			iwlagn_commit_rxon(priv, ctx);
 			iwlagn_commit_rxon(priv, ctx);
 
 
-	if (priv->cfg->ops->hcmd->set_pan_params)
-		priv->cfg->ops->hcmd->set_pan_params(priv);
+	iwlagn_set_pan_params(priv);
 }
 }

+ 0 - 90
drivers/net/wireless/iwlwifi/iwl-agn-tx.c

@@ -877,96 +877,6 @@ void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
 	iwl_free_txq_mem(priv);
 	iwl_free_txq_mem(priv);
 }
 }
 
 
-/**
- * iwlagn_txq_ctx_alloc - allocate TX queue context
- * Allocate all Tx DMA structures and initialize them
- *
- * @param priv
- * @return error code
- */
-int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
-{
-	int ret;
-	int txq_id, slots_num;
-	unsigned long flags;
-
-	/* Free all tx/cmd queues and keep-warm buffer */
-	iwlagn_hw_txq_ctx_free(priv);
-
-	ret = iwlagn_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
-				priv->hw_params.scd_bc_tbls_size);
-	if (ret) {
-		IWL_ERR(priv, "Scheduler BC Table allocation failed\n");
-		goto error_bc_tbls;
-	}
-	/* Alloc keep-warm buffer */
-	ret = iwlagn_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
-	if (ret) {
-		IWL_ERR(priv, "Keep Warm allocation failed\n");
-		goto error_kw;
-	}
-
-	/* allocate tx queue structure */
-	ret = iwl_alloc_txq_mem(priv);
-	if (ret)
-		goto error;
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	/* Turn off all Tx DMA fifos */
-	iwlagn_txq_set_sched(priv, 0);
-
-	/* Tell NIC where to find the "keep warm" buffer */
-	iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* Alloc and init all Tx queues, including the command queue (#4/#9) */
-	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-		slots_num = (txq_id == priv->cmd_queue) ?
-					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
-				       txq_id);
-		if (ret) {
-			IWL_ERR(priv, "Tx %d queue init failed\n", txq_id);
-			goto error;
-		}
-	}
-
-	return ret;
-
- error:
-	iwlagn_hw_txq_ctx_free(priv);
-	iwlagn_free_dma_ptr(priv, &priv->kw);
- error_kw:
-	iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);
- error_bc_tbls:
-	return ret;
-}
-
-void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
-{
-	int txq_id, slots_num;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	/* Turn off all Tx DMA fifos */
-	iwlagn_txq_set_sched(priv, 0);
-
-	/* Tell NIC where to find the "keep warm" buffer */
-	iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* Alloc and init all Tx queues, including the command queue (#4) */
-	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-		slots_num = txq_id == priv->cmd_queue ?
-			    TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
-	}
-}
-
 /**
 /**
  * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
  * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
  */
  */

+ 5 - 3
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c

@@ -386,11 +386,13 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
 	spin_lock_irqsave(&priv->lock, flags);
 	spin_lock_irqsave(&priv->lock, flags);
 
 
 	priv->scd_base_addr = iwl_read_prph(priv, IWLAGN_SCD_SRAM_BASE_ADDR);
 	priv->scd_base_addr = iwl_read_prph(priv, IWLAGN_SCD_SRAM_BASE_ADDR);
-	a = priv->scd_base_addr + IWLAGN_SCD_CONTEXT_DATA_OFFSET;
-	for (; a < priv->scd_base_addr + IWLAGN_SCD_TX_STTS_BITMAP_OFFSET;
+	a = priv->scd_base_addr + IWLAGN_SCD_CONTEXT_MEM_LOWER_BOUND;
+	/* reset conext data memory */
+	for (; a < priv->scd_base_addr + IWLAGN_SCD_CONTEXT_MEM_UPPER_BOUND;
 		a += 4)
 		a += 4)
 		iwl_write_targ_mem(priv, a, 0);
 		iwl_write_targ_mem(priv, a, 0);
-	for (; a < priv->scd_base_addr + IWLAGN_SCD_TRANSLATE_TBL_OFFSET;
+	/* reset tx status memory */
+	for (; a < priv->scd_base_addr + IWLAGN_SCD_TX_STTS_MEM_UPPER_BOUND;
 		a += 4)
 		a += 4)
 		iwl_write_targ_mem(priv, a, 0);
 		iwl_write_targ_mem(priv, a, 0);
 	for (; a < priv->scd_base_addr +
 	for (; a < priv->scd_base_addr +

+ 25 - 29
drivers/net/wireless/iwlwifi/iwl-agn.c

@@ -56,7 +56,7 @@
 #include "iwl-agn-calib.h"
 #include "iwl-agn-calib.h"
 #include "iwl-agn.h"
 #include "iwl-agn.h"
 #include "iwl-pci.h"
 #include "iwl-pci.h"
-
+#include "iwl-trans.h"
 
 
 /******************************************************************************
 /******************************************************************************
  *
  *
@@ -90,12 +90,10 @@ void iwl_update_chain_flags(struct iwl_priv *priv)
 {
 {
 	struct iwl_rxon_context *ctx;
 	struct iwl_rxon_context *ctx;
 
 
-	if (priv->cfg->ops->hcmd->set_rxon_chain) {
-		for_each_context(priv, ctx) {
-			priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
-			if (ctx->active.rx_chain != ctx->staging.rx_chain)
-				iwlagn_commit_rxon(priv, ctx);
-		}
+	for_each_context(priv, ctx) {
+		iwlagn_set_rxon_chain(priv, ctx);
+		if (ctx->active.rx_chain != ctx->staging.rx_chain)
+			iwlagn_commit_rxon(priv, ctx);
 	}
 	}
 }
 }
 
 
@@ -260,7 +258,7 @@ static void iwl_bg_bt_runtime_config(struct work_struct *work)
 	/* dont send host command if rf-kill is on */
 	/* dont send host command if rf-kill is on */
 	if (!iwl_is_ready_rf(priv))
 	if (!iwl_is_ready_rf(priv))
 		return;
 		return;
-	priv->cfg->ops->hcmd->send_bt_config(priv);
+	iwlagn_send_advance_bt_config(priv);
 }
 }
 
 
 static void iwl_bg_bt_full_concurrency(struct work_struct *work)
 static void iwl_bg_bt_full_concurrency(struct work_struct *work)
@@ -287,12 +285,11 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work)
 	 * to avoid 3-wire collisions
 	 * to avoid 3-wire collisions
 	 */
 	 */
 	for_each_context(priv, ctx) {
 	for_each_context(priv, ctx) {
-		if (priv->cfg->ops->hcmd->set_rxon_chain)
-			priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+		iwlagn_set_rxon_chain(priv, ctx);
 		iwlagn_commit_rxon(priv, ctx);
 		iwlagn_commit_rxon(priv, ctx);
 	}
 	}
 
 
-	priv->cfg->ops->hcmd->send_bt_config(priv);
+	iwlagn_send_advance_bt_config(priv);
 out:
 out:
 	mutex_unlock(&priv->mutex);
 	mutex_unlock(&priv->mutex);
 }
 }
@@ -2017,7 +2014,7 @@ int iwl_alive_start(struct iwl_priv *priv)
 		priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
 		priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
 		priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
 		priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
 		priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
 		priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
-		priv->cfg->ops->hcmd->send_bt_config(priv);
+		iwlagn_send_advance_bt_config(priv);
 		priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
 		priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
 		iwlagn_send_prio_tbl(priv);
 		iwlagn_send_prio_tbl(priv);
 
 
@@ -2030,7 +2027,13 @@ int iwl_alive_start(struct iwl_priv *priv)
 					 BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
 					 BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
+	} else {
+		/*
+		 * default is 2-wire BT coexexistence support
+		 */
+		iwl_send_bt_config(priv);
 	}
 	}
+
 	if (priv->hw_params.calib_rt_cfg)
 	if (priv->hw_params.calib_rt_cfg)
 		iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg);
 		iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg);
 
 
@@ -2039,8 +2042,7 @@ int iwl_alive_start(struct iwl_priv *priv)
 	priv->active_rate = IWL_RATES_MASK;
 	priv->active_rate = IWL_RATES_MASK;
 
 
 	/* Configure Tx antenna selection based on H/W config */
 	/* Configure Tx antenna selection based on H/W config */
-	if (priv->cfg->ops->hcmd->set_tx_ant)
-		priv->cfg->ops->hcmd->set_tx_ant(priv, priv->cfg->valid_tx_ant);
+	iwlagn_send_tx_ant_config(priv, priv->cfg->valid_tx_ant);
 
 
 	if (iwl_is_associated_ctx(ctx)) {
 	if (iwl_is_associated_ctx(ctx)) {
 		struct iwl_rxon_cmd *active_rxon =
 		struct iwl_rxon_cmd *active_rxon =
@@ -2054,16 +2056,7 @@ int iwl_alive_start(struct iwl_priv *priv)
 		for_each_context(priv, tmp)
 		for_each_context(priv, tmp)
 			iwl_connection_init_rx_config(priv, tmp);
 			iwl_connection_init_rx_config(priv, tmp);
 
 
-		if (priv->cfg->ops->hcmd->set_rxon_chain)
-			priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
-	}
-
-	if (!priv->cfg->bt_params || (priv->cfg->bt_params &&
-	    !priv->cfg->bt_params->advanced_bt_coexist)) {
-		/*
-		 * default is 2-wire BT coexexistence support
-		 */
-		priv->cfg->ops->hcmd->send_bt_config(priv);
+		iwlagn_set_rxon_chain(priv, ctx);
 	}
 	}
 
 
 	iwl_reset_run_time_calib(priv);
 	iwl_reset_run_time_calib(priv);
@@ -3288,9 +3281,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
 	priv->rx_statistics_jiffies = jiffies;
 	priv->rx_statistics_jiffies = jiffies;
 
 
 	/* Choose which receivers/antennas to use */
 	/* Choose which receivers/antennas to use */
-	if (priv->cfg->ops->hcmd->set_rxon_chain)
-		priv->cfg->ops->hcmd->set_rxon_chain(priv,
-					&priv->contexts[IWL_RXON_CTX_BSS]);
+	iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
 
 
 	iwl_init_scan_params(priv);
 	iwl_init_scan_params(priv);
 
 
@@ -3517,6 +3508,8 @@ int iwl_probe(void *bus_specific, struct iwl_bus_ops *bus_ops,
 	priv->bus.ops->set_drv_data(&priv->bus, priv);
 	priv->bus.ops->set_drv_data(&priv->bus, priv);
 	priv->bus.dev = priv->bus.ops->get_dev(&priv->bus);
 	priv->bus.dev = priv->bus.ops->get_dev(&priv->bus);
 
 
+	iwl_trans_register(&priv->trans);
+
 	/* At this point both hw and priv are allocated. */
 	/* At this point both hw and priv are allocated. */
 
 
 	SET_IEEE80211_DEV(hw, priv->bus.dev);
 	SET_IEEE80211_DEV(hw, priv->bus.dev);
@@ -3716,8 +3709,7 @@ void __devexit iwl_remove(struct iwl_priv * priv)
 
 
 	iwl_dealloc_ucode(priv);
 	iwl_dealloc_ucode(priv);
 
 
-	if (priv->rxq.bd)
-		iwlagn_rx_queue_free(priv, &priv->rxq);
+	priv->trans.ops->rx_free(priv);
 	iwlagn_hw_txq_ctx_free(priv);
 	iwlagn_hw_txq_ctx_free(priv);
 
 
 	iwl_eeprom_free(priv);
 	iwl_eeprom_free(priv);
@@ -3820,6 +3812,10 @@ MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])");
 module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO);
 module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO);
 MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])");
 MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])");
 
 
+module_param_named(wd_disable, iwlagn_mod_params.wd_disable, bool, S_IRUGO);
+MODULE_PARM_DESC(wd_disable,
+		"Disable stuck queue watchdog timer (default: 0 [enabled])");
+
 /*
 /*
  * set bt_coex_active to true, uCode will do kill/defer
  * set bt_coex_active to true, uCode will do kill/defer
  * every time the priority line is asserted (BT is sending signals on the
  * every time the priority line is asserted (BT is sending signals on the

+ 1 - 4
drivers/net/wireless/iwlwifi/iwl-agn.h

@@ -182,7 +182,6 @@ void iwlagn_temperature(struct iwl_priv *priv);
 u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv);
 u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv);
 const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
 const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
 				   size_t offset);
 				   size_t offset);
-void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwlagn_hw_nic_init(struct iwl_priv *priv);
 int iwlagn_hw_nic_init(struct iwl_priv *priv);
 int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
 int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
@@ -194,7 +193,6 @@ void iwlagn_rx_queue_restock(struct iwl_priv *priv);
 void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority);
 void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority);
 void iwlagn_rx_replenish(struct iwl_priv *priv);
 void iwlagn_rx_replenish(struct iwl_priv *priv);
 void iwlagn_rx_replenish_now(struct iwl_priv *priv);
 void iwlagn_rx_replenish_now(struct iwl_priv *priv);
-void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwlagn_rxq_stop(struct iwl_priv *priv);
 int iwlagn_rxq_stop(struct iwl_priv *priv);
 int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
 int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
 void iwl_setup_rx_handlers(struct iwl_priv *priv);
 void iwl_setup_rx_handlers(struct iwl_priv *priv);
@@ -220,8 +218,6 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
 				struct iwl_rx_mem_buffer *rxb);
 				struct iwl_rx_mem_buffer *rxb);
 int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
 int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
 void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv);
 void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv);
-int iwlagn_txq_ctx_alloc(struct iwl_priv *priv);
-void iwlagn_txq_ctx_reset(struct iwl_priv *priv);
 void iwlagn_txq_ctx_stop(struct iwl_priv *priv);
 void iwlagn_txq_ctx_stop(struct iwl_priv *priv);
 
 
 static inline u32 iwl_tx_status_to_mac80211(u32 status)
 static inline u32 iwl_tx_status_to_mac80211(u32 status)
@@ -260,6 +256,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
 /* hcmd */
 /* hcmd */
 int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
 int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
 int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
 int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
+int iwlagn_set_pan_params(struct iwl_priv *priv);
 
 
 /* bt coex */
 /* bt coex */
 void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
 void iwlagn_send_advance_bt_config(struct iwl_priv *priv);

+ 3 - 19
drivers/net/wireless/iwlwifi/iwl-core.c

@@ -585,8 +585,7 @@ static void _iwl_set_rxon_ht(struct iwl_priv *priv,
 		rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
 		rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
 	}
 	}
 
 
-	if (priv->cfg->ops->hcmd->set_rxon_chain)
-		priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+	iwlagn_set_rxon_chain(priv, ctx);
 
 
 	IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
 	IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
 			"extension channel offset 0x%x\n",
 			"extension channel offset 0x%x\n",
@@ -1216,8 +1215,7 @@ static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
 {
 	iwl_connection_init_rx_config(priv, ctx);
 	iwl_connection_init_rx_config(priv, ctx);
 
 
-	if (priv->cfg->ops->hcmd->set_rxon_chain)
-		priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+	iwlagn_set_rxon_chain(priv, ctx);
 
 
 	return iwlagn_commit_rxon(priv, ctx);
 	return iwlagn_commit_rxon(priv, ctx);
 }
 }
@@ -1372,20 +1370,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 
 
 }
 }
 
 
-int iwl_alloc_txq_mem(struct iwl_priv *priv)
-{
-	if (!priv->txq)
-		priv->txq = kzalloc(
-			sizeof(struct iwl_tx_queue) *
-				priv->cfg->base_params->num_of_queues,
-			GFP_KERNEL);
-	if (!priv->txq) {
-		IWL_ERR(priv, "Not enough memory for txq\n");
-		return -ENOMEM;
-	}
-	return 0;
-}
-
 void iwl_free_txq_mem(struct iwl_priv *priv)
 void iwl_free_txq_mem(struct iwl_priv *priv)
 {
 {
 	kfree(priv->txq);
 	kfree(priv->txq);
@@ -1853,7 +1837,7 @@ void iwl_setup_watchdog(struct iwl_priv *priv)
 {
 {
 	unsigned int timeout = priv->cfg->base_params->wd_timeout;
 	unsigned int timeout = priv->cfg->base_params->wd_timeout;
 
 
-	if (timeout)
+	if (timeout && !iwlagn_mod_params.wd_disable)
 		mod_timer(&priv->watchdog,
 		mod_timer(&priv->watchdog,
 			  jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout)));
 			  jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout)));
 	else
 	else

+ 3 - 15
drivers/net/wireless/iwlwifi/iwl-core.h

@@ -80,14 +80,6 @@ struct iwl_cmd;
 
 
 #define IWL_CMD(x) case x: return #x
 #define IWL_CMD(x) case x: return #x
 
 
-struct iwl_hcmd_ops {
-	void (*set_rxon_chain)(struct iwl_priv *priv,
-			       struct iwl_rxon_context *ctx);
-	int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant);
-	void (*send_bt_config)(struct iwl_priv *priv);
-	int (*set_pan_params)(struct iwl_priv *priv);
-};
-
 struct iwl_hcmd_utils_ops {
 struct iwl_hcmd_utils_ops {
 	u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
 	u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
 	void (*gain_computation)(struct iwl_priv *priv,
 	void (*gain_computation)(struct iwl_priv *priv,
@@ -146,7 +138,6 @@ struct iwl_nic_ops {
 
 
 struct iwl_ops {
 struct iwl_ops {
 	const struct iwl_lib_ops *lib;
 	const struct iwl_lib_ops *lib;
-	const struct iwl_hcmd_ops *hcmd;
 	const struct iwl_hcmd_utils_ops *utils;
 	const struct iwl_hcmd_utils_ops *utils;
 	const struct iwl_nic_ops *nic;
 	const struct iwl_nic_ops *nic;
 };
 };
@@ -160,6 +151,7 @@ struct iwl_mod_params {
 	int restart_fw;		/* def: 1 = restart firmware */
 	int restart_fw;		/* def: 1 = restart firmware */
 	bool plcp_check;	/* def: true = enable plcp health check */
 	bool plcp_check;	/* def: true = enable plcp health check */
 	bool ack_check;		/* def: false = disable ack health check */
 	bool ack_check;		/* def: false = disable ack health check */
+	bool wd_disable;	/* def: false = enable stuck queue check */
 	bool bt_coex_active;	/* def: true = enable bt coex */
 	bool bt_coex_active;	/* def: true = enable bt coex */
 	int led_mode;		/* def: 0 = system default */
 	int led_mode;		/* def: 0 = system default */
 	bool no_sleep_autoadjust; /* def: true = disable autoadjust */
 	bool no_sleep_autoadjust; /* def: true = disable autoadjust */
@@ -336,7 +328,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 int iwl_mac_change_interface(struct ieee80211_hw *hw,
 int iwl_mac_change_interface(struct ieee80211_hw *hw,
 			     struct ieee80211_vif *vif,
 			     struct ieee80211_vif *vif,
 			     enum nl80211_iftype newtype, bool newp2p);
 			     enum nl80211_iftype newtype, bool newp2p);
-int iwl_alloc_txq_mem(struct iwl_priv *priv);
 void iwl_free_txq_mem(struct iwl_priv *priv);
 void iwl_free_txq_mem(struct iwl_priv *priv);
 
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -382,7 +373,6 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
 ******************************************************/
 ******************************************************/
 void iwl_cmd_queue_free(struct iwl_priv *priv);
 void iwl_cmd_queue_free(struct iwl_priv *priv);
 void iwl_cmd_queue_unmap(struct iwl_priv *priv);
 void iwl_cmd_queue_unmap(struct iwl_priv *priv);
-int iwl_rx_queue_alloc(struct iwl_priv *priv);
 void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
 void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
 				  struct iwl_rx_queue *q);
 				  struct iwl_rx_queue *q);
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
@@ -396,11 +386,9 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
 * TX
 * TX
 ******************************************************/
 ******************************************************/
 void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
 void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
-		      int slots_num, u32 txq_id);
-void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
-			int slots_num, u32 txq_id);
 void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
 void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
+int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+			  int count, int slots_num, u32 id);
 void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id);
 void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id);
 void iwl_setup_watchdog(struct iwl_priv *priv);
 void iwl_setup_watchdog(struct iwl_priv *priv);
 /*****************************************************
 /*****************************************************

+ 20 - 2
drivers/net/wireless/iwlwifi/iwl-dev.h

@@ -666,7 +666,6 @@ struct iwl_hw_params {
 	u16 max_rxq_size;
 	u16 max_rxq_size;
 	u16 max_rxq_log;
 	u16 max_rxq_log;
 	u32 rx_page_order;
 	u32 rx_page_order;
-	u32 rx_wrt_ptr_reg;
 	u8  max_stations;
 	u8  max_stations;
 	u8  ht40_channel;
 	u8  ht40_channel;
 	u8  max_beacon_itrvl;	/* in 1024 ms */
 	u8  max_beacon_itrvl;	/* in 1024 ms */
@@ -1228,6 +1227,25 @@ struct iwl_bus {
 	unsigned int irq;
 	unsigned int irq;
 };
 };
 
 
+struct iwl_trans;
+
+/**
+ * struct iwl_trans_ops - transport specific operations
+
+ * @rx_init: inits the rx memory, allocate it if needed
+ * @rx_free: frees the rx memory
+ * @tx_init:inits the tx memory, allocate if needed
+ */
+struct iwl_trans_ops {
+	int (*rx_init)(struct iwl_priv *priv);
+	void (*rx_free)(struct iwl_priv *priv);
+	int (*tx_init)(struct iwl_priv *priv);
+};
+
+struct iwl_trans {
+	const struct iwl_trans_ops *ops;
+};
+
 struct iwl_priv {
 struct iwl_priv {
 
 
 	/* ieee device used by generic ieee processing code */
 	/* ieee device used by generic ieee processing code */
@@ -1296,13 +1314,13 @@ struct iwl_priv {
 	struct mutex mutex;
 	struct mutex mutex;
 
 
 	struct iwl_bus bus;	/* bus specific data */
 	struct iwl_bus bus;	/* bus specific data */
+	struct iwl_trans trans;
 
 
 	/* microcode/device supports multiple contexts */
 	/* microcode/device supports multiple contexts */
 	u8 valid_contexts;
 	u8 valid_contexts;
 
 
 	/* command queue number */
 	/* command queue number */
 	u8 cmd_queue;
 	u8 cmd_queue;
-	u8 last_sync_cmd_id;
 
 
 	/* max number of station keys */
 	/* max number of station keys */
 	u8 sta_key_max_num;
 	u8 sta_key_max_num;

+ 3 - 10
drivers/net/wireless/iwlwifi/iwl-hcmd.c

@@ -171,6 +171,8 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	int cmd_idx;
 	int cmd_idx;
 	int ret;
 	int ret;
 
 
+	lockdep_assert_held(&priv->mutex);
+
 	if (WARN_ON(cmd->flags & CMD_ASYNC))
 	if (WARN_ON(cmd->flags & CMD_ASYNC))
 		return -EINVAL;
 		return -EINVAL;
 
 
@@ -181,16 +183,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
 	IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
 			get_cmd_string(cmd->id));
 			get_cmd_string(cmd->id));
 
 
-	if (test_and_set_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
-		IWL_ERR(priv, "STATUS_HCMD_ACTIVE already set while sending %s"
-			      ". Previous SYNC cmdn is %s\n",
-			get_cmd_string(cmd->id),
-			get_cmd_string(priv->last_sync_cmd_id));
-		WARN_ON(1);
-	} else {
-		priv->last_sync_cmd_id = cmd->id;
-	}
-
+	set_bit(STATUS_HCMD_ACTIVE, &priv->status);
 	IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
 	IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
 			get_cmd_string(cmd->id));
 			get_cmd_string(cmd->id));
 
 

+ 2 - 1
drivers/net/wireless/iwlwifi/iwl-pci.c

@@ -67,6 +67,7 @@
 #include "iwl-agn.h"
 #include "iwl-agn.h"
 #include "iwl-core.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-io.h"
+#include "iwl-trans.h"
 
 
 /* PCI registers */
 /* PCI registers */
 #define PCI_CFG_RETRY_TIMEOUT	0x041
 #define PCI_CFG_RETRY_TIMEOUT	0x041
@@ -93,7 +94,7 @@ static u16 iwl_pciexp_link_ctrl(struct iwl_bus *bus)
 	u16 pci_lnk_ctl;
 	u16 pci_lnk_ctl;
 	struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
 	struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
 
 
-	pos = pci_find_capability(pci_dev, PCI_CAP_ID_EXP);
+	pos = pci_pcie_cap(pci_dev);
 	pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
 	pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
 	return pci_lnk_ctl;
 	return pci_lnk_ctl;
 }
 }

+ 14 - 5
drivers/net/wireless/iwlwifi/iwl-prph.h

@@ -168,6 +168,7 @@
  * the scheduler (especially for queue #4/#9, the command queue, otherwise
  * the scheduler (especially for queue #4/#9, the command queue, otherwise
  * the driver can't issue commands!):
  * the driver can't issue commands!):
  */
  */
+#define SCD_MEM_LOWER_BOUND		(0x0000)
 
 
 /**
 /**
  * Max Tx window size is the max number of contiguous TFDs that the scheduler
  * Max Tx window size is the max number of contiguous TFDs that the scheduler
@@ -197,15 +198,23 @@
 #define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS	(16)
 #define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS	(16)
 #define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK	(0x007F0000)
 #define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK	(0x007F0000)
 
 
-#define IWLAGN_SCD_CONTEXT_DATA_OFFSET		(0x600)
-#define IWLAGN_SCD_TX_STTS_BITMAP_OFFSET		(0x7B1)
-#define IWLAGN_SCD_TRANSLATE_TBL_OFFSET		(0x7E0)
+/* Context Data */
+#define IWLAGN_SCD_CONTEXT_MEM_LOWER_BOUND	(SCD_MEM_LOWER_BOUND + 0x600)
+#define IWLAGN_SCD_CONTEXT_MEM_UPPER_BOUND	(SCD_MEM_LOWER_BOUND + 0x6A0)
+
+/* Tx status */
+#define IWLAGN_SCD_TX_STTS_MEM_LOWER_BOUND	(SCD_MEM_LOWER_BOUND + 0x6A0)
+#define IWLAGN_SCD_TX_STTS_MEM_UPPER_BOUND	(SCD_MEM_LOWER_BOUND + 0x7E0)
+
+/* Translation Data */
+#define IWLAGN_SCD_TRANS_TBL_MEM_LOWER_BOUND	(SCD_MEM_LOWER_BOUND + 0x7E0)
+#define IWLAGN_SCD_TRANS_TBL_MEM_UPPER_BOUND	(SCD_MEM_LOWER_BOUND + 0x808)
 
 
 #define IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(x)\
 #define IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(x)\
-	(IWLAGN_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
+	(IWLAGN_SCD_CONTEXT_MEM_LOWER_BOUND + ((x) * 8))
 
 
 #define IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
 #define IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
-	((IWLAGN_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc)
+	((IWLAGN_SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc)
 
 
 #define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv)	\
 #define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv)	\
 	(((1<<(priv)->hw_params.max_txq_num) - 1) &\
 	(((1<<(priv)->hw_params.max_txq_num) - 1) &\

+ 3 - 44
drivers/net/wireless/iwlwifi/iwl-rx.c

@@ -134,7 +134,6 @@ int iwl_rx_queue_space(const struct iwl_rx_queue *q)
 void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
 void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
-	u32 rx_wrt_ptr_reg = priv->hw_params.rx_wrt_ptr_reg;
 	u32 reg;
 	u32 reg;
 
 
 	spin_lock_irqsave(&q->lock, flags);
 	spin_lock_irqsave(&q->lock, flags);
@@ -146,7 +145,7 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q
 		/* shadow register enabled */
 		/* shadow register enabled */
 		/* Device expects a multiple of 8 */
 		/* Device expects a multiple of 8 */
 		q->write_actual = (q->write & ~0x7);
 		q->write_actual = (q->write & ~0x7);
-		iwl_write32(priv, rx_wrt_ptr_reg, q->write_actual);
+		iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write_actual);
 	} else {
 	} else {
 		/* If power-saving is in use, make sure device is awake */
 		/* If power-saving is in use, make sure device is awake */
 		if (test_bit(STATUS_POWER_PMI, &priv->status)) {
 		if (test_bit(STATUS_POWER_PMI, &priv->status)) {
@@ -162,14 +161,14 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q
 			}
 			}
 
 
 			q->write_actual = (q->write & ~0x7);
 			q->write_actual = (q->write & ~0x7);
-			iwl_write_direct32(priv, rx_wrt_ptr_reg,
+			iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
 					q->write_actual);
 					q->write_actual);
 
 
 		/* Else device is assumed to be awake */
 		/* Else device is assumed to be awake */
 		} else {
 		} else {
 			/* Device expects a multiple of 8 */
 			/* Device expects a multiple of 8 */
 			q->write_actual = (q->write & ~0x7);
 			q->write_actual = (q->write & ~0x7);
-			iwl_write_direct32(priv, rx_wrt_ptr_reg,
+			iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
 				q->write_actual);
 				q->write_actual);
 		}
 		}
 	}
 	}
@@ -179,46 +178,6 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q
 	spin_unlock_irqrestore(&q->lock, flags);
 	spin_unlock_irqrestore(&q->lock, flags);
 }
 }
 
 
-int iwl_rx_queue_alloc(struct iwl_priv *priv)
-{
-	struct iwl_rx_queue *rxq = &priv->rxq;
-	struct device *dev = priv->bus.dev;
-	int i;
-
-	spin_lock_init(&rxq->lock);
-	INIT_LIST_HEAD(&rxq->rx_free);
-	INIT_LIST_HEAD(&rxq->rx_used);
-
-	/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
-	rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->bd_dma,
-				     GFP_KERNEL);
-	if (!rxq->bd)
-		goto err_bd;
-
-	rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct iwl_rb_status),
-					  &rxq->rb_stts_dma, GFP_KERNEL);
-	if (!rxq->rb_stts)
-		goto err_rb;
-
-	/* Fill the rx_used queue with _all_ of the Rx buffers */
-	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
-		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-
-	/* Set us so that we have processed and used all buffers, but have
-	 * not restocked the Rx queue with fresh buffers */
-	rxq->read = rxq->write = 0;
-	rxq->write_actual = 0;
-	rxq->free_count = 0;
-	rxq->need_update = 0;
-	return 0;
-
-err_rb:
-	dma_free_coherent(dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-			  rxq->bd_dma);
-err_bd:
-	return -ENOMEM;
-}
-
 /******************************************************************************
 /******************************************************************************
  *
  *
  * Generic RX handler implementations
  * Generic RX handler implementations

+ 132 - 104
drivers/net/wireless/iwlwifi/iwl-testmode.h

@@ -66,116 +66,144 @@
 #include <linux/types.h>
 #include <linux/types.h>
 
 
 
 
-/* Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and
+/*
+ * Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and
  * from and kernel space to user space(IWL_TM_CMD_ID_DEV2APP_XX).
  * from and kernel space to user space(IWL_TM_CMD_ID_DEV2APP_XX).
- * The command ID is carried with IWL_TM_ATTR_COMMAND. There are three types of
- * of command from user space and two types of command from kernel space.
- * See below.
+ * The command ID is carried with IWL_TM_ATTR_COMMAND.
+ *
+ * @IWL_TM_CMD_APP2DEV_UCODE:
+ *	commands from user application to the uCode,
+ *	the actual uCode host command ID is carried with
+ *	IWL_TM_ATTR_UCODE_CMD_ID
+ *
+ * @IWL_TM_CMD_APP2DEV_REG_READ32:
+ * @IWL_TM_CMD_APP2DEV_REG_WRITE32:
+ * @IWL_TM_CMD_APP2DEV_REG_WRITE8:
+ *	commands from user applicaiton to access register
+ *
+ * @IWL_TM_CMD_APP2DEV_GET_DEVICENAME: retrieve device name
+ * @IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: load initial uCode image
+ * @IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: perform calibration
+ * @IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: load runtime uCode image
+ * @IWL_TM_CMD_APP2DEV_GET_EEPROM: request EEPROM data
+ * @IWL_TM_CMD_APP2DEV_FIXRATE_REQ: set fix MCS
+ *	commands fom user space for pure driver level operations
+ *
+ * @IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+ * @IWL_TM_CMD_APP2DEV_END_TRACE:
+ * @IWL_TM_CMD_APP2DEV_READ_TRACE:
+ *	commands fom user space for uCode trace operations
+ *
+ * @IWL_TM_CMD_DEV2APP_SYNC_RSP:
+ *	commands from kernel space to carry the synchronous response
+ *	to user application
+ * @IWL_TM_CMD_DEV2APP_UCODE_RX_PKT:
+ *	commands from kernel space to multicast the spontaneous messages
+ *	to user application
+ * @IWL_TM_CMD_DEV2APP_EEPROM_RSP:
+ *	commands from kernel space to carry the eeprom response
+ *	to user application
  */
  */
 enum iwl_tm_cmd_t {
 enum iwl_tm_cmd_t {
-	/* commands from user application to the uCode,
-	 * the actual uCode host command ID is carried with
-	 * IWL_TM_ATTR_UCODE_CMD_ID */
-	IWL_TM_CMD_APP2DEV_UCODE = 1,
-
-	/* commands from user applicaiton to access register */
-	IWL_TM_CMD_APP2DEV_REG_READ32,
-	IWL_TM_CMD_APP2DEV_REG_WRITE32,
-	IWL_TM_CMD_APP2DEV_REG_WRITE8,
-
-	/* commands fom user space for pure driver level operations */
-	IWL_TM_CMD_APP2DEV_GET_DEVICENAME,
-	IWL_TM_CMD_APP2DEV_LOAD_INIT_FW,
-	IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB,
-	IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW,
-	IWL_TM_CMD_APP2DEV_GET_EEPROM,
-	IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
-	/* if there is other new command for the driver layer operation,
-	 * append them here */
-
-	/* commands fom user space for uCode trace operations */
-	IWL_TM_CMD_APP2DEV_BEGIN_TRACE,
-	IWL_TM_CMD_APP2DEV_END_TRACE,
-	IWL_TM_CMD_APP2DEV_READ_TRACE,
-
-	/* commands from kernel space to carry the synchronous response
-	 * to user application */
-	IWL_TM_CMD_DEV2APP_SYNC_RSP,
-
-	/* commands from kernel space to multicast the spontaneous messages
-	 * to user application */
-	IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
-
-	/* commands from kernel space to carry the eeprom response
-	 * to user application */
-	IWL_TM_CMD_DEV2APP_EEPROM_RSP,
-
-	IWL_TM_CMD_MAX,
+	IWL_TM_CMD_APP2DEV_UCODE		= 1,
+	IWL_TM_CMD_APP2DEV_REG_READ32		= 2,
+	IWL_TM_CMD_APP2DEV_REG_WRITE32		= 3,
+	IWL_TM_CMD_APP2DEV_REG_WRITE8		= 4,
+	IWL_TM_CMD_APP2DEV_GET_DEVICENAME	= 5,
+	IWL_TM_CMD_APP2DEV_LOAD_INIT_FW		= 6,
+	IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB	= 7,
+	IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW	= 8,
+	IWL_TM_CMD_APP2DEV_GET_EEPROM		= 9,
+	IWL_TM_CMD_APP2DEV_FIXRATE_REQ		= 10,
+	IWL_TM_CMD_APP2DEV_BEGIN_TRACE		= 11,
+	IWL_TM_CMD_APP2DEV_END_TRACE		= 12,
+	IWL_TM_CMD_APP2DEV_READ_TRACE		= 13,
+	IWL_TM_CMD_DEV2APP_SYNC_RSP		= 14,
+	IWL_TM_CMD_DEV2APP_UCODE_RX_PKT		= 15,
+	IWL_TM_CMD_DEV2APP_EEPROM_RSP		= 16,
+	IWL_TM_CMD_MAX				= 17,
 };
 };
 
 
+/*
+ * Atrribute filed in testmode command
+ * See enum iwl_tm_cmd_t.
+ *
+ * @IWL_TM_ATTR_NOT_APPLICABLE:
+ *	The attribute is not applicable or invalid
+ * @IWL_TM_ATTR_COMMAND:
+ *	From user space to kernel space:
+ *	the command either destines to ucode, driver, or register;
+ *	From kernel space to user space:
+ *	the command either carries synchronous response,
+ *	or the spontaneous message multicast from the device;
+ *
+ * @IWL_TM_ATTR_UCODE_CMD_ID:
+ * @IWL_TM_ATTR_UCODE_CMD_DATA:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE,
+ *	The mandatory fields are :
+ *	IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID;
+ *	IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands;
+ *	The optional fields are:
+ *	IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload
+ *	to the ucode
+ *
+ * @IWL_TM_ATTR_REG_OFFSET:
+ * @IWL_TM_ATTR_REG_VALUE8:
+ * @IWL_TM_ATTR_REG_VALUE32:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX,
+ *	The mandatory fields are:
+ *	IWL_TM_ATTR_REG_OFFSET for the offset of the target register;
+ *	IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value
+ *
+ * @IWL_TM_ATTR_SYNC_RSP:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP,
+ *	The mandatory fields are:
+ *	IWL_TM_ATTR_SYNC_RSP for the data content responding to the user
+ *	application command
+ *
+ * @IWL_TM_ATTR_UCODE_RX_PKT:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
+ *	The mandatory fields are:
+ *	IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user
+ *	application
+ *
+ * @IWL_TM_ATTR_EEPROM:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_EEPROM,
+ *	The mandatory fields are:
+ *	IWL_TM_ATTR_EEPROM for the data content responging to the user
+ *	application
+ *
+ * @IWL_TM_ATTR_TRACE_ADDR:
+ * @IWL_TM_ATTR_TRACE_SIZE:
+ * @IWL_TM_ATTR_TRACE_DUMP:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_XXX_TRACE,
+ *	The mandatory fields are:
+ *	IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address
+ *	IWL_TM_ATTR_MEM_TRACE_SIZE for the trace buffer size
+ *	IWL_TM_ATTR_MEM_TRACE_DUMP for the trace dump
+ *
+ * @IWL_TM_ATTR_FIXRATE:
+ *	When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
+ *	The mandatory fields are:
+ *	IWL_TM_ATTR_FIXRATE for the fixed rate
+ *
+ */
 enum iwl_tm_attr_t {
 enum iwl_tm_attr_t {
-	IWL_TM_ATTR_NOT_APPLICABLE = 0,
-
-	/* From user space to kernel space:
-	 * the command either destines to ucode, driver, or register;
-	 * See enum iwl_tm_cmd_t.
-	 *
-	 * From kernel space to user space:
-	 * the command either carries synchronous response,
-	 * or the spontaneous message multicast from the device;
-	 * See enum iwl_tm_cmd_t. */
-	IWL_TM_ATTR_COMMAND,
-
-	/* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE,
-	 * The mandatory fields are :
-	 * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID;
-	 * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands;
-	 * The optional fields are:
-	 * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload
-	 * to the ucode */
-	IWL_TM_ATTR_UCODE_CMD_ID,
-	IWL_TM_ATTR_UCODE_CMD_DATA,
-
-	/* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX,
-	 * The mandatory fields are:
-	 * IWL_TM_ATTR_REG_OFFSET for the offset of the target register;
-	 * IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value */
-	IWL_TM_ATTR_REG_OFFSET,
-	IWL_TM_ATTR_REG_VALUE8,
-	IWL_TM_ATTR_REG_VALUE32,
-
-	/* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP,
-	 * The mandatory fields are:
-	 * IWL_TM_ATTR_SYNC_RSP for the data content responding to the user
-	 * application command */
-	IWL_TM_ATTR_SYNC_RSP,
-	/* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
-	 * The mandatory fields are:
-	 * IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user
-	 * application */
-	IWL_TM_ATTR_UCODE_RX_PKT,
-
-	/* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_EEPROM,
-	 * The mandatory fields are:
-	 * IWL_TM_ATTR_EEPROM for the data content responging to the user
-	 * application */
-	IWL_TM_ATTR_EEPROM,
-
-	/* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_XXX_TRACE,
-	 * The mandatory fields are:
-	 * IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address
-	 */
-	IWL_TM_ATTR_TRACE_ADDR,
-	IWL_TM_ATTR_TRACE_SIZE,
-	IWL_TM_ATTR_TRACE_DUMP,
-
-	/* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
-	 * The mandatory fields are:
-	 * IWL_TM_ATTR_FIXRATE for the fixed rate
-	 */
-	IWL_TM_ATTR_FIXRATE,
-
-	IWL_TM_ATTR_MAX,
+	IWL_TM_ATTR_NOT_APPLICABLE		= 0,
+	IWL_TM_ATTR_COMMAND			= 1,
+	IWL_TM_ATTR_UCODE_CMD_ID		= 2,
+	IWL_TM_ATTR_UCODE_CMD_DATA		= 3,
+	IWL_TM_ATTR_REG_OFFSET			= 4,
+	IWL_TM_ATTR_REG_VALUE8			= 5,
+	IWL_TM_ATTR_REG_VALUE32			= 6,
+	IWL_TM_ATTR_SYNC_RSP			= 7,
+	IWL_TM_ATTR_UCODE_RX_PKT		= 8,
+	IWL_TM_ATTR_EEPROM			= 9,
+	IWL_TM_ATTR_TRACE_ADDR			= 10,
+	IWL_TM_ATTR_TRACE_SIZE			= 11,
+	IWL_TM_ATTR_TRACE_DUMP			= 12,
+	IWL_TM_ATTR_FIXRATE			= 13,
+	IWL_TM_ATTR_MAX				= 14,
 };
 };
 
 
 /* uCode trace buffer */
 /* uCode trace buffer */

+ 423 - 0
drivers/net/wireless/iwlwifi/iwl-trans.c

@@ -0,0 +1,423 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include "iwl-dev.h"
+#include "iwl-trans.h"
+#include "iwl-core.h"
+#include "iwl-helpers.h"
+/*TODO remove uneeded includes when the transport layer tx_free will be here */
+#include "iwl-agn.h"
+
+static int iwl_trans_rx_alloc(struct iwl_priv *priv)
+{
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct device *dev = priv->bus.dev;
+
+	memset(&priv->rxq, 0, sizeof(priv->rxq));
+
+	spin_lock_init(&rxq->lock);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+
+	if (WARN_ON(rxq->bd || rxq->rb_stts))
+		return -EINVAL;
+
+	/* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
+	rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+				     &rxq->bd_dma, GFP_KERNEL);
+	if (!rxq->bd)
+		goto err_bd;
+	memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE);
+
+	/*Allocate the driver's pointer to receive buffer status */
+	rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts),
+					  &rxq->rb_stts_dma, GFP_KERNEL);
+	if (!rxq->rb_stts)
+		goto err_rb_stts;
+	memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
+
+	return 0;
+
+err_rb_stts:
+	dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+			rxq->bd, rxq->bd_dma);
+	memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+	rxq->bd = NULL;
+err_bd:
+	return -ENOMEM;
+}
+
+static void iwl_trans_rxq_free_rx_bufs(struct iwl_priv *priv)
+{
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	int i;
+
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+		/* In the reset function, these buffers may have been allocated
+		 * to an SKB, so we need to unmap and free potential storage */
+		if (rxq->pool[i].page != NULL) {
+			dma_unmap_page(priv->bus.dev, rxq->pool[i].page_dma,
+				PAGE_SIZE << priv->hw_params.rx_page_order,
+				DMA_FROM_DEVICE);
+			__iwl_free_pages(priv, rxq->pool[i].page);
+			rxq->pool[i].page = NULL;
+		}
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+	}
+}
+
+static int iwl_trans_rx_init(struct iwl_priv *priv)
+{
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	int i, err;
+	unsigned long flags;
+
+	if (!rxq->bd) {
+		err = iwl_trans_rx_alloc(priv);
+		if (err)
+			return err;
+	}
+
+	spin_lock_irqsave(&rxq->lock, flags);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+
+	iwl_trans_rxq_free_rx_bufs(priv);
+
+	for (i = 0; i < RX_QUEUE_SIZE; i++)
+		rxq->queue[i] = NULL;
+
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->write_actual = 0;
+	rxq->free_count = 0;
+	spin_unlock_irqrestore(&rxq->lock, flags);
+
+	return 0;
+}
+
+static void iwl_trans_rx_free(struct iwl_priv *priv)
+{
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	unsigned long flags;
+
+	/*if rxq->bd is NULL, it means that nothing has been allocated,
+	 * exit now */
+	if (!rxq->bd) {
+		IWL_DEBUG_INFO(priv, "Free NULL rx context\n");
+		return;
+	}
+
+	spin_lock_irqsave(&rxq->lock, flags);
+	iwl_trans_rxq_free_rx_bufs(priv);
+	spin_unlock_irqrestore(&rxq->lock, flags);
+
+	dma_free_coherent(priv->bus.dev, sizeof(__le32) * RX_QUEUE_SIZE,
+			  rxq->bd, rxq->bd_dma);
+	memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+	rxq->bd = NULL;
+
+	if (rxq->rb_stts)
+		dma_free_coherent(priv->bus.dev,
+				  sizeof(struct iwl_rb_status),
+				  rxq->rb_stts, rxq->rb_stts_dma);
+	else
+		IWL_DEBUG_INFO(priv, "Free rxq->rb_stts which is NULL\n");
+	memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
+	rxq->rb_stts = NULL;
+}
+
+/* TODO:remove this code duplication */
+static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv,
+				    struct iwl_dma_ptr *ptr, size_t size)
+{
+	if (WARN_ON(ptr->addr))
+		return -EINVAL;
+
+	ptr->addr = dma_alloc_coherent(priv->bus.dev, size,
+				       &ptr->dma, GFP_KERNEL);
+	if (!ptr->addr)
+		return -ENOMEM;
+	ptr->size = size;
+	return 0;
+}
+
+static int iwl_trans_txq_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq,
+		      int slots_num, u32 txq_id)
+{
+	size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX;
+	int i;
+
+	if (WARN_ON(txq->meta || txq->cmd || txq->txb || txq->tfds))
+		return -EINVAL;
+
+	txq->meta = kzalloc(sizeof(txq->meta[0]) * slots_num,
+			    GFP_KERNEL);
+	txq->cmd = kzalloc(sizeof(txq->cmd[0]) * slots_num,
+			   GFP_KERNEL);
+
+	if (!txq->meta || !txq->cmd)
+		goto error;
+
+	for (i = 0; i < slots_num; i++) {
+		txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd),
+					GFP_KERNEL);
+		if (!txq->cmd[i])
+			goto error;
+	}
+
+	/* Alloc driver data array and TFD circular buffer */
+	/* Driver private data, only for Tx (not command) queues,
+	 * not shared with device. */
+	if (txq_id != priv->cmd_queue) {
+		txq->txb = kzalloc(sizeof(txq->txb[0]) *
+				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+		if (!txq->txb) {
+			IWL_ERR(priv, "kmalloc for auxiliary BD "
+				  "structures failed\n");
+			goto error;
+		}
+	} else {
+		txq->txb = NULL;
+	}
+
+	/* Circular buffer of transmit frame descriptors (TFDs),
+	 * shared with device */
+	txq->tfds = dma_alloc_coherent(priv->bus.dev, tfd_sz, &txq->q.dma_addr,
+				       GFP_KERNEL);
+	if (!txq->tfds) {
+		IWL_ERR(priv, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
+		goto error;
+	}
+	txq->q.id = txq_id;
+
+	return 0;
+error:
+	kfree(txq->txb);
+	txq->txb = NULL;
+	/* since txq->cmd has been zeroed,
+	 * all non allocated cmd[i] will be NULL */
+	if (txq->cmd)
+		for (i = 0; i < slots_num; i++)
+			kfree(txq->cmd[i]);
+	kfree(txq->meta);
+	kfree(txq->cmd);
+	txq->meta = NULL;
+	txq->cmd = NULL;
+
+	return -ENOMEM;
+
+}
+
+static int iwl_trans_txq_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
+		      int slots_num, u32 txq_id)
+{
+	int ret;
+
+	txq->need_update = 0;
+	memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num);
+
+	/*
+	 * For the default queues 0-3, set up the swq_id
+	 * already -- all others need to get one later
+	 * (if they need one at all).
+	 */
+	if (txq_id < 4)
+		iwl_set_swq_id(txq, txq_id, txq_id);
+
+	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+	 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+	/* Initialize queue's high/low-water marks, and head/tail indexes */
+	ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
+			txq_id);
+	if (ret)
+		return ret;
+
+	/*
+	 * Tell nic where to find circular buffer of Tx Frame Descriptors for
+	 * given Tx queue, and enable the DMA channel used for that queue.
+	 * Circular buffer (TFD queue in DRAM) physical base address */
+	iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
+			     txq->q.dma_addr >> 8);
+
+	return 0;
+}
+
+/**
+ * iwl_trans_tx_alloc - allocate TX context
+ * Allocate all Tx DMA structures and initialize them
+ *
+ * @param priv
+ * @return error code
+ */
+static int iwl_trans_tx_alloc(struct iwl_priv *priv)
+{
+	int ret;
+	int txq_id, slots_num;
+
+	/*It is not allowed to alloc twice, so warn when this happens.
+	 * We cannot rely on the previous allocation, so free and fail */
+	if (WARN_ON(priv->txq)) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	ret = iwlagn_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
+				priv->hw_params.scd_bc_tbls_size);
+	if (ret) {
+		IWL_ERR(priv, "Scheduler BC Table allocation failed\n");
+		goto error;
+	}
+
+	/* Alloc keep-warm buffer */
+	ret = iwlagn_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
+	if (ret) {
+		IWL_ERR(priv, "Keep Warm allocation failed\n");
+		goto error;
+	}
+
+	priv->txq = kzalloc(sizeof(struct iwl_tx_queue) *
+			priv->cfg->base_params->num_of_queues, GFP_KERNEL);
+	if (!priv->txq) {
+		IWL_ERR(priv, "Not enough memory for txq\n");
+		ret = ENOMEM;
+		goto error;
+	}
+
+	/* Alloc and init all Tx queues, including the command queue (#4/#9) */
+	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+		slots_num = (txq_id == priv->cmd_queue) ?
+					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+		ret = iwl_trans_txq_alloc(priv, &priv->txq[txq_id], slots_num,
+				       txq_id);
+		if (ret) {
+			IWL_ERR(priv, "Tx %d queue alloc failed\n", txq_id);
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	iwlagn_hw_txq_ctx_free(priv);
+
+	return ret;
+}
+static int iwl_trans_tx_init(struct iwl_priv *priv)
+{
+	int ret;
+	int txq_id, slots_num;
+	unsigned long flags;
+	bool alloc = false;
+
+	if (!priv->txq) {
+		ret = iwl_trans_tx_alloc(priv);
+		if (ret)
+			goto error;
+		alloc = true;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* Turn off all Tx DMA fifos */
+	iwl_write_prph(priv, IWLAGN_SCD_TXFACT, 0);
+
+	/* Tell NIC where to find the "keep warm" buffer */
+	iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Alloc and init all Tx queues, including the command queue (#4/#9) */
+	for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+		slots_num = (txq_id == priv->cmd_queue) ?
+					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+		ret = iwl_trans_txq_init(priv, &priv->txq[txq_id], slots_num,
+				       txq_id);
+		if (ret) {
+			IWL_ERR(priv, "Tx %d queue init failed\n", txq_id);
+			goto error;
+		}
+	}
+
+	return 0;
+error:
+	/*Upon error, free only if we allocated something */
+	if (alloc)
+		iwlagn_hw_txq_ctx_free(priv);
+	return ret;
+}
+
+static const struct iwl_trans_ops trans_ops = {
+	.rx_init = iwl_trans_rx_init,
+	.rx_free = iwl_trans_rx_free,
+
+	.tx_init = iwl_trans_tx_init,
+};
+
+void iwl_trans_register(struct iwl_trans *trans)
+{
+	trans->ops = &trans_ops;
+}

+ 64 - 0
drivers/net/wireless/iwlwifi/iwl-trans.h

@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+void iwl_trans_register(struct iwl_trans *trans);

+ 1 - 138
drivers/net/wireless/iwlwifi/iwl-tx.c

@@ -220,24 +220,6 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
 	return 0;
 	return 0;
 }
 }
 
 
-/*
- * Tell nic where to find circular buffer of Tx Frame Descriptors for
- * given Tx queue, and enable the DMA channel used for that queue.
- *
- * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
- * channels supported in hardware.
- */
-static int iwlagn_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
-{
-	int txq_id = txq->q.id;
-
-	/* Circular buffer (TFD queue in DRAM) physical base address */
-	iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
-			     txq->q.dma_addr >> 8);
-
-	return 0;
-}
-
 /**
 /**
  * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
  * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
  */
  */
@@ -392,11 +374,10 @@ int iwl_queue_space(const struct iwl_queue *q)
 	return s;
 	return s;
 }
 }
 
 
-
 /**
 /**
  * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
  * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
  */
  */
-static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
 			  int count, int slots_num, u32 id)
 			  int count, int slots_num, u32 id)
 {
 {
 	q->n_bd = count;
 	q->n_bd = count;
@@ -426,124 +407,6 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
 	return 0;
 	return 0;
 }
 }
 
 
-/**
- * iwl_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
- */
-static int iwl_tx_queue_alloc(struct iwl_priv *priv,
-			      struct iwl_tx_queue *txq, u32 id)
-{
-	struct device *dev = priv->bus.dev;
-	size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX;
-
-	/* Driver private data, only for Tx (not command) queues,
-	 * not shared with device. */
-	if (id != priv->cmd_queue) {
-		txq->txb = kzalloc(sizeof(txq->txb[0]) *
-				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
-		if (!txq->txb) {
-			IWL_ERR(priv, "kmalloc for auxiliary BD "
-				  "structures failed\n");
-			goto error;
-		}
-	} else {
-		txq->txb = NULL;
-	}
-
-	/* Circular buffer of transmit frame descriptors (TFDs),
-	 * shared with device */
-	txq->tfds = dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr,
-				       GFP_KERNEL);
-	if (!txq->tfds) {
-		IWL_ERR(priv, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
-		goto error;
-	}
-	txq->q.id = id;
-
-	return 0;
-
- error:
-	kfree(txq->txb);
-	txq->txb = NULL;
-
-	return -ENOMEM;
-}
-
-/**
- * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
- */
-int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
-		      int slots_num, u32 txq_id)
-{
-	int i, len;
-	int ret;
-
-	txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * slots_num,
-			    GFP_KERNEL);
-	txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * slots_num,
-			   GFP_KERNEL);
-
-	if (!txq->meta || !txq->cmd)
-		goto out_free_arrays;
-
-	len = sizeof(struct iwl_device_cmd);
-	for (i = 0; i < slots_num; i++) {
-		txq->cmd[i] = kmalloc(len, GFP_KERNEL);
-		if (!txq->cmd[i])
-			goto err;
-	}
-
-	/* Alloc driver data array and TFD circular buffer */
-	ret = iwl_tx_queue_alloc(priv, txq, txq_id);
-	if (ret)
-		goto err;
-
-	txq->need_update = 0;
-
-	/*
-	 * For the default queues 0-3, set up the swq_id
-	 * already -- all others need to get one later
-	 * (if they need one at all).
-	 */
-	if (txq_id < 4)
-		iwl_set_swq_id(txq, txq_id, txq_id);
-
-	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-	 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
-	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
-	/* Initialize queue's high/low-water marks, and head/tail indexes */
-	ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
-	if (ret)
-		return ret;
-
-	/* Tell device where to find queue */
-	iwlagn_tx_queue_init(priv, txq);
-
-	return 0;
-err:
-	for (i = 0; i < slots_num; i++)
-		kfree(txq->cmd[i]);
-out_free_arrays:
-	kfree(txq->meta);
-	kfree(txq->cmd);
-
-	return -ENOMEM;
-}
-
-void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
-			int slots_num, u32 txq_id)
-{
-	memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * slots_num);
-
-	txq->need_update = 0;
-
-	/* Initialize queue's high/low-water marks, and head/tail indexes */
-	iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
-
-	/* Tell device where to find queue */
-	iwlagn_tx_queue_init(priv, txq);
-}
-
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
 
 
 /**
 /**

+ 2 - 2
drivers/net/wireless/mwifiex/sdio.h

@@ -54,10 +54,10 @@
 
 
 #define SDIO_MP_AGGR_DEF_PKT_LIMIT	8
 #define SDIO_MP_AGGR_DEF_PKT_LIMIT	8
 
 
-#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE        (4096)	/* 4K */
+#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE        (8192)	/* 8K */
 
 
 /* Multi port RX aggregation buffer size */
 /* Multi port RX aggregation buffer size */
-#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE        (4096)	/* 4K */
+#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE        (16384)	/* 16K */
 
 
 /* Misc. Config Register : Auto Re-enable interrupts */
 /* Misc. Config Register : Auto Re-enable interrupts */
 #define AUTO_RE_ENABLE_INT              BIT(4)
 #define AUTO_RE_ENABLE_INT              BIT(4)

+ 1 - 0
drivers/net/wireless/rt2x00/rt2400pci.c

@@ -1723,6 +1723,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
 	.set_antenna		= rt2x00mac_set_antenna,
 	.set_antenna		= rt2x00mac_set_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_ringparam		= rt2x00mac_get_ringparam,
 	.get_ringparam		= rt2x00mac_get_ringparam,
+	.tx_frames_pending	= rt2x00mac_tx_frames_pending,
 };
 };
 
 
 static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
 static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {

+ 1 - 0
drivers/net/wireless/rt2x00/rt2500pci.c

@@ -2016,6 +2016,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
 	.set_antenna		= rt2x00mac_set_antenna,
 	.set_antenna		= rt2x00mac_set_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_ringparam		= rt2x00mac_get_ringparam,
 	.get_ringparam		= rt2x00mac_get_ringparam,
+	.tx_frames_pending	= rt2x00mac_tx_frames_pending,
 };
 };
 
 
 static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
 static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {

+ 1 - 0
drivers/net/wireless/rt2x00/rt2500usb.c

@@ -1827,6 +1827,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
 	.set_antenna		= rt2x00mac_set_antenna,
 	.set_antenna		= rt2x00mac_set_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_ringparam		= rt2x00mac_get_ringparam,
 	.get_ringparam		= rt2x00mac_get_ringparam,
+	.tx_frames_pending	= rt2x00mac_tx_frames_pending,
 };
 };
 
 
 static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
 static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {

+ 2 - 0
drivers/net/wireless/rt2x00/rt2800pci.c

@@ -1031,6 +1031,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
 	.flush			= rt2x00mac_flush,
 	.flush			= rt2x00mac_flush,
 	.get_survey		= rt2800_get_survey,
 	.get_survey		= rt2800_get_survey,
 	.get_ringparam		= rt2x00mac_get_ringparam,
 	.get_ringparam		= rt2x00mac_get_ringparam,
+	.tx_frames_pending	= rt2x00mac_tx_frames_pending,
 };
 };
 
 
 static const struct rt2800_ops rt2800pci_rt2800_ops = {
 static const struct rt2800_ops rt2800pci_rt2800_ops = {
@@ -1160,6 +1161,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
 #endif
 #endif
 #ifdef CONFIG_RT2800PCI_RT53XX
 #ifdef CONFIG_RT2800PCI_RT53XX
 	{ PCI_DEVICE(0x1814, 0x5390) },
 	{ PCI_DEVICE(0x1814, 0x5390) },
+	{ PCI_DEVICE(0x1814, 0x539f) },
 #endif
 #endif
 	{ 0, }
 	{ 0, }
 };
 };

+ 3 - 2
drivers/net/wireless/rt2x00/rt2800usb.c

@@ -757,6 +757,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
 	.flush			= rt2x00mac_flush,
 	.flush			= rt2x00mac_flush,
 	.get_survey		= rt2800_get_survey,
 	.get_survey		= rt2800_get_survey,
 	.get_ringparam		= rt2x00mac_get_ringparam,
 	.get_ringparam		= rt2x00mac_get_ringparam,
+	.tx_frames_pending	= rt2x00mac_tx_frames_pending,
 };
 };
 
 
 static const struct rt2800_ops rt2800usb_rt2800_ops = {
 static const struct rt2800_ops rt2800usb_rt2800_ops = {
@@ -1020,6 +1021,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x0df6, 0x0048) },
 	{ USB_DEVICE(0x0df6, 0x0048) },
 	{ USB_DEVICE(0x0df6, 0x0051) },
 	{ USB_DEVICE(0x0df6, 0x0051) },
 	{ USB_DEVICE(0x0df6, 0x005f) },
 	{ USB_DEVICE(0x0df6, 0x005f) },
+	{ USB_DEVICE(0x0df6, 0x0060) },
 	/* SMC */
 	/* SMC */
 	{ USB_DEVICE(0x083a, 0x6618) },
 	{ USB_DEVICE(0x083a, 0x6618) },
 	{ USB_DEVICE(0x083a, 0x7511) },
 	{ USB_DEVICE(0x083a, 0x7511) },
@@ -1076,6 +1078,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x148f, 0x3572) },
 	{ USB_DEVICE(0x148f, 0x3572) },
 	/* Sitecom */
 	/* Sitecom */
 	{ USB_DEVICE(0x0df6, 0x0041) },
 	{ USB_DEVICE(0x0df6, 0x0041) },
+	{ USB_DEVICE(0x0df6, 0x0062) },
 	/* Toshiba */
 	/* Toshiba */
 	{ USB_DEVICE(0x0930, 0x0a07) },
 	{ USB_DEVICE(0x0930, 0x0a07) },
 	/* Zinwell */
 	/* Zinwell */
@@ -1174,8 +1177,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
 	{ USB_DEVICE(0x0df6, 0x004a) },
 	{ USB_DEVICE(0x0df6, 0x004a) },
 	{ USB_DEVICE(0x0df6, 0x004d) },
 	{ USB_DEVICE(0x0df6, 0x004d) },
 	{ USB_DEVICE(0x0df6, 0x0053) },
 	{ USB_DEVICE(0x0df6, 0x0053) },
-	{ USB_DEVICE(0x0df6, 0x0060) },
-	{ USB_DEVICE(0x0df6, 0x0062) },
 	/* SMC */
 	/* SMC */
 	{ USB_DEVICE(0x083a, 0xa512) },
 	{ USB_DEVICE(0x083a, 0xa512) },
 	{ USB_DEVICE(0x083a, 0xc522) },
 	{ USB_DEVICE(0x083a, 0xc522) },

+ 1 - 0
drivers/net/wireless/rt2x00/rt2x00.h

@@ -1277,6 +1277,7 @@ int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
 int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
 int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
 void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
 void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
 			     u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
 			     u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
+bool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw);
 
 
 /*
 /*
  * Driver allocation handlers.
  * Driver allocation handlers.

+ 3 - 3
drivers/net/wireless/rt2x00/rt2x00crypto.c

@@ -45,11 +45,11 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
 	}
 	}
 }
 }
 
 
-void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
+void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
+				       struct sk_buff *skb,
 				       struct txentry_desc *txdesc)
 				       struct txentry_desc *txdesc)
 {
 {
-	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
 	struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
 
 
 	if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key)
 	if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key)

+ 2 - 1
drivers/net/wireless/rt2x00/rt2x00lib.h

@@ -336,7 +336,8 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
  */
  */
 #ifdef CONFIG_RT2X00_LIB_CRYPTO
 #ifdef CONFIG_RT2X00_LIB_CRYPTO
 enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key);
 enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key);
-void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
+void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
+				       struct sk_buff *skb,
 				       struct txentry_desc *txdesc);
 				       struct txentry_desc *txdesc);
 unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
 unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
 				      struct sk_buff *skb);
 				      struct sk_buff *skb);

+ 14 - 0
drivers/net/wireless/rt2x00/rt2x00mac.c

@@ -818,3 +818,17 @@ void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
 	*rx_max = rt2x00dev->rx->limit;
 	*rx_max = rt2x00dev->rx->limit;
 }
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam);
 EXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam);
+
+bool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct data_queue *queue;
+
+	tx_queue_for_each(rt2x00dev, queue) {
+		if (!rt2x00queue_empty(queue))
+			return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_tx_frames_pending);

+ 62 - 46
drivers/net/wireless/rt2x00/rt2x00queue.c

@@ -200,11 +200,12 @@ void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
 	skb_pull(skb, l2pad);
 	skb_pull(skb, l2pad);
 }
 }
 
 
-static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
+static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
+						 struct sk_buff *skb,
 						 struct txentry_desc *txdesc)
 						 struct txentry_desc *txdesc)
 {
 {
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
 	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
 
 
 	if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
 	if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
@@ -212,7 +213,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
 
 
 	__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
 	__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
 
 
-	if (!test_bit(REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->cap_flags))
+	if (!test_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags))
 		return;
 		return;
 
 
 	/*
 	/*
@@ -237,12 +238,12 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
 
 
 }
 }
 
 
-static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry,
+static void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev,
+						  struct sk_buff *skb,
 						  struct txentry_desc *txdesc,
 						  struct txentry_desc *txdesc,
 						  const struct rt2x00_rate *hwrate)
 						  const struct rt2x00_rate *hwrate)
 {
 {
-	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
 	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
 	unsigned int data_length;
 	unsigned int data_length;
 	unsigned int duration;
 	unsigned int duration;
@@ -259,8 +260,8 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry,
 		txdesc->u.plcp.ifs = IFS_SIFS;
 		txdesc->u.plcp.ifs = IFS_SIFS;
 
 
 	/* Data length + CRC + Crypto overhead (IV/EIV/ICV/MIC) */
 	/* Data length + CRC + Crypto overhead (IV/EIV/ICV/MIC) */
-	data_length = entry->skb->len + 4;
-	data_length += rt2x00crypto_tx_overhead(rt2x00dev, entry->skb);
+	data_length = skb->len + 4;
+	data_length += rt2x00crypto_tx_overhead(rt2x00dev, skb);
 
 
 	/*
 	/*
 	 * PLCP setup
 	 * PLCP setup
@@ -301,13 +302,14 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry,
 	}
 	}
 }
 }
 
 
-static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry,
+static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev,
+						struct sk_buff *skb,
 						struct txentry_desc *txdesc,
 						struct txentry_desc *txdesc,
 						const struct rt2x00_rate *hwrate)
 						const struct rt2x00_rate *hwrate)
 {
 {
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
 	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
 
 	if (tx_info->control.sta)
 	if (tx_info->control.sta)
 		txdesc->u.ht.mpdu_density =
 		txdesc->u.ht.mpdu_density =
@@ -380,12 +382,12 @@ static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry,
 		txdesc->u.ht.txop = TXOP_HTTXOP;
 		txdesc->u.ht.txop = TXOP_HTTXOP;
 }
 }
 
 
-static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
+static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
+					     struct sk_buff *skb,
 					     struct txentry_desc *txdesc)
 					     struct txentry_desc *txdesc)
 {
 {
-	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
 	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
 	struct ieee80211_rate *rate;
 	struct ieee80211_rate *rate;
 	const struct rt2x00_rate *hwrate = NULL;
 	const struct rt2x00_rate *hwrate = NULL;
@@ -395,8 +397,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 	/*
 	/*
 	 * Header and frame information.
 	 * Header and frame information.
 	 */
 	 */
-	txdesc->length = entry->skb->len;
-	txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
+	txdesc->length = skb->len;
+	txdesc->header_length = ieee80211_get_hdrlen_from_skb(skb);
 
 
 	/*
 	/*
 	 * Check whether this frame is to be acked.
 	 * Check whether this frame is to be acked.
@@ -471,13 +473,15 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 	/*
 	/*
 	 * Apply TX descriptor handling by components
 	 * Apply TX descriptor handling by components
 	 */
 	 */
-	rt2x00crypto_create_tx_descriptor(entry, txdesc);
-	rt2x00queue_create_tx_descriptor_seq(entry, txdesc);
+	rt2x00crypto_create_tx_descriptor(rt2x00dev, skb, txdesc);
+	rt2x00queue_create_tx_descriptor_seq(rt2x00dev, skb, txdesc);
 
 
 	if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags))
 	if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags))
-		rt2x00queue_create_tx_descriptor_ht(entry, txdesc, hwrate);
+		rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc,
+						    hwrate);
 	else
 	else
-		rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate);
+		rt2x00queue_create_tx_descriptor_plcp(rt2x00dev, skb, txdesc,
+						      hwrate);
 }
 }
 
 
 static int rt2x00queue_write_tx_data(struct queue_entry *entry,
 static int rt2x00queue_write_tx_data(struct queue_entry *entry,
@@ -555,33 +559,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
 			       bool local)
 			       bool local)
 {
 {
 	struct ieee80211_tx_info *tx_info;
 	struct ieee80211_tx_info *tx_info;
-	struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
+	struct queue_entry *entry;
 	struct txentry_desc txdesc;
 	struct txentry_desc txdesc;
 	struct skb_frame_desc *skbdesc;
 	struct skb_frame_desc *skbdesc;
 	u8 rate_idx, rate_flags;
 	u8 rate_idx, rate_flags;
-
-	if (unlikely(rt2x00queue_full(queue))) {
-		ERROR(queue->rt2x00dev,
-		      "Dropping frame due to full tx queue %d.\n", queue->qid);
-		return -ENOBUFS;
-	}
-
-	if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA,
-				      &entry->flags))) {
-		ERROR(queue->rt2x00dev,
-		      "Arrived at non-free entry in the non-full queue %d.\n"
-		      "Please file bug report to %s.\n",
-		      queue->qid, DRV_PROJECT);
-		return -EINVAL;
-	}
+	int ret = 0;
 
 
 	/*
 	/*
 	 * Copy all TX descriptor information into txdesc,
 	 * Copy all TX descriptor information into txdesc,
 	 * after that we are free to use the skb->cb array
 	 * after that we are free to use the skb->cb array
 	 * for our information.
 	 * for our information.
 	 */
 	 */
-	entry->skb = skb;
-	rt2x00queue_create_tx_descriptor(entry, &txdesc);
+	rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc);
 
 
 	/*
 	/*
 	 * All information is retrieved from the skb->cb array,
 	 * All information is retrieved from the skb->cb array,
@@ -593,7 +582,6 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
 	rate_flags = tx_info->control.rates[0].flags;
 	rate_flags = tx_info->control.rates[0].flags;
 	skbdesc = get_skb_frame_desc(skb);
 	skbdesc = get_skb_frame_desc(skb);
 	memset(skbdesc, 0, sizeof(*skbdesc));
 	memset(skbdesc, 0, sizeof(*skbdesc));
-	skbdesc->entry = entry;
 	skbdesc->tx_rate_idx = rate_idx;
 	skbdesc->tx_rate_idx = rate_idx;
 	skbdesc->tx_rate_flags = rate_flags;
 	skbdesc->tx_rate_flags = rate_flags;
 
 
@@ -622,9 +610,33 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
 	 * for PCI devices.
 	 * for PCI devices.
 	 */
 	 */
 	if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags))
 	if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags))
-		rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length);
+		rt2x00queue_insert_l2pad(skb, txdesc.header_length);
 	else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags))
 	else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags))
-		rt2x00queue_align_frame(entry->skb);
+		rt2x00queue_align_frame(skb);
+
+	spin_lock(&queue->tx_lock);
+
+	if (unlikely(rt2x00queue_full(queue))) {
+		ERROR(queue->rt2x00dev,
+		      "Dropping frame due to full tx queue %d.\n", queue->qid);
+		ret = -ENOBUFS;
+		goto out;
+	}
+
+	entry = rt2x00queue_get_entry(queue, Q_INDEX);
+
+	if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA,
+				      &entry->flags))) {
+		ERROR(queue->rt2x00dev,
+		      "Arrived at non-free entry in the non-full queue %d.\n"
+		      "Please file bug report to %s.\n",
+		      queue->qid, DRV_PROJECT);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	skbdesc->entry = entry;
+	entry->skb = skb;
 
 
 	/*
 	/*
 	 * It could be possible that the queue was corrupted and this
 	 * It could be possible that the queue was corrupted and this
@@ -634,7 +646,8 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
 	if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) {
 	if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) {
 		clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
 		clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
 		entry->skb = NULL;
 		entry->skb = NULL;
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 	}
 
 
 	set_bit(ENTRY_DATA_PENDING, &entry->flags);
 	set_bit(ENTRY_DATA_PENDING, &entry->flags);
@@ -643,7 +656,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
 	rt2x00queue_write_tx_descriptor(entry, &txdesc);
 	rt2x00queue_write_tx_descriptor(entry, &txdesc);
 	rt2x00queue_kick_tx_queue(queue, &txdesc);
 	rt2x00queue_kick_tx_queue(queue, &txdesc);
 
 
-	return 0;
+out:
+	spin_unlock(&queue->tx_lock);
+	return ret;
 }
 }
 
 
 int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
 int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
@@ -697,7 +712,7 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
 	 * after that we are free to use the skb->cb array
 	 * after that we are free to use the skb->cb array
 	 * for our information.
 	 * for our information.
 	 */
 	 */
-	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
+	rt2x00queue_create_tx_descriptor(rt2x00dev, intf->beacon->skb, &txdesc);
 
 
 	/*
 	/*
 	 * Fill in skb descriptor
 	 * Fill in skb descriptor
@@ -1184,6 +1199,7 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
 			     struct data_queue *queue, enum data_queue_qid qid)
 			     struct data_queue *queue, enum data_queue_qid qid)
 {
 {
 	mutex_init(&queue->status_lock);
 	mutex_init(&queue->status_lock);
+	spin_lock_init(&queue->tx_lock);
 	spin_lock_init(&queue->index_lock);
 	spin_lock_init(&queue->index_lock);
 
 
 	queue->rt2x00dev = rt2x00dev;
 	queue->rt2x00dev = rt2x00dev;

+ 2 - 0
drivers/net/wireless/rt2x00/rt2x00queue.h

@@ -432,6 +432,7 @@ enum data_queue_flags {
  * @flags: Entry flags, see &enum queue_entry_flags.
  * @flags: Entry flags, see &enum queue_entry_flags.
  * @status_lock: The mutex for protecting the start/stop/flush
  * @status_lock: The mutex for protecting the start/stop/flush
  *	handling on this queue.
  *	handling on this queue.
+ * @tx_lock: Spinlock to serialize tx operations on this queue.
  * @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or
  * @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or
  *	@index_crypt needs to be changed this lock should be grabbed to prevent
  *	@index_crypt needs to be changed this lock should be grabbed to prevent
  *	index corruption due to concurrency.
  *	index corruption due to concurrency.
@@ -458,6 +459,7 @@ struct data_queue {
 	unsigned long flags;
 	unsigned long flags;
 
 
 	struct mutex status_lock;
 	struct mutex status_lock;
+	spinlock_t tx_lock;
 	spinlock_t index_lock;
 	spinlock_t index_lock;
 
 
 	unsigned int count;
 	unsigned int count;

+ 1 - 0
drivers/net/wireless/rt2x00/rt61pci.c

@@ -2982,6 +2982,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
 	.set_antenna		= rt2x00mac_set_antenna,
 	.set_antenna		= rt2x00mac_set_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_ringparam		= rt2x00mac_get_ringparam,
 	.get_ringparam		= rt2x00mac_get_ringparam,
+	.tx_frames_pending	= rt2x00mac_tx_frames_pending,
 };
 };
 
 
 static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
 static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {

+ 1 - 0
drivers/net/wireless/rt2x00/rt73usb.c

@@ -2314,6 +2314,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
 	.set_antenna		= rt2x00mac_set_antenna,
 	.set_antenna		= rt2x00mac_set_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_antenna		= rt2x00mac_get_antenna,
 	.get_ringparam		= rt2x00mac_get_ringparam,
 	.get_ringparam		= rt2x00mac_get_ringparam,
+	.tx_frames_pending	= rt2x00mac_tx_frames_pending,
 };
 };
 
 
 static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
 static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {

+ 0 - 4
drivers/net/wireless/rtlwifi/pci.c

@@ -788,15 +788,11 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
 {
 {
 	struct ieee80211_hw *hw = dev_id;
 	struct ieee80211_hw *hw = dev_id;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	unsigned long flags;
 	unsigned long flags;
 	u32 inta = 0;
 	u32 inta = 0;
 	u32 intb = 0;
 	u32 intb = 0;
 
 
-	if (rtlpci->irq_enabled == 0)
-		return IRQ_HANDLED;
-
 	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 
 
 	/*read ISR: 4/8bytes */
 	/*read ISR: 4/8bytes */

+ 0 - 1
drivers/net/wireless/rtlwifi/pci.h

@@ -158,7 +158,6 @@ struct rtl_pci {
 	bool first_init;
 	bool first_init;
 	bool being_init_adapter;
 	bool being_init_adapter;
 	bool init_ready;
 	bool init_ready;
-	bool irq_enabled;
 
 
 	/*Tx */
 	/*Tx */
 	struct rtl8192_tx_ring tx_ring[RTL_PCI_MAX_TX_QUEUE_COUNT];
 	struct rtl8192_tx_ring tx_ring[RTL_PCI_MAX_TX_QUEUE_COUNT];

+ 0 - 2
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c

@@ -1183,7 +1183,6 @@ void rtl92ce_enable_interrupt(struct ieee80211_hw *hw)
 
 
 	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
 	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
 	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
 	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
-	rtlpci->irq_enabled = true;
 }
 }
 
 
 void rtl92ce_disable_interrupt(struct ieee80211_hw *hw)
 void rtl92ce_disable_interrupt(struct ieee80211_hw *hw)
@@ -1193,7 +1192,6 @@ void rtl92ce_disable_interrupt(struct ieee80211_hw *hw)
 
 
 	rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
-	rtlpci->irq_enabled = false;
 	synchronize_irq(rtlpci->pdev->irq);
 	synchronize_irq(rtlpci->pdev->irq);
 }
 }
 
 

+ 0 - 9
drivers/net/wireless/rtlwifi/rtl8192cu/mac.c

@@ -380,13 +380,11 @@ void rtl92c_enable_interrupt(struct ieee80211_hw *hw)
 				0xFFFFFFFF);
 				0xFFFFFFFF);
 		rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] &
 		rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] &
 				0xFFFFFFFF);
 				0xFFFFFFFF);
-		rtlpci->irq_enabled = true;
 	} else {
 	} else {
 		rtl_write_dword(rtlpriv, REG_HIMR, rtlusb->irq_mask[0] &
 		rtl_write_dword(rtlpriv, REG_HIMR, rtlusb->irq_mask[0] &
 				0xFFFFFFFF);
 				0xFFFFFFFF);
 		rtl_write_dword(rtlpriv, REG_HIMRE, rtlusb->irq_mask[1] &
 		rtl_write_dword(rtlpriv, REG_HIMRE, rtlusb->irq_mask[1] &
 				0xFFFFFFFF);
 				0xFFFFFFFF);
-		rtlusb->irq_enabled = true;
 	}
 	}
 }
 }
 
 
@@ -398,16 +396,9 @@ void rtl92c_init_interrupt(struct ieee80211_hw *hw)
 void rtl92c_disable_interrupt(struct ieee80211_hw *hw)
 void rtl92c_disable_interrupt(struct ieee80211_hw *hw)
 {
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
 
 
 	rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
-	if (IS_HARDWARE_TYPE_8192CE(rtlhal))
-		rtlpci->irq_enabled = false;
-	else if (IS_HARDWARE_TYPE_8192CU(rtlhal))
-		rtlusb->irq_enabled = false;
 }
 }
 
 
 void rtl92c_set_qos(struct ieee80211_hw *hw, int aci)
 void rtl92c_set_qos(struct ieee80211_hw *hw, int aci)

+ 11 - 8
drivers/net/wireless/rtlwifi/rtl8192de/hw.c

@@ -449,7 +449,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	case HW_VAR_CORRECT_TSF: {
 	case HW_VAR_CORRECT_TSF: {
 		u8 btype_ibss = ((u8 *) (val))[0];
 		u8 btype_ibss = ((u8 *) (val))[0];
 
 
-		if (btype_ibss == true)
+		if (btype_ibss)
 			_rtl92de_stop_tx_beacon(hw);
 			_rtl92de_stop_tx_beacon(hw);
 		_rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(3));
 		_rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(3));
 		rtl_write_dword(rtlpriv, REG_TSFTR,
 		rtl_write_dword(rtlpriv, REG_TSFTR,
@@ -457,7 +457,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 		rtl_write_dword(rtlpriv, REG_TSFTR + 4,
 		rtl_write_dword(rtlpriv, REG_TSFTR + 4,
 				(u32) ((mac->tsf >> 32) & 0xffffffff));
 				(u32) ((mac->tsf >> 32) & 0xffffffff));
 		_rtl92de_set_bcn_ctrl_reg(hw, BIT(3), 0);
 		_rtl92de_set_bcn_ctrl_reg(hw, BIT(3), 0);
-		if (btype_ibss == true)
+		if (btype_ibss)
 			_rtl92de_resume_tx_beacon(hw);
 			_rtl92de_resume_tx_beacon(hw);
 
 
 		break;
 		break;
@@ -932,8 +932,8 @@ int rtl92de_hw_init(struct ieee80211_hw *hw)
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 ("Failed to download FW. Init HW "
 			 ("Failed to download FW. Init HW "
 			 "without FW..\n"));
 			 "without FW..\n"));
-		err = 1;
 		rtlhal->fw_ready = false;
 		rtlhal->fw_ready = false;
+		return 1;
 	} else {
 	} else {
 		rtlhal->fw_ready = true;
 		rtlhal->fw_ready = true;
 	}
 	}
@@ -1044,6 +1044,11 @@ int rtl92de_hw_init(struct ieee80211_hw *hw)
 				if (((tmp_rega & BIT(11)) == BIT(11)))
 				if (((tmp_rega & BIT(11)) == BIT(11)))
 					break;
 					break;
 			}
 			}
+			/* check that loop was successful. If not, exit now */
+			if (i == 10000) {
+				rtlpci->init_ready = false;
+				return 1;
+			}
 		}
 		}
 	}
 	}
 	rtlpci->init_ready = true;
 	rtlpci->init_ready = true;
@@ -1142,7 +1147,7 @@ void rtl92de_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 
 
 	if (rtlpriv->psc.rfpwr_state != ERFON)
 	if (rtlpriv->psc.rfpwr_state != ERFON)
 		return;
 		return;
-	if (check_bssid == true) {
+	if (check_bssid) {
 		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
 		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
 		_rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(4));
 		_rtl92de_set_bcn_ctrl_reg(hw, 0, BIT(4));
@@ -1221,7 +1226,6 @@ void rtl92de_enable_interrupt(struct ieee80211_hw *hw)
 
 
 	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
 	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
 	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
 	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
-	rtlpci->irq_enabled = true;
 }
 }
 
 
 void rtl92de_disable_interrupt(struct ieee80211_hw *hw)
 void rtl92de_disable_interrupt(struct ieee80211_hw *hw)
@@ -1231,7 +1235,6 @@ void rtl92de_disable_interrupt(struct ieee80211_hw *hw)
 
 
 	rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
-	rtlpci->irq_enabled = false;
 	synchronize_irq(rtlpci->pdev->irq);
 	synchronize_irq(rtlpci->pdev->irq);
 }
 }
 
 
@@ -1787,7 +1790,7 @@ static void _rtl92de_read_adapter_info(struct ieee80211_hw *hw)
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n"));
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n"));
 		rtlefuse->autoload_failflag = false;
 		rtlefuse->autoload_failflag = false;
 	}
 	}
-	if (rtlefuse->autoload_failflag == true) {
+	if (rtlefuse->autoload_failflag) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 ("RTL819X Not boot from eeprom, check it !!"));
 			 ("RTL819X Not boot from eeprom, check it !!"));
 		return;
 		return;
@@ -2149,7 +2152,7 @@ bool rtl92de_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
 			  REG_MAC_PINMUX_CFG) & ~(BIT(3)));
 			  REG_MAC_PINMUX_CFG) & ~(BIT(3)));
 	u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL);
 	u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL);
 	e_rfpowerstate_toset = (u1tmp & BIT(3)) ? ERFON : ERFOFF;
 	e_rfpowerstate_toset = (u1tmp & BIT(3)) ? ERFON : ERFOFF;
-	if ((ppsc->hwradiooff == true) && (e_rfpowerstate_toset == ERFON)) {
+	if (ppsc->hwradiooff && (e_rfpowerstate_toset == ERFON)) {
 		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 			 ("GPIOChangeRF  - HW Radio ON, RF ON\n"));
 			 ("GPIOChangeRF  - HW Radio ON, RF ON\n"));
 		e_rfpowerstate_toset = ERFON;
 		e_rfpowerstate_toset = ERFON;

+ 1 - 1
drivers/net/wireless/rtlwifi/rtl8192de/led.c

@@ -93,7 +93,7 @@ void rtl92de_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
 		break;
 		break;
 	case LED_PIN_LED0:
 	case LED_PIN_LED0:
 		ledcfg &= 0xf0;
 		ledcfg &= 0xf0;
-		if (pcipriv->ledctl.led_opendrain == true)
+		if (pcipriv->ledctl.led_opendrain)
 			rtl_write_byte(rtlpriv, REG_LEDCFG2,
 			rtl_write_byte(rtlpriv, REG_LEDCFG2,
 				       (ledcfg | BIT(1) | BIT(5) | BIT(6)));
 				       (ledcfg | BIT(1) | BIT(5) | BIT(6)));
 		else
 		else

+ 12 - 18
drivers/net/wireless/rtlwifi/rtl8192de/phy.c

@@ -932,7 +932,7 @@ bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 					  enum rf_content content,
 					  enum rf_content content,
 					  enum radio_path rfpath)
 					  enum radio_path rfpath)
 {
 {
-	int i, j;
+	int i;
 	u32 *radioa_array_table;
 	u32 *radioa_array_table;
 	u32 *radiob_array_table;
 	u32 *radiob_array_table;
 	u16 radioa_arraylen, radiob_arraylen;
 	u16 radioa_arraylen, radiob_arraylen;
@@ -974,13 +974,10 @@ bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 				mdelay(50);
 				mdelay(50);
 			} else if (radioa_array_table[i] == 0xfd) {
 			} else if (radioa_array_table[i] == 0xfd) {
 				/* delay_ms(5); */
 				/* delay_ms(5); */
-				for (j = 0; j < 100; j++)
-					udelay(MAX_STALL_TIME);
+				mdelay(5);
 			} else if (radioa_array_table[i] == 0xfc) {
 			} else if (radioa_array_table[i] == 0xfc) {
 				/* delay_ms(1); */
 				/* delay_ms(1); */
-				for (j = 0; j < 20; j++)
-					udelay(MAX_STALL_TIME);
-
+				mdelay(1);
 			} else if (radioa_array_table[i] == 0xfb) {
 			} else if (radioa_array_table[i] == 0xfb) {
 				udelay(50);
 				udelay(50);
 			} else if (radioa_array_table[i] == 0xfa) {
 			} else if (radioa_array_table[i] == 0xfa) {
@@ -1004,12 +1001,10 @@ bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 				mdelay(50);
 				mdelay(50);
 			} else if (radiob_array_table[i] == 0xfd) {
 			} else if (radiob_array_table[i] == 0xfd) {
 				/* delay_ms(5); */
 				/* delay_ms(5); */
-				for (j = 0; j < 100; j++)
-					udelay(MAX_STALL_TIME);
+				mdelay(5);
 			} else if (radiob_array_table[i] == 0xfc) {
 			} else if (radiob_array_table[i] == 0xfc) {
 				/* delay_ms(1); */
 				/* delay_ms(1); */
-				for (j = 0; j < 20; j++)
-					udelay(MAX_STALL_TIME);
+				mdelay(1);
 			} else if (radiob_array_table[i] == 0xfb) {
 			} else if (radiob_array_table[i] == 0xfb) {
 				udelay(50);
 				udelay(50);
 			} else if (radiob_array_table[i] == 0xfa) {
 			} else if (radiob_array_table[i] == 0xfa) {
@@ -1276,7 +1271,7 @@ static void rtl92d_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band)
 {
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u8 i, value8;
+	u8 value8;
 
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("==>\n"));
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("==>\n"));
 	rtlhal->bandset = band;
 	rtlhal->bandset = band;
@@ -1321,8 +1316,7 @@ static void rtl92d_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band)
 		rtl_write_byte(rtlpriv, (rtlhal->interfaceindex ==
 		rtl_write_byte(rtlpriv, (rtlhal->interfaceindex ==
 			0 ? REG_MAC0 : REG_MAC1), value8);
 			0 ? REG_MAC0 : REG_MAC1), value8);
 	}
 	}
-	for (i = 0; i < 20; i++)
-		udelay(MAX_STALL_TIME);
+	mdelay(1);
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("<==Switch Band OK.\n"));
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("<==Switch Band OK.\n"));
 }
 }
 
 
@@ -1684,7 +1678,7 @@ static u8 _rtl92d_phy_patha_iqk(struct ieee80211_hw *hw, bool configpathb)
 	RTPRINT(rtlpriv, FINIT, INIT_IQK,
 	RTPRINT(rtlpriv, FINIT, INIT_IQK,
 		("Delay %d ms for One shot, path A LOK & IQK.\n",
 		("Delay %d ms for One shot, path A LOK & IQK.\n",
 		IQK_DELAY_TIME));
 		IQK_DELAY_TIME));
-	udelay(IQK_DELAY_TIME * 1000);
+	mdelay(IQK_DELAY_TIME);
 	/* Check failed */
 	/* Check failed */
 	regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
 	regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
 	RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac));
 	RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac));
@@ -1755,7 +1749,7 @@ static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw,
 		RTPRINT(rtlpriv, FINIT, INIT_IQK,
 		RTPRINT(rtlpriv, FINIT, INIT_IQK,
 			("Delay %d ms for One shot, path A LOK & IQK.\n",
 			("Delay %d ms for One shot, path A LOK & IQK.\n",
 			IQK_DELAY_TIME));
 			IQK_DELAY_TIME));
-		udelay(IQK_DELAY_TIME * 1000 * 10);
+		mdelay(IQK_DELAY_TIME * 10);
 		/* Check failed */
 		/* Check failed */
 		regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
 		regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
 		RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac));
 		RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac));
@@ -1808,7 +1802,7 @@ static u8 _rtl92d_phy_pathb_iqk(struct ieee80211_hw *hw)
 	RTPRINT(rtlpriv, FINIT, INIT_IQK,
 	RTPRINT(rtlpriv, FINIT, INIT_IQK,
 		("Delay %d ms for One shot, path B LOK & IQK.\n",
 		("Delay %d ms for One shot, path B LOK & IQK.\n",
 		IQK_DELAY_TIME));
 		IQK_DELAY_TIME));
-	udelay(IQK_DELAY_TIME * 1000);
+	mdelay(IQK_DELAY_TIME);
 	/* Check failed */
 	/* Check failed */
 	regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
 	regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
 	RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac));
 	RTPRINT(rtlpriv, FINIT, INIT_IQK, ("0xeac = 0x%x\n", regeac));
@@ -1875,7 +1869,7 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw)
 		/* delay x ms */
 		/* delay x ms */
 		RTPRINT(rtlpriv, FINIT, INIT_IQK,
 		RTPRINT(rtlpriv, FINIT, INIT_IQK,
 			("Delay %d ms for One shot, path B LOK & IQK.\n", 10));
 			("Delay %d ms for One shot, path B LOK & IQK.\n", 10));
-		udelay(IQK_DELAY_TIME * 1000 * 10);
+		mdelay(IQK_DELAY_TIME * 10);
 
 
 		/* Check failed */
 		/* Check failed */
 		regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
 		regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD);
@@ -2206,7 +2200,7 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw,
 	 * PHY_REG.txt , and radio_a, radio_b.txt */
 	 * PHY_REG.txt , and radio_a, radio_b.txt */
 
 
 	RTPRINT(rtlpriv, FINIT, INIT_IQK, ("IQK for 5G NORMAL:Start!!!\n"));
 	RTPRINT(rtlpriv, FINIT, INIT_IQK, ("IQK for 5G NORMAL:Start!!!\n"));
-	udelay(IQK_DELAY_TIME * 1000 * 20);
+	mdelay(IQK_DELAY_TIME * 20);
 	if (t == 0) {
 	if (t == 0) {
 		bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD);
 		bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD);
 		RTPRINT(rtlpriv, FINIT, INIT_IQK, ("==>0x%08x\n", bbvalue));
 		RTPRINT(rtlpriv, FINIT, INIT_IQK, ("==>0x%08x\n", bbvalue));

+ 8 - 8
drivers/net/wireless/rtlwifi/rtl8192de/rf.c

@@ -87,7 +87,7 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
 
 
 	if (rtlefuse->eeprom_regulatory != 0)
 	if (rtlefuse->eeprom_regulatory != 0)
 		turbo_scanoff = true;
 		turbo_scanoff = true;
-	if (mac->act_scanning == true) {
+	if (mac->act_scanning) {
 		tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
 		tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
 		tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
 		tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
 		if (turbo_scanoff) {
 		if (turbo_scanoff) {
@@ -416,9 +416,9 @@ bool rtl92d_phy_enable_anotherphy(struct ieee80211_hw *hw, bool bmac0)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
 	struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
 	u8 u1btmp;
 	u8 u1btmp;
-	u8 direct = bmac0 == true ? BIT(3) | BIT(2) : BIT(3);
-	u8 mac_reg = bmac0 == true ? REG_MAC1 : REG_MAC0;
-	u8 mac_on_bit = bmac0 == true ? MAC1_ON : MAC0_ON;
+	u8 direct = bmac0 ? BIT(3) | BIT(2) : BIT(3);
+	u8 mac_reg = bmac0 ? REG_MAC1 : REG_MAC0;
+	u8 mac_on_bit = bmac0 ? MAC1_ON : MAC0_ON;
 	bool bresult = true; /* true: need to enable BB/RF power */
 	bool bresult = true; /* true: need to enable BB/RF power */
 
 
 	rtlhal->during_mac0init_radiob = false;
 	rtlhal->during_mac0init_radiob = false;
@@ -447,9 +447,9 @@ void rtl92d_phy_powerdown_anotherphy(struct ieee80211_hw *hw, bool bmac0)
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
 	struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
 	u8 u1btmp;
 	u8 u1btmp;
-	u8 direct = bmac0 == true ? BIT(3) | BIT(2) : BIT(3);
-	u8 mac_reg = bmac0 == true ? REG_MAC1 : REG_MAC0;
-	u8 mac_on_bit = bmac0 == true ? MAC1_ON : MAC0_ON;
+	u8 direct = bmac0 ? BIT(3) | BIT(2) : BIT(3);
+	u8 mac_reg = bmac0 ? REG_MAC1 : REG_MAC0;
+	u8 mac_on_bit = bmac0 ? MAC1_ON : MAC0_ON;
 
 
 	rtlhal->during_mac0init_radiob = false;
 	rtlhal->during_mac0init_radiob = false;
 	rtlhal->during_mac1init_radioa = false;
 	rtlhal->during_mac1init_radioa = false;
@@ -573,7 +573,7 @@ bool rtl92d_phy_rf6052_config(struct ieee80211_hw *hw)
 		udelay(1);
 		udelay(1);
 		switch (rfpath) {
 		switch (rfpath) {
 		case RF90_PATH_A:
 		case RF90_PATH_A:
-			if (true_bpath == true)
+			if (true_bpath)
 				rtstatus = rtl92d_phy_config_rf_with_headerfile(
 				rtstatus = rtl92d_phy_config_rf_with_headerfile(
 						hw, radiob_txt,
 						hw, radiob_txt,
 						(enum radio_path)rfpath);
 						(enum radio_path)rfpath);

+ 3 - 3
drivers/net/wireless/rtlwifi/rtl8192de/trx.c

@@ -614,7 +614,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw,	struct rtl_stats *stats,
 						    (u8)
 						    (u8)
 						    GET_RX_DESC_RXMCS(pdesc));
 						    GET_RX_DESC_RXMCS(pdesc));
 	rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
 	rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
-	if (phystatus == true) {
+	if (phystatus) {
 		p_drvinfo = (struct rx_fwinfo_92d *)(skb->data +
 		p_drvinfo = (struct rx_fwinfo_92d *)(skb->data +
 						     stats->rx_bufshift);
 						     stats->rx_bufshift);
 		_rtl92de_translate_rx_signal_stuff(hw,
 		_rtl92de_translate_rx_signal_stuff(hw,
@@ -876,7 +876,7 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw,
 
 
 void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
 void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
 {
 {
-	if (istx == true) {
+	if (istx) {
 		switch (desc_name) {
 		switch (desc_name) {
 		case HW_DESC_OWN:
 		case HW_DESC_OWN:
 			wmb();
 			wmb();
@@ -917,7 +917,7 @@ u32 rtl92de_get_desc(u8 *p_desc, bool istx, u8 desc_name)
 {
 {
 	u32 ret = 0;
 	u32 ret = 0;
 
 
-	if (istx == true) {
+	if (istx) {
 		switch (desc_name) {
 		switch (desc_name) {
 		case HW_DESC_OWN:
 		case HW_DESC_OWN:
 			ret = GET_TX_DESC_OWN(p_desc);
 			ret = GET_TX_DESC_OWN(p_desc);

+ 0 - 3
drivers/net/wireless/rtlwifi/rtl8192se/hw.c

@@ -1214,8 +1214,6 @@ void rtl92se_enable_interrupt(struct ieee80211_hw *hw)
 	rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]);
 	rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]);
 	/* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */
 	/* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */
 	rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F);
 	rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F);
-
-	rtlpci->irq_enabled = true;
 }
 }
 
 
 void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
 void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
@@ -1226,7 +1224,6 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
 	rtl_write_dword(rtlpriv, INTA_MASK, 0);
 	rtl_write_dword(rtlpriv, INTA_MASK, 0);
 	rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);
 	rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);
 
 
-	rtlpci->irq_enabled = false;
 	synchronize_irq(rtlpci->pdev->irq);
 	synchronize_irq(rtlpci->pdev->irq);
 }
 }
 
 

+ 1 - 1
drivers/net/wireless/wl12xx/Kconfig

@@ -11,7 +11,6 @@ config WL12XX
 	depends on WL12XX_MENU && GENERIC_HARDIRQS
 	depends on WL12XX_MENU && GENERIC_HARDIRQS
 	depends on INET
 	depends on INET
 	select FW_LOADER
 	select FW_LOADER
-	select CRC7
 	---help---
 	---help---
 	  This module adds support for wireless adapters based on TI wl1271 and
 	  This module adds support for wireless adapters based on TI wl1271 and
 	  TI wl1273 chipsets. This module does *not* include support for wl1251.
 	  TI wl1273 chipsets. This module does *not* include support for wl1251.
@@ -33,6 +32,7 @@ config WL12XX_HT
 config WL12XX_SPI
 config WL12XX_SPI
 	tristate "TI wl12xx SPI support"
 	tristate "TI wl12xx SPI support"
 	depends on WL12XX && SPI_MASTER
 	depends on WL12XX && SPI_MASTER
+	select CRC7
 	---help---
 	---help---
 	  This module adds support for the SPI interface of adapters using
 	  This module adds support for the SPI interface of adapters using
 	  TI wl12xx chipsets.  Select this if your platform is using
 	  TI wl12xx chipsets.  Select this if your platform is using

+ 48 - 1
drivers/net/wireless/wl12xx/acx.c

@@ -25,7 +25,6 @@
 
 
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/crc7.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
@@ -1068,6 +1067,7 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
 	mem_conf->tx_free_req = mem->min_req_tx_blocks;
 	mem_conf->tx_free_req = mem->min_req_tx_blocks;
 	mem_conf->rx_free_req = mem->min_req_rx_blocks;
 	mem_conf->rx_free_req = mem->min_req_rx_blocks;
 	mem_conf->tx_min = mem->tx_min;
 	mem_conf->tx_min = mem->tx_min;
+	mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks;
 
 
 	ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
 	ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
 				   sizeof(*mem_conf));
 				   sizeof(*mem_conf));
@@ -1577,6 +1577,53 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
+int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
+{
+	struct wl1271_acx_ps_rx_streaming *rx_streaming;
+	u32 conf_queues, enable_queues;
+	int i, ret = 0;
+
+	wl1271_debug(DEBUG_ACX, "acx ps rx streaming");
+
+	rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL);
+	if (!rx_streaming) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	conf_queues = wl->conf.rx_streaming.queues;
+	if (enable)
+		enable_queues = conf_queues;
+	else
+		enable_queues = 0;
+
+	for (i = 0; i < 8; i++) {
+		/*
+		 * Skip non-changed queues, to avoid redundant acxs.
+		 * this check assumes conf.rx_streaming.queues can't
+		 * be changed while rx_streaming is enabled.
+		 */
+		if (!(conf_queues & BIT(i)))
+			continue;
+
+		rx_streaming->tid = i;
+		rx_streaming->enable = enable_queues & BIT(i);
+		rx_streaming->period = wl->conf.rx_streaming.interval;
+		rx_streaming->timeout = wl->conf.rx_streaming.interval;
+
+		ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING,
+					   rx_streaming,
+					   sizeof(*rx_streaming));
+		if (ret < 0) {
+			wl1271_warning("acx ps rx streaming failed: %d", ret);
+			goto out;
+		}
+	}
+out:
+	kfree(rx_streaming);
+	return ret;
+}
+
 int wl1271_acx_max_tx_retry(struct wl1271 *wl)
 int wl1271_acx_max_tx_retry(struct wl1271 *wl)
 {
 {
 	struct wl1271_acx_max_tx_retry *acx = NULL;
 	struct wl1271_acx_max_tx_retry *acx = NULL;

+ 16 - 0
drivers/net/wireless/wl12xx/acx.h

@@ -828,6 +828,8 @@ struct wl1271_acx_sta_config_memory {
 	u8 tx_free_req;
 	u8 tx_free_req;
 	u8 rx_free_req;
 	u8 rx_free_req;
 	u8 tx_min;
 	u8 tx_min;
+	u8 fwlog_blocks;
+	u8 padding[3];
 } __packed;
 } __packed;
 
 
 struct wl1271_acx_mem_map {
 struct wl1271_acx_mem_map {
@@ -1153,6 +1155,19 @@ struct wl1271_acx_fw_tsf_information {
 	u8 padding[3];
 	u8 padding[3];
 } __packed;
 } __packed;
 
 
+struct wl1271_acx_ps_rx_streaming {
+	struct acx_header header;
+
+	u8 tid;
+	u8 enable;
+
+	/* interval between triggers (10-100 msec) */
+	u8 period;
+
+	/* timeout before first trigger (0-200 msec) */
+	u8 timeout;
+} __packed;
+
 struct wl1271_acx_max_tx_retry {
 struct wl1271_acx_max_tx_retry {
 	struct acx_header header;
 	struct acx_header header;
 
 
@@ -1384,6 +1399,7 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
 int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
 int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
 				       bool enable);
 				       bool enable);
 int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
 int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
+int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
 int wl1271_acx_max_tx_retry(struct wl1271 *wl);
 int wl1271_acx_max_tx_retry(struct wl1271 *wl);
 int wl1271_acx_config_ps(struct wl1271 *wl);
 int wl1271_acx_config_ps(struct wl1271 *wl);
 int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
 int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);

+ 33 - 0
drivers/net/wireless/wl12xx/boot.c

@@ -102,6 +102,33 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
 	wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
 	wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
 }
 }
 
 
+static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl)
+{
+	unsigned int quirks = 0;
+	unsigned int *fw_ver = wl->chip.fw_ver;
+
+	/* Only for wl127x */
+	if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
+	    /* Check STA version */
+	    (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
+	      (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
+	     /* Check AP version */
+	     ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
+	      (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
+		quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
+
+	/* Only new station firmwares support routing fw logs to the host */
+	if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
+	    (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN))
+		quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED;
+
+	/* This feature is not yet supported for AP mode */
+	if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP)
+		quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED;
+
+	return quirks;
+}
+
 static void wl1271_parse_fw_ver(struct wl1271 *wl)
 static void wl1271_parse_fw_ver(struct wl1271 *wl)
 {
 {
 	int ret;
 	int ret;
@@ -116,6 +143,9 @@ static void wl1271_parse_fw_ver(struct wl1271 *wl)
 		memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
 		memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
 		return;
 		return;
 	}
 	}
+
+	/* Check if any quirks are needed with older fw versions */
+	wl->quirks |= wl12xx_get_fw_ver_quirks(wl);
 }
 }
 
 
 static void wl1271_boot_fw_version(struct wl1271 *wl)
 static void wl1271_boot_fw_version(struct wl1271 *wl)
@@ -749,6 +779,9 @@ int wl1271_load_firmware(struct wl1271 *wl)
 		clk |= (wl->ref_clock << 1) << 4;
 		clk |= (wl->ref_clock << 1) << 4;
 	}
 	}
 
 
+	if (wl->quirks & WL12XX_QUIRK_LPD_MODE)
+		clk |= SCRATCH_ENABLE_LPD;
+
 	wl1271_write32(wl, DRPW_SCRATCH_START, clk);
 	wl1271_write32(wl, DRPW_SCRATCH_START, clk);
 
 
 	wl1271_set_partition(wl, &part_table[PART_WORK]);
 	wl1271_set_partition(wl, &part_table[PART_WORK]);

+ 91 - 3
drivers/net/wireless/wl12xx/cmd.c

@@ -23,7 +23,6 @@
 
 
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/crc7.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/etherdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ieee80211.h>
 #include <linux/ieee80211.h>
@@ -106,7 +105,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
 
 
 fail:
 fail:
 	WARN_ON(1);
 	WARN_ON(1);
-	ieee80211_queue_work(wl->hw, &wl->recovery_work);
+	wl12xx_queue_recovery_work(wl);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -135,6 +134,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
 	/* Override the REF CLK from the NVS with the one from platform data */
 	/* Override the REF CLK from the NVS with the one from platform data */
 	gen_parms->general_params.ref_clock = wl->ref_clock;
 	gen_parms->general_params.ref_clock = wl->ref_clock;
 
 
+	/* LPD mode enable (bits 6-7) in WL1271 AP mode only */
+	if (wl->quirks & WL12XX_QUIRK_LPD_MODE)
+		gen_parms->general_params.general_settings |=
+			GENERAL_SETTINGS_DRPW_LPD;
+
 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
 	if (ret < 0) {
 	if (ret < 0) {
 		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
 		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
@@ -352,7 +356,7 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
 
 
 	ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
 	ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
 	if (ret != 0) {
 	if (ret != 0) {
-		ieee80211_queue_work(wl->hw, &wl->recovery_work);
+		wl12xx_queue_recovery_work(wl);
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -1223,3 +1227,87 @@ out_free:
 out:
 out:
 	return ret;
 	return ret;
 }
 }
+
+int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
+{
+	struct wl12xx_cmd_config_fwlog *cmd;
+	int ret = 0;
+
+	wl1271_debug(DEBUG_CMD, "cmd config firmware logger");
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cmd->logger_mode = wl->conf.fwlog.mode;
+	cmd->log_severity = wl->conf.fwlog.severity;
+	cmd->timestamp = wl->conf.fwlog.timestamp;
+	cmd->output = wl->conf.fwlog.output;
+	cmd->threshold = wl->conf.fwlog.threshold;
+
+	ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("failed to send config firmware logger command");
+		goto out_free;
+	}
+
+out_free:
+	kfree(cmd);
+
+out:
+	return ret;
+}
+
+int wl12xx_cmd_start_fwlog(struct wl1271 *wl)
+{
+	struct wl12xx_cmd_start_fwlog *cmd;
+	int ret = 0;
+
+	wl1271_debug(DEBUG_CMD, "cmd start firmware logger");
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("failed to send start firmware logger command");
+		goto out_free;
+	}
+
+out_free:
+	kfree(cmd);
+
+out:
+	return ret;
+}
+
+int wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
+{
+	struct wl12xx_cmd_stop_fwlog *cmd;
+	int ret = 0;
+
+	wl1271_debug(DEBUG_CMD, "cmd stop firmware logger");
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("failed to send stop firmware logger command");
+		goto out_free;
+	}
+
+out_free:
+	kfree(cmd);
+
+out:
+	return ret;
+}

+ 62 - 0
drivers/net/wireless/wl12xx/cmd.h

@@ -70,6 +70,9 @@ int wl1271_cmd_start_bss(struct wl1271 *wl);
 int wl1271_cmd_stop_bss(struct wl1271 *wl);
 int wl1271_cmd_stop_bss(struct wl1271 *wl);
 int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
 int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
 int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid);
 int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid);
+int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
+int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
+int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
 
 
 enum wl1271_commands {
 enum wl1271_commands {
 	CMD_INTERROGATE     = 1,    /*use this to read information elements*/
 	CMD_INTERROGATE     = 1,    /*use this to read information elements*/
@@ -107,6 +110,9 @@ enum wl1271_commands {
 	CMD_START_PERIODIC_SCAN      = 50,
 	CMD_START_PERIODIC_SCAN      = 50,
 	CMD_STOP_PERIODIC_SCAN       = 51,
 	CMD_STOP_PERIODIC_SCAN       = 51,
 	CMD_SET_STA_STATE            = 52,
 	CMD_SET_STA_STATE            = 52,
+	CMD_CONFIG_FWLOGGER          = 53,
+	CMD_START_FWLOGGER           = 54,
+	CMD_STOP_FWLOGGER            = 55,
 
 
 	/* AP mode commands */
 	/* AP mode commands */
 	CMD_BSS_START                = 60,
 	CMD_BSS_START                = 60,
@@ -575,4 +581,60 @@ struct wl1271_cmd_remove_sta {
 	u8 padding1;
 	u8 padding1;
 } __packed;
 } __packed;
 
 
+/*
+ * Continuous mode - packets are transferred to the host periodically
+ * via the data path.
+ * On demand - Log messages are stored in a cyclic buffer in the
+ * firmware, and only transferred to the host when explicitly requested
+ */
+enum wl12xx_fwlogger_log_mode {
+	WL12XX_FWLOG_CONTINUOUS,
+	WL12XX_FWLOG_ON_DEMAND
+};
+
+/* Include/exclude timestamps from the log messages */
+enum wl12xx_fwlogger_timestamp {
+	WL12XX_FWLOG_TIMESTAMP_DISABLED,
+	WL12XX_FWLOG_TIMESTAMP_ENABLED
+};
+
+/*
+ * Logs can be routed to the debug pinouts (where available), to the host bus
+ * (SDIO/SPI), or dropped
+ */
+enum wl12xx_fwlogger_output {
+	WL12XX_FWLOG_OUTPUT_NONE,
+	WL12XX_FWLOG_OUTPUT_DBG_PINS,
+	WL12XX_FWLOG_OUTPUT_HOST,
+};
+
+struct wl12xx_cmd_config_fwlog {
+	struct wl1271_cmd_header header;
+
+	/* See enum wl12xx_fwlogger_log_mode */
+	u8 logger_mode;
+
+	/* Minimum log level threshold */
+	u8 log_severity;
+
+	/* Include/exclude timestamps from the log messages */
+	u8 timestamp;
+
+	/* See enum wl1271_fwlogger_output */
+	u8 output;
+
+	/* Regulates the frequency of log messages */
+	u8 threshold;
+
+	u8 padding[3];
+} __packed;
+
+struct wl12xx_cmd_start_fwlog {
+	struct wl1271_cmd_header header;
+} __packed;
+
+struct wl12xx_cmd_stop_fwlog {
+	struct wl1271_cmd_header header;
+} __packed;
+
 #endif /* __WL1271_CMD_H__ */
 #endif /* __WL1271_CMD_H__ */

+ 55 - 0
drivers/net/wireless/wl12xx/conf.h

@@ -1248,6 +1248,59 @@ struct conf_fm_coex {
 	u8 swallow_clk_diff;
 	u8 swallow_clk_diff;
 };
 };
 
 
+struct conf_rx_streaming_settings {
+	/*
+	 * RX Streaming duration (in msec) from last tx/rx
+	 *
+	 * Range: u32
+	 */
+	u32 duration;
+
+	/*
+	 * Bitmap of tids to be polled during RX streaming.
+	 * (Note: it doesn't look like it really matters)
+	 *
+	 * Range: 0x1-0xff
+	 */
+	u8 queues;
+
+	/*
+	 * RX Streaming interval.
+	 * (Note:this value is also used as the rx streaming timeout)
+	 * Range: 0 (disabled), 10 - 100
+	 */
+	u8 interval;
+
+	/*
+	 * enable rx streaming also when there is no coex activity
+	 */
+	u8 always;
+};
+
+struct conf_fwlog {
+	/* Continuous or on-demand */
+	u8 mode;
+
+	/*
+	 * Number of memory blocks dedicated for the FW logger
+	 *
+	 * Range: 1-3, or 0 to disable the FW logger
+	 */
+	u8 mem_blocks;
+
+	/* Minimum log level threshold */
+	u8 severity;
+
+	/* Include/exclude timestamps from the log messages */
+	u8 timestamp;
+
+	/* See enum wl1271_fwlogger_output */
+	u8 output;
+
+	/* Regulates the frequency of log messages */
+	u8 threshold;
+};
+
 struct conf_drv_settings {
 struct conf_drv_settings {
 	struct conf_sg_settings sg;
 	struct conf_sg_settings sg;
 	struct conf_rx_settings rx;
 	struct conf_rx_settings rx;
@@ -1263,6 +1316,8 @@ struct conf_drv_settings {
 	struct conf_memory_settings mem_wl127x;
 	struct conf_memory_settings mem_wl127x;
 	struct conf_memory_settings mem_wl128x;
 	struct conf_memory_settings mem_wl128x;
 	struct conf_fm_coex fm_coex;
 	struct conf_fm_coex fm_coex;
+	struct conf_rx_streaming_settings rx_streaming;
+	struct conf_fwlog fwlog;
 	u8 hci_io_ds;
 	u8 hci_io_ds;
 };
 };
 
 

+ 136 - 2
drivers/net/wireless/wl12xx/debugfs.c

@@ -71,6 +71,14 @@ static const struct file_operations name## _ops = {			\
 	if (!entry || IS_ERR(entry))					\
 	if (!entry || IS_ERR(entry))					\
 		goto err;						\
 		goto err;						\
 
 
+#define DEBUGFS_ADD_PREFIX(prefix, name, parent)			\
+	do {								\
+		entry = debugfs_create_file(#name, 0400, parent,	\
+				    wl, &prefix## _## name## _ops);	\
+		if (!entry || IS_ERR(entry))				\
+			goto err;					\
+	} while (0);
+
 #define DEBUGFS_FWSTATS_FILE(sub, name, fmt)				\
 #define DEBUGFS_FWSTATS_FILE(sub, name, fmt)				\
 static ssize_t sub## _ ##name## _read(struct file *file,		\
 static ssize_t sub## _ ##name## _read(struct file *file,		\
 				      char __user *userbuf,		\
 				      char __user *userbuf,		\
@@ -298,7 +306,7 @@ static ssize_t start_recovery_write(struct file *file,
 	struct wl1271 *wl = file->private_data;
 	struct wl1271 *wl = file->private_data;
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
-	ieee80211_queue_work(wl->hw, &wl->recovery_work);
+	wl12xx_queue_recovery_work(wl);
 	mutex_unlock(&wl->mutex);
 	mutex_unlock(&wl->mutex);
 
 
 	return count;
 	return count;
@@ -527,11 +535,129 @@ static const struct file_operations beacon_interval_ops = {
 	.llseek = default_llseek,
 	.llseek = default_llseek,
 };
 };
 
 
+static ssize_t rx_streaming_interval_write(struct file *file,
+			   const char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	char buf[10];
+	size_t len;
+	unsigned long value;
+	int ret;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+	buf[len] = '\0';
+
+	ret = kstrtoul(buf, 0, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value in rx_streaming_interval!");
+		return -EINVAL;
+	}
+
+	/* valid values: 0, 10-100 */
+	if (value && (value < 10 || value > 100)) {
+		wl1271_warning("value is not in range!");
+		return -ERANGE;
+	}
+
+	mutex_lock(&wl->mutex);
+
+	wl->conf.rx_streaming.interval = value;
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	wl1271_recalc_rx_streaming(wl);
+
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static ssize_t rx_streaming_interval_read(struct file *file,
+			    char __user *userbuf,
+			    size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	return wl1271_format_buffer(userbuf, count, ppos,
+				    "%d\n", wl->conf.rx_streaming.interval);
+}
+
+static const struct file_operations rx_streaming_interval_ops = {
+	.read = rx_streaming_interval_read,
+	.write = rx_streaming_interval_write,
+	.open = wl1271_open_file_generic,
+	.llseek = default_llseek,
+};
+
+static ssize_t rx_streaming_always_write(struct file *file,
+			   const char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	char buf[10];
+	size_t len;
+	unsigned long value;
+	int ret;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+	buf[len] = '\0';
+
+	ret = kstrtoul(buf, 0, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value in rx_streaming_write!");
+		return -EINVAL;
+	}
+
+	/* valid values: 0, 10-100 */
+	if (!(value == 0 || value == 1)) {
+		wl1271_warning("value is not in valid!");
+		return -EINVAL;
+	}
+
+	mutex_lock(&wl->mutex);
+
+	wl->conf.rx_streaming.always = value;
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	wl1271_recalc_rx_streaming(wl);
+
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static ssize_t rx_streaming_always_read(struct file *file,
+			    char __user *userbuf,
+			    size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	return wl1271_format_buffer(userbuf, count, ppos,
+				    "%d\n", wl->conf.rx_streaming.always);
+}
+
+static const struct file_operations rx_streaming_always_ops = {
+	.read = rx_streaming_always_read,
+	.write = rx_streaming_always_write,
+	.open = wl1271_open_file_generic,
+	.llseek = default_llseek,
+};
+
 static int wl1271_debugfs_add_files(struct wl1271 *wl,
 static int wl1271_debugfs_add_files(struct wl1271 *wl,
 				     struct dentry *rootdir)
 				     struct dentry *rootdir)
 {
 {
 	int ret = 0;
 	int ret = 0;
-	struct dentry *entry, *stats;
+	struct dentry *entry, *stats, *streaming;
 
 
 	stats = debugfs_create_dir("fw-statistics", rootdir);
 	stats = debugfs_create_dir("fw-statistics", rootdir);
 	if (!stats || IS_ERR(stats)) {
 	if (!stats || IS_ERR(stats)) {
@@ -640,6 +766,14 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
 	DEBUGFS_ADD(dtim_interval, rootdir);
 	DEBUGFS_ADD(dtim_interval, rootdir);
 	DEBUGFS_ADD(beacon_interval, rootdir);
 	DEBUGFS_ADD(beacon_interval, rootdir);
 
 
+	streaming = debugfs_create_dir("rx_streaming", rootdir);
+	if (!streaming || IS_ERR(streaming))
+		goto err;
+
+	DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming);
+	DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming);
+
+
 	return 0;
 	return 0;
 
 
 err:
 err:

+ 25 - 11
drivers/net/wireless/wl12xx/event.c

@@ -133,10 +133,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
 		if (ret < 0)
 		if (ret < 0)
 			break;
 			break;
 
 
-		/* enable beacon early termination */
-		ret = wl1271_acx_bet_enable(wl, true);
-		if (ret < 0)
-			break;
+		/*
+		 * BET has only a minor effect in 5GHz and masks
+		 * channel switch IEs, so we only enable BET on 2.4GHz
+		*/
+		if (wl->band == IEEE80211_BAND_2GHZ)
+			/* enable beacon early termination */
+			ret = wl1271_acx_bet_enable(wl, true);
 
 
 		if (wl->ps_compl) {
 		if (wl->ps_compl) {
 			complete(wl->ps_compl);
 			complete(wl->ps_compl);
@@ -183,6 +186,21 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed)
 	ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid);
 	ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid);
 }
 }
 
 
+static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
+					       u8 enable)
+{
+	if (enable) {
+		/* disable dynamic PS when requested by the firmware */
+		ieee80211_disable_dyn_ps(wl->vif);
+		set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
+	} else {
+		ieee80211_enable_dyn_ps(wl->vif);
+		clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
+		wl1271_recalc_rx_streaming(wl);
+	}
+
+}
+
 static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
 static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
 {
 {
 	wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
 	wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
@@ -226,14 +244,10 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
 		}
 		}
 	}
 	}
 
 
-	/* disable dynamic PS when requested by the firmware */
 	if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
 	if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
-	    wl->bss_type == BSS_TYPE_STA_BSS) {
-		if (mbox->soft_gemini_sense_info)
-			ieee80211_disable_dyn_ps(wl->vif);
-		else
-			ieee80211_enable_dyn_ps(wl->vif);
-	}
+	    wl->bss_type == BSS_TYPE_STA_BSS)
+		wl12xx_event_soft_gemini_sense(wl,
+					       mbox->soft_gemini_sense_info);
 
 
 	/*
 	/*
 	 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
 	 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon

+ 3 - 0
drivers/net/wireless/wl12xx/ini.h

@@ -24,6 +24,9 @@
 #ifndef __INI_H__
 #ifndef __INI_H__
 #define __INI_H__
 #define __INI_H__
 
 
+#define GENERAL_SETTINGS_DRPW_LPD 0xc0
+#define SCRATCH_ENABLE_LPD        BIT(25)
+
 #define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
 #define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
 
 
 struct wl1271_ini_general_params {
 struct wl1271_ini_general_params {

+ 19 - 0
drivers/net/wireless/wl12xx/init.c

@@ -321,6 +321,20 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
 	return 0;
 	return 0;
 }
 }
 
 
+static int wl12xx_init_fwlog(struct wl1271 *wl)
+{
+	int ret;
+
+	if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED)
+		return 0;
+
+	ret = wl12xx_cmd_config_fwlog(wl);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static int wl1271_sta_hw_init(struct wl1271 *wl)
 static int wl1271_sta_hw_init(struct wl1271 *wl)
 {
 {
 	int ret;
 	int ret;
@@ -382,6 +396,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
+	/* Configure the FW logger */
+	ret = wl12xx_init_fwlog(wl);
+	if (ret < 0)
+		return ret;
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 4 - 3
drivers/net/wireless/wl12xx/io.c

@@ -23,7 +23,6 @@
 
 
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/crc7.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 
 
 #include "wl12xx.h"
 #include "wl12xx.h"
@@ -128,12 +127,14 @@ EXPORT_SYMBOL_GPL(wl1271_set_partition);
 
 
 void wl1271_io_reset(struct wl1271 *wl)
 void wl1271_io_reset(struct wl1271 *wl)
 {
 {
-	wl->if_ops->reset(wl);
+	if (wl->if_ops->reset)
+		wl->if_ops->reset(wl);
 }
 }
 
 
 void wl1271_io_init(struct wl1271 *wl)
 void wl1271_io_init(struct wl1271 *wl)
 {
 {
-	wl->if_ops->init(wl);
+	if (wl->if_ops->init)
+		wl->if_ops->init(wl);
 }
 }
 
 
 void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
 void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)

+ 14 - 0
drivers/net/wireless/wl12xx/io.h

@@ -129,6 +129,20 @@ static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
 	wl1271_raw_write(wl, physical, buf, len, fixed);
 	wl1271_raw_write(wl, physical, buf, len, fixed);
 }
 }
 
 
+static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
+				      void *buf, size_t len, bool fixed)
+{
+	int physical;
+	int addr;
+
+	/* Addresses are stored internally as addresses to 32 bytes blocks */
+	addr = hwaddr << 5;
+
+	physical = wl1271_translate_addr(wl, addr);
+
+	wl1271_raw_read(wl, physical, buf, len, fixed);
+}
+
 static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
 static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
 {
 {
 	return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
 	return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));

+ 484 - 106
drivers/net/wireless/wl12xx/main.c

@@ -31,6 +31,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/wl12xx.h>
 #include <linux/wl12xx.h>
+#include <linux/sched.h>
 
 
 #include "wl12xx.h"
 #include "wl12xx.h"
 #include "wl12xx_80211.h"
 #include "wl12xx_80211.h"
@@ -362,9 +363,25 @@ static struct conf_drv_settings default_conf = {
 		.fm_disturbed_band_margin     = 0xff,       /* default */
 		.fm_disturbed_band_margin     = 0xff,       /* default */
 		.swallow_clk_diff             = 0xff,       /* default */
 		.swallow_clk_diff             = 0xff,       /* default */
 	},
 	},
+	.rx_streaming = {
+		.duration                      = 150,
+		.queues                        = 0x1,
+		.interval                      = 20,
+		.always                        = 0,
+	},
+	.fwlog = {
+		.mode                         = WL12XX_FWLOG_ON_DEMAND,
+		.mem_blocks                   = 2,
+		.severity                     = 0,
+		.timestamp                    = WL12XX_FWLOG_TIMESTAMP_DISABLED,
+		.output                       = WL12XX_FWLOG_OUTPUT_HOST,
+		.threshold                    = 0,
+	},
 	.hci_io_ds = HCI_IO_DS_6MA,
 	.hci_io_ds = HCI_IO_DS_6MA,
 };
 };
 
 
+static char *fwlog_param;
+
 static void __wl1271_op_remove_interface(struct wl1271 *wl,
 static void __wl1271_op_remove_interface(struct wl1271 *wl,
 					 bool reset_tx_queues);
 					 bool reset_tx_queues);
 static void wl1271_free_ap_keys(struct wl1271 *wl);
 static void wl1271_free_ap_keys(struct wl1271 *wl);
@@ -388,6 +405,22 @@ static struct platform_device wl1271_device = {
 static DEFINE_MUTEX(wl_list_mutex);
 static DEFINE_MUTEX(wl_list_mutex);
 static LIST_HEAD(wl_list);
 static LIST_HEAD(wl_list);
 
 
+static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
+{
+	int ret;
+	if (operstate != IF_OPER_UP)
+		return 0;
+
+	if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
+		return 0;
+
+	ret = wl1271_cmd_set_sta_state(wl);
+	if (ret < 0)
+		return ret;
+
+	wl1271_info("Association completed.");
+	return 0;
+}
 static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
 static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
 			     void *arg)
 			     void *arg)
 {
 {
@@ -437,11 +470,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
-	if ((dev->operstate == IF_OPER_UP) &&
-	    !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
-		wl1271_cmd_set_sta_state(wl);
-		wl1271_info("Association completed.");
-	}
+	wl1271_check_operstate(wl, dev->operstate);
 
 
 	wl1271_ps_elp_sleep(wl);
 	wl1271_ps_elp_sleep(wl);
 
 
@@ -473,6 +502,117 @@ static int wl1271_reg_notify(struct wiphy *wiphy,
 	return 0;
 	return 0;
 }
 }
 
 
+static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
+{
+	int ret = 0;
+
+	/* we should hold wl->mutex */
+	ret = wl1271_acx_ps_rx_streaming(wl, enable);
+	if (ret < 0)
+		goto out;
+
+	if (enable)
+		set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
+	else
+		clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
+out:
+	return ret;
+}
+
+/*
+ * this function is being called when the rx_streaming interval
+ * has beed changed or rx_streaming should be disabled
+ */
+int wl1271_recalc_rx_streaming(struct wl1271 *wl)
+{
+	int ret = 0;
+	int period = wl->conf.rx_streaming.interval;
+
+	/* don't reconfigure if rx_streaming is disabled */
+	if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
+		goto out;
+
+	/* reconfigure/disable according to new streaming_period */
+	if (period &&
+	    test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
+	    (wl->conf.rx_streaming.always ||
+	     test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
+		ret = wl1271_set_rx_streaming(wl, true);
+	else {
+		ret = wl1271_set_rx_streaming(wl, false);
+		/* don't cancel_work_sync since we might deadlock */
+		del_timer_sync(&wl->rx_streaming_timer);
+	}
+out:
+	return ret;
+}
+
+static void wl1271_rx_streaming_enable_work(struct work_struct *work)
+{
+	int ret;
+	struct wl1271 *wl =
+		container_of(work, struct wl1271, rx_streaming_enable_work);
+
+	mutex_lock(&wl->mutex);
+
+	if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
+	    !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
+	    (!wl->conf.rx_streaming.always &&
+	     !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
+		goto out;
+
+	if (!wl->conf.rx_streaming.interval)
+		goto out;
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	ret = wl1271_set_rx_streaming(wl, true);
+	if (ret < 0)
+		goto out_sleep;
+
+	/* stop it after some time of inactivity */
+	mod_timer(&wl->rx_streaming_timer,
+		  jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
+
+out_sleep:
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+}
+
+static void wl1271_rx_streaming_disable_work(struct work_struct *work)
+{
+	int ret;
+	struct wl1271 *wl =
+		container_of(work, struct wl1271, rx_streaming_disable_work);
+
+	mutex_lock(&wl->mutex);
+
+	if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
+		goto out;
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	ret = wl1271_set_rx_streaming(wl, false);
+	if (ret)
+		goto out_sleep;
+
+out_sleep:
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+}
+
+static void wl1271_rx_streaming_timer(unsigned long data)
+{
+	struct wl1271 *wl = (struct wl1271 *)data;
+	ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
+}
+
 static void wl1271_conf_init(struct wl1271 *wl)
 static void wl1271_conf_init(struct wl1271 *wl)
 {
 {
 
 
@@ -488,8 +628,24 @@ static void wl1271_conf_init(struct wl1271 *wl)
 
 
 	/* apply driver default configuration */
 	/* apply driver default configuration */
 	memcpy(&wl->conf, &default_conf, sizeof(default_conf));
 	memcpy(&wl->conf, &default_conf, sizeof(default_conf));
-}
 
 
+	/* Adjust settings according to optional module parameters */
+	if (fwlog_param) {
+		if (!strcmp(fwlog_param, "continuous")) {
+			wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
+		} else if (!strcmp(fwlog_param, "ondemand")) {
+			wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
+		} else if (!strcmp(fwlog_param, "dbgpins")) {
+			wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
+			wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
+		} else if (!strcmp(fwlog_param, "disable")) {
+			wl->conf.fwlog.mem_blocks = 0;
+			wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
+		} else {
+			wl1271_error("Unknown fwlog parameter %s", fwlog_param);
+		}
+	}
+}
 
 
 static int wl1271_plt_init(struct wl1271 *wl)
 static int wl1271_plt_init(struct wl1271 *wl)
 {
 {
@@ -741,7 +897,7 @@ static void wl1271_flush_deferred_work(struct wl1271 *wl)
 
 
 	/* Return sent skbs to the network stack */
 	/* Return sent skbs to the network stack */
 	while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
 	while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
-		ieee80211_tx_status(wl->hw, skb);
+		ieee80211_tx_status_ni(wl->hw, skb);
 }
 }
 
 
 static void wl1271_netstack_work(struct work_struct *work)
 static void wl1271_netstack_work(struct work_struct *work)
@@ -808,7 +964,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
 		if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
 		if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
 			wl1271_error("watchdog interrupt received! "
 			wl1271_error("watchdog interrupt received! "
 				     "starting recovery.");
 				     "starting recovery.");
-			ieee80211_queue_work(wl->hw, &wl->recovery_work);
+			wl12xx_queue_recovery_work(wl);
 
 
 			/* restarting the chip. ignore any other interrupt. */
 			/* restarting the chip. ignore any other interrupt. */
 			goto out;
 			goto out;
@@ -970,6 +1126,89 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
+void wl12xx_queue_recovery_work(struct wl1271 *wl)
+{
+	if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+		ieee80211_queue_work(wl->hw, &wl->recovery_work);
+}
+
+size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
+{
+	size_t len = 0;
+
+	/* The FW log is a length-value list, find where the log end */
+	while (len < maxlen) {
+		if (memblock[len] == 0)
+			break;
+		if (len + memblock[len] + 1 > maxlen)
+			break;
+		len += memblock[len] + 1;
+	}
+
+	/* Make sure we have enough room */
+	len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
+
+	/* Fill the FW log file, consumed by the sysfs fwlog entry */
+	memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
+	wl->fwlog_size += len;
+
+	return len;
+}
+
+static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
+{
+	u32 addr;
+	u32 first_addr;
+	u8 *block;
+
+	if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
+	    (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
+	    (wl->conf.fwlog.mem_blocks == 0))
+		return;
+
+	wl1271_info("Reading FW panic log");
+
+	block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
+	if (!block)
+		return;
+
+	/*
+	 * Make sure the chip is awake and the logger isn't active.
+	 * This might fail if the firmware hanged.
+	 */
+	if (!wl1271_ps_elp_wakeup(wl))
+		wl12xx_cmd_stop_fwlog(wl);
+
+	/* Read the first memory block address */
+	wl1271_fw_status(wl, wl->fw_status);
+	first_addr = __le32_to_cpu(wl->fw_status->sta.log_start_addr);
+	if (!first_addr)
+		goto out;
+
+	/* Traverse the memory blocks linked list */
+	addr = first_addr;
+	do {
+		memset(block, 0, WL12XX_HW_BLOCK_SIZE);
+		wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
+				   false);
+
+		/*
+		 * Memory blocks are linked to one another. The first 4 bytes
+		 * of each memory block hold the hardware address of the next
+		 * one. The last memory block points to the first one.
+		 */
+		addr = __le32_to_cpup((__le32 *)block);
+		if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
+				       WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
+			break;
+	} while (addr && (addr != first_addr));
+
+	wake_up_interruptible(&wl->fwlog_waitq);
+
+out:
+	kfree(block);
+}
+
 static void wl1271_recovery_work(struct work_struct *work)
 static void wl1271_recovery_work(struct work_struct *work)
 {
 {
 	struct wl1271 *wl =
 	struct wl1271 *wl =
@@ -980,6 +1219,11 @@ static void wl1271_recovery_work(struct work_struct *work)
 	if (wl->state != WL1271_STATE_ON)
 	if (wl->state != WL1271_STATE_ON)
 		goto out;
 		goto out;
 
 
+	/* Avoid a recursive recovery */
+	set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
+
+	wl12xx_read_fwlog_panic(wl);
+
 	wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
 	wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
 		    wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
 		    wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
 
 
@@ -996,6 +1240,9 @@ static void wl1271_recovery_work(struct work_struct *work)
 
 
 	/* reboot the chipset */
 	/* reboot the chipset */
 	__wl1271_op_remove_interface(wl, false);
 	__wl1271_op_remove_interface(wl, false);
+
+	clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
+
 	ieee80211_restart_hw(wl->hw);
 	ieee80211_restart_hw(wl->hw);
 
 
 	/*
 	/*
@@ -1074,9 +1321,13 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
 			     wl->chip.id);
 			     wl->chip.id);
 
 
-		/* end-of-transaction flag should be set in wl127x AP mode */
+		/*
+		 * 'end-of-transaction flag' and 'LPD mode flag'
+		 * should be set in wl127x AP mode only
+		 */
 		if (wl->bss_type == BSS_TYPE_AP_BSS)
 		if (wl->bss_type == BSS_TYPE_AP_BSS)
-			wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
+			wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
+				       WL12XX_QUIRK_LPD_MODE);
 
 
 		ret = wl1271_setup(wl);
 		ret = wl1271_setup(wl);
 		if (ret < 0)
 		if (ret < 0)
@@ -1089,6 +1340,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 		ret = wl1271_setup(wl);
 		ret = wl1271_setup(wl);
 		if (ret < 0)
 		if (ret < 0)
 			goto out;
 			goto out;
+
 		if (wl1271_set_block_size(wl))
 		if (wl1271_set_block_size(wl))
 			wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
 			wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
 		break;
 		break;
@@ -1117,24 +1369,6 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
-static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
-{
-	unsigned int quirks = 0;
-	unsigned int *fw_ver = wl->chip.fw_ver;
-
-	/* Only for wl127x */
-	if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
-	    /* Check STA version */
-	    (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
-	      (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
-	     /* Check AP version */
-	     ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
-	      (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
-		quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
-
-	return quirks;
-}
-
 int wl1271_plt_start(struct wl1271 *wl)
 int wl1271_plt_start(struct wl1271 *wl)
 {
 {
 	int retries = WL1271_BOOT_RETRIES;
 	int retries = WL1271_BOOT_RETRIES;
@@ -1171,8 +1405,6 @@ int wl1271_plt_start(struct wl1271 *wl)
 		wl1271_notice("firmware booted in PLT mode (%s)",
 		wl1271_notice("firmware booted in PLT mode (%s)",
 			      wl->chip.fw_ver_str);
 			      wl->chip.fw_ver_str);
 
 
-		/* Check if any quirks are needed with older fw versions */
-		wl->quirks |= wl1271_get_fw_ver_quirks(wl);
 		goto out;
 		goto out;
 
 
 irq_disable:
 irq_disable:
@@ -1352,13 +1584,10 @@ static struct notifier_block wl1271_dev_notifier = {
 };
 };
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
-static int wl1271_configure_suspend(struct wl1271 *wl)
+static int wl1271_configure_suspend_sta(struct wl1271 *wl)
 {
 {
 	int ret;
 	int ret;
 
 
-	if (wl->bss_type != BSS_TYPE_STA_BSS)
-		return 0;
-
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
 
 
 	ret = wl1271_ps_elp_wakeup(wl);
 	ret = wl1271_ps_elp_wakeup(wl);
@@ -1403,11 +1632,41 @@ out:
 
 
 }
 }
 
 
+static int wl1271_configure_suspend_ap(struct wl1271 *wl)
+{
+	int ret;
+
+	mutex_lock(&wl->mutex);
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out_unlock;
+
+	ret = wl1271_acx_set_ap_beacon_filter(wl, true);
+
+	wl1271_ps_elp_sleep(wl);
+out_unlock:
+	mutex_unlock(&wl->mutex);
+	return ret;
+
+}
+
+static int wl1271_configure_suspend(struct wl1271 *wl)
+{
+	if (wl->bss_type == BSS_TYPE_STA_BSS)
+		return wl1271_configure_suspend_sta(wl);
+	if (wl->bss_type == BSS_TYPE_AP_BSS)
+		return wl1271_configure_suspend_ap(wl);
+	return 0;
+}
+
 static void wl1271_configure_resume(struct wl1271 *wl)
 static void wl1271_configure_resume(struct wl1271 *wl)
 {
 {
 	int ret;
 	int ret;
+	bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
+	bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
 
 
-	if (wl->bss_type != BSS_TYPE_STA_BSS)
+	if (!is_sta && !is_ap)
 		return;
 		return;
 
 
 	mutex_lock(&wl->mutex);
 	mutex_lock(&wl->mutex);
@@ -1415,10 +1674,14 @@ static void wl1271_configure_resume(struct wl1271 *wl)
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
-	/* exit psm if it wasn't configured */
-	if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
-		wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
-				   wl->basic_rate, true);
+	if (is_sta) {
+		/* exit psm if it wasn't configured */
+		if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
+			wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+					   wl->basic_rate, true);
+	} else if (is_ap) {
+		wl1271_acx_set_ap_beacon_filter(wl, false);
+	}
 
 
 	wl1271_ps_elp_sleep(wl);
 	wl1271_ps_elp_sleep(wl);
 out:
 out:
@@ -1429,69 +1692,69 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
 			    struct cfg80211_wowlan *wow)
 			    struct cfg80211_wowlan *wow)
 {
 {
 	struct wl1271 *wl = hw->priv;
 	struct wl1271 *wl = hw->priv;
+	int ret;
+
 	wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
 	wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
-	wl->wow_enabled = !!wow;
-	if (wl->wow_enabled) {
-		int ret;
-		ret = wl1271_configure_suspend(wl);
-		if (ret < 0) {
-			wl1271_warning("couldn't prepare device to suspend");
-			return ret;
-		}
-		/* flush any remaining work */
-		wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
-		flush_delayed_work(&wl->scan_complete_work);
+	WARN_ON(!wow || !wow->any);
 
 
-		/*
-		 * disable and re-enable interrupts in order to flush
-		 * the threaded_irq
-		 */
-		wl1271_disable_interrupts(wl);
+	wl->wow_enabled = true;
+	ret = wl1271_configure_suspend(wl);
+	if (ret < 0) {
+		wl1271_warning("couldn't prepare device to suspend");
+		return ret;
+	}
+	/* flush any remaining work */
+	wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
+	flush_delayed_work(&wl->scan_complete_work);
 
 
-		/*
-		 * set suspended flag to avoid triggering a new threaded_irq
-		 * work. no need for spinlock as interrupts are disabled.
-		 */
-		set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
+	/*
+	 * disable and re-enable interrupts in order to flush
+	 * the threaded_irq
+	 */
+	wl1271_disable_interrupts(wl);
+
+	/*
+	 * set suspended flag to avoid triggering a new threaded_irq
+	 * work. no need for spinlock as interrupts are disabled.
+	 */
+	set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
+
+	wl1271_enable_interrupts(wl);
+	flush_work(&wl->tx_work);
+	flush_delayed_work(&wl->pspoll_work);
+	flush_delayed_work(&wl->elp_work);
 
 
-		wl1271_enable_interrupts(wl);
-		flush_work(&wl->tx_work);
-		flush_delayed_work(&wl->pspoll_work);
-		flush_delayed_work(&wl->elp_work);
-	}
 	return 0;
 	return 0;
 }
 }
 
 
 static int wl1271_op_resume(struct ieee80211_hw *hw)
 static int wl1271_op_resume(struct ieee80211_hw *hw)
 {
 {
 	struct wl1271 *wl = hw->priv;
 	struct wl1271 *wl = hw->priv;
+	unsigned long flags;
+	bool run_irq_work = false;
+
 	wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
 	wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
 		     wl->wow_enabled);
 		     wl->wow_enabled);
+	WARN_ON(!wl->wow_enabled);
 
 
 	/*
 	/*
 	 * re-enable irq_work enqueuing, and call irq_work directly if
 	 * re-enable irq_work enqueuing, and call irq_work directly if
 	 * there is a pending work.
 	 * there is a pending work.
 	 */
 	 */
-	if (wl->wow_enabled) {
-		struct wl1271 *wl = hw->priv;
-		unsigned long flags;
-		bool run_irq_work = false;
-
-		spin_lock_irqsave(&wl->wl_lock, flags);
-		clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
-		if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
-			run_irq_work = true;
-		spin_unlock_irqrestore(&wl->wl_lock, flags);
-
-		if (run_irq_work) {
-			wl1271_debug(DEBUG_MAC80211,
-				     "run postponed irq_work directly");
-			wl1271_irq(0, wl);
-			wl1271_enable_interrupts(wl);
-		}
+	spin_lock_irqsave(&wl->wl_lock, flags);
+	clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
+	if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
+		run_irq_work = true;
+	spin_unlock_irqrestore(&wl->wl_lock, flags);
 
 
-		wl1271_configure_resume(wl);
+	if (run_irq_work) {
+		wl1271_debug(DEBUG_MAC80211,
+			     "run postponed irq_work directly");
+		wl1271_irq(0, wl);
+		wl1271_enable_interrupts(wl);
 	}
 	}
+	wl1271_configure_resume(wl);
+	wl->wow_enabled = false;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1629,9 +1892,6 @@ power_off:
 	strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
 	strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
 		sizeof(wiphy->fw_version));
 		sizeof(wiphy->fw_version));
 
 
-	/* Check if any quirks are needed with older fw versions */
-	wl->quirks |= wl1271_get_fw_ver_quirks(wl);
-
 	/*
 	/*
 	 * Now we know if 11a is supported (info from the NVS), so disable
 	 * Now we know if 11a is supported (info from the NVS), so disable
 	 * 11a channels if not supported
 	 * 11a channels if not supported
@@ -1694,6 +1954,9 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
 	cancel_delayed_work_sync(&wl->scan_complete_work);
 	cancel_delayed_work_sync(&wl->scan_complete_work);
 	cancel_work_sync(&wl->netstack_work);
 	cancel_work_sync(&wl->netstack_work);
 	cancel_work_sync(&wl->tx_work);
 	cancel_work_sync(&wl->tx_work);
+	del_timer_sync(&wl->rx_streaming_timer);
+	cancel_work_sync(&wl->rx_streaming_enable_work);
+	cancel_work_sync(&wl->rx_streaming_disable_work);
 	cancel_delayed_work_sync(&wl->pspoll_work);
 	cancel_delayed_work_sync(&wl->pspoll_work);
 	cancel_delayed_work_sync(&wl->elp_work);
 	cancel_delayed_work_sync(&wl->elp_work);
 
 
@@ -2780,24 +3043,6 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
 		}
 		}
 	}
 	}
 
 
-	if (changed & BSS_CHANGED_IBSS) {
-		wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
-			     bss_conf->ibss_joined);
-
-		if (bss_conf->ibss_joined) {
-			u32 rates = bss_conf->basic_rates;
-			wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
-									 rates);
-			wl->basic_rate = wl1271_tx_min_rate_get(wl);
-
-			/* by default, use 11b rates */
-			wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
-			ret = wl1271_acx_sta_rate_policies(wl);
-			if (ret < 0)
-				goto out;
-		}
-	}
-
 	ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
 	ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
@@ -3023,6 +3268,24 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
 		}
 		}
 	}
 	}
 
 
+	if (changed & BSS_CHANGED_IBSS) {
+		wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
+			     bss_conf->ibss_joined);
+
+		if (bss_conf->ibss_joined) {
+			u32 rates = bss_conf->basic_rates;
+			wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
+									 rates);
+			wl->basic_rate = wl1271_tx_min_rate_get(wl);
+
+			/* by default, use 11b rates */
+			wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
+			ret = wl1271_acx_sta_rate_policies(wl);
+			if (ret < 0)
+				goto out;
+		}
+	}
+
 	ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
 	ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
@@ -3061,6 +3324,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
 			wl1271_warning("cmd join failed %d", ret);
 			wl1271_warning("cmd join failed %d", ret);
 			goto out;
 			goto out;
 		}
 		}
+		wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
 	}
 	}
 
 
 out:
 out:
@@ -3784,6 +4048,69 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
 static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
 static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
 		   wl1271_sysfs_show_hw_pg_ver, NULL);
 		   wl1271_sysfs_show_hw_pg_ver, NULL);
 
 
+static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
+				       struct bin_attribute *bin_attr,
+				       char *buffer, loff_t pos, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct wl1271 *wl = dev_get_drvdata(dev);
+	ssize_t len;
+	int ret;
+
+	ret = mutex_lock_interruptible(&wl->mutex);
+	if (ret < 0)
+		return -ERESTARTSYS;
+
+	/* Let only one thread read the log at a time, blocking others */
+	while (wl->fwlog_size == 0) {
+		DEFINE_WAIT(wait);
+
+		prepare_to_wait_exclusive(&wl->fwlog_waitq,
+					  &wait,
+					  TASK_INTERRUPTIBLE);
+
+		if (wl->fwlog_size != 0) {
+			finish_wait(&wl->fwlog_waitq, &wait);
+			break;
+		}
+
+		mutex_unlock(&wl->mutex);
+
+		schedule();
+		finish_wait(&wl->fwlog_waitq, &wait);
+
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+
+		ret = mutex_lock_interruptible(&wl->mutex);
+		if (ret < 0)
+			return -ERESTARTSYS;
+	}
+
+	/* Check if the fwlog is still valid */
+	if (wl->fwlog_size < 0) {
+		mutex_unlock(&wl->mutex);
+		return 0;
+	}
+
+	/* Seeking is not supported - old logs are not kept. Disregard pos. */
+	len = min(count, (size_t)wl->fwlog_size);
+	wl->fwlog_size -= len;
+	memcpy(buffer, wl->fwlog, len);
+
+	/* Make room for new messages */
+	memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
+
+	mutex_unlock(&wl->mutex);
+
+	return len;
+}
+
+static struct bin_attribute fwlog_attr = {
+	.attr = {.name = "fwlog", .mode = S_IRUSR},
+	.read = wl1271_sysfs_read_fwlog,
+};
+
 int wl1271_register_hw(struct wl1271 *wl)
 int wl1271_register_hw(struct wl1271 *wl)
 {
 {
 	int ret;
 	int ret;
@@ -3964,6 +4291,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 	INIT_WORK(&wl->tx_work, wl1271_tx_work);
 	INIT_WORK(&wl->tx_work, wl1271_tx_work);
 	INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
 	INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
 	INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
 	INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
+	INIT_WORK(&wl->rx_streaming_enable_work,
+		  wl1271_rx_streaming_enable_work);
+	INIT_WORK(&wl->rx_streaming_disable_work,
+		  wl1271_rx_streaming_disable_work);
+
+	wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
+	if (!wl->freezable_wq) {
+		ret = -ENOMEM;
+		goto err_hw;
+	}
+
 	wl->channel = WL1271_DEFAULT_CHANNEL;
 	wl->channel = WL1271_DEFAULT_CHANNEL;
 	wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
 	wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
 	wl->default_key = 0;
 	wl->default_key = 0;
@@ -3989,6 +4327,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 	wl->quirks = 0;
 	wl->quirks = 0;
 	wl->platform_quirks = 0;
 	wl->platform_quirks = 0;
 	wl->sched_scanning = false;
 	wl->sched_scanning = false;
+	setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
+		    (unsigned long) wl);
+	wl->fwlog_size = 0;
+	init_waitqueue_head(&wl->fwlog_waitq);
 
 
 	memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
 	memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
 	for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
 	for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
@@ -4006,7 +4348,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 	wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
 	wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
 	if (!wl->aggr_buf) {
 	if (!wl->aggr_buf) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
-		goto err_hw;
+		goto err_wq;
 	}
 	}
 
 
 	wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
 	wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
@@ -4015,11 +4357,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 		goto err_aggr;
 		goto err_aggr;
 	}
 	}
 
 
+	/* Allocate one page for the FW log */
+	wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
+	if (!wl->fwlog) {
+		ret = -ENOMEM;
+		goto err_dummy_packet;
+	}
+
 	/* Register platform device */
 	/* Register platform device */
 	ret = platform_device_register(wl->plat_dev);
 	ret = platform_device_register(wl->plat_dev);
 	if (ret) {
 	if (ret) {
 		wl1271_error("couldn't register platform device");
 		wl1271_error("couldn't register platform device");
-		goto err_dummy_packet;
+		goto err_fwlog;
 	}
 	}
 	dev_set_drvdata(&wl->plat_dev->dev, wl);
 	dev_set_drvdata(&wl->plat_dev->dev, wl);
 
 
@@ -4037,20 +4386,36 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 		goto err_bt_coex_state;
 		goto err_bt_coex_state;
 	}
 	}
 
 
+	/* Create sysfs file for the FW log */
+	ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
+	if (ret < 0) {
+		wl1271_error("failed to create sysfs file fwlog");
+		goto err_hw_pg_ver;
+	}
+
 	return hw;
 	return hw;
 
 
+err_hw_pg_ver:
+	device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
+
 err_bt_coex_state:
 err_bt_coex_state:
 	device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
 	device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
 
 
 err_platform:
 err_platform:
 	platform_device_unregister(wl->plat_dev);
 	platform_device_unregister(wl->plat_dev);
 
 
+err_fwlog:
+	free_page((unsigned long)wl->fwlog);
+
 err_dummy_packet:
 err_dummy_packet:
 	dev_kfree_skb(wl->dummy_packet);
 	dev_kfree_skb(wl->dummy_packet);
 
 
 err_aggr:
 err_aggr:
 	free_pages((unsigned long)wl->aggr_buf, order);
 	free_pages((unsigned long)wl->aggr_buf, order);
 
 
+err_wq:
+	destroy_workqueue(wl->freezable_wq);
+
 err_hw:
 err_hw:
 	wl1271_debugfs_exit(wl);
 	wl1271_debugfs_exit(wl);
 	kfree(plat_dev);
 	kfree(plat_dev);
@@ -4066,7 +4431,15 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
 
 
 int wl1271_free_hw(struct wl1271 *wl)
 int wl1271_free_hw(struct wl1271 *wl)
 {
 {
+	/* Unblock any fwlog readers */
+	mutex_lock(&wl->mutex);
+	wl->fwlog_size = -1;
+	wake_up_interruptible_all(&wl->fwlog_waitq);
+	mutex_unlock(&wl->mutex);
+
+	device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
 	platform_device_unregister(wl->plat_dev);
 	platform_device_unregister(wl->plat_dev);
+	free_page((unsigned long)wl->fwlog);
 	dev_kfree_skb(wl->dummy_packet);
 	dev_kfree_skb(wl->dummy_packet);
 	free_pages((unsigned long)wl->aggr_buf,
 	free_pages((unsigned long)wl->aggr_buf,
 			get_order(WL1271_AGGR_BUFFER_SIZE));
 			get_order(WL1271_AGGR_BUFFER_SIZE));
@@ -4081,6 +4454,7 @@ int wl1271_free_hw(struct wl1271 *wl)
 
 
 	kfree(wl->fw_status);
 	kfree(wl->fw_status);
 	kfree(wl->tx_res_if);
 	kfree(wl->tx_res_if);
+	destroy_workqueue(wl->freezable_wq);
 
 
 	ieee80211_free_hw(wl->hw);
 	ieee80211_free_hw(wl->hw);
 
 
@@ -4093,6 +4467,10 @@ EXPORT_SYMBOL_GPL(wl12xx_debug_level);
 module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
 module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
 MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
 
 
+module_param_named(fwlog, fwlog_param, charp, 0);
+MODULE_PARM_DESC(keymap,
+		 "FW logger options: continuous, ondemand, dbgpins or disable");
+
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");

+ 7 - 5
drivers/net/wireless/wl12xx/ps.c

@@ -118,7 +118,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
 			&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
 			&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
 		if (ret == 0) {
 		if (ret == 0) {
 			wl1271_error("ELP wakeup timeout!");
 			wl1271_error("ELP wakeup timeout!");
-			ieee80211_queue_work(wl->hw, &wl->recovery_work);
+			wl12xx_queue_recovery_work(wl);
 			ret = -ETIMEDOUT;
 			ret = -ETIMEDOUT;
 			goto err;
 			goto err;
 		} else if (ret < 0) {
 		} else if (ret < 0) {
@@ -169,9 +169,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
 		wl1271_debug(DEBUG_PSM, "leaving psm");
 		wl1271_debug(DEBUG_PSM, "leaving psm");
 
 
 		/* disable beacon early termination */
 		/* disable beacon early termination */
-		ret = wl1271_acx_bet_enable(wl, false);
-		if (ret < 0)
-			return ret;
+		if (wl->band == IEEE80211_BAND_2GHZ) {
+			ret = wl1271_acx_bet_enable(wl, false);
+			if (ret < 0)
+				return ret;
+		}
 
 
 		/* disable beacon filtering */
 		/* disable beacon filtering */
 		ret = wl1271_acx_beacon_filter_opt(wl, false);
 		ret = wl1271_acx_beacon_filter_opt(wl, false);
@@ -202,7 +204,7 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
 			info = IEEE80211_SKB_CB(skb);
 			info = IEEE80211_SKB_CB(skb);
 			info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
 			info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
 			info->status.rates[0].idx = -1;
 			info->status.rates[0].idx = -1;
-			ieee80211_tx_status(wl->hw, skb);
+			ieee80211_tx_status_ni(wl->hw, skb);
 			filtered++;
 			filtered++;
 		}
 		}
 	}
 	}

+ 34 - 5
drivers/net/wireless/wl12xx/rx.c

@@ -22,6 +22,7 @@
  */
  */
 
 
 #include <linux/gfp.h>
 #include <linux/gfp.h>
+#include <linux/sched.h>
 
 
 #include "wl12xx.h"
 #include "wl12xx.h"
 #include "acx.h"
 #include "acx.h"
@@ -95,6 +96,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_hdr *hdr;
 	u8 *buf;
 	u8 *buf;
 	u8 beacon = 0;
 	u8 beacon = 0;
+	u8 is_data = 0;
 
 
 	/*
 	/*
 	 * In PLT mode we seem to get frames and mac80211 warns about them,
 	 * In PLT mode we seem to get frames and mac80211 warns about them,
@@ -106,6 +108,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
 	/* the data read starts with the descriptor */
 	/* the data read starts with the descriptor */
 	desc = (struct wl1271_rx_descriptor *) data;
 	desc = (struct wl1271_rx_descriptor *) data;
 
 
+	if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) {
+		size_t len = length - sizeof(*desc);
+		wl12xx_copy_fwlog(wl, data + sizeof(*desc), len);
+		wake_up_interruptible(&wl->fwlog_waitq);
+		return 0;
+	}
+
 	switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
 	switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
 	/* discard corrupted packets */
 	/* discard corrupted packets */
 	case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
 	case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
@@ -137,6 +146,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
 	hdr = (struct ieee80211_hdr *)skb->data;
 	hdr = (struct ieee80211_hdr *)skb->data;
 	if (ieee80211_is_beacon(hdr->frame_control))
 	if (ieee80211_is_beacon(hdr->frame_control))
 		beacon = 1;
 		beacon = 1;
+	if (ieee80211_is_data_present(hdr->frame_control))
+		is_data = 1;
 
 
 	wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
 	wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
 
 
@@ -147,9 +158,9 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
 	skb_trim(skb, skb->len - desc->pad_len);
 	skb_trim(skb, skb->len - desc->pad_len);
 
 
 	skb_queue_tail(&wl->deferred_rx_queue, skb);
 	skb_queue_tail(&wl->deferred_rx_queue, skb);
-	ieee80211_queue_work(wl->hw, &wl->netstack_work);
+	queue_work(wl->freezable_wq, &wl->netstack_work);
 
 
-	return 0;
+	return is_data;
 }
 }
 
 
 void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
 void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
@@ -162,6 +173,8 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
 	u32 mem_block;
 	u32 mem_block;
 	u32 pkt_length;
 	u32 pkt_length;
 	u32 pkt_offset;
 	u32 pkt_offset;
+	bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
+	bool had_data = false;
 
 
 	while (drv_rx_counter != fw_rx_counter) {
 	while (drv_rx_counter != fw_rx_counter) {
 		buf_size = 0;
 		buf_size = 0;
@@ -214,9 +227,11 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
 			 * conditions, in that case the received frame will just
 			 * conditions, in that case the received frame will just
 			 * be dropped.
 			 * be dropped.
 			 */
 			 */
-			wl1271_rx_handle_data(wl,
-					      wl->aggr_buf + pkt_offset,
-					      pkt_length);
+			if (wl1271_rx_handle_data(wl,
+						  wl->aggr_buf + pkt_offset,
+						  pkt_length) == 1)
+				had_data = true;
+
 			wl->rx_counter++;
 			wl->rx_counter++;
 			drv_rx_counter++;
 			drv_rx_counter++;
 			drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
 			drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
@@ -230,6 +245,20 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
 	 */
 	 */
 	if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION)
 	if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION)
 		wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
 		wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
+
+	if (!is_ap && wl->conf.rx_streaming.interval && had_data &&
+	    (wl->conf.rx_streaming.always ||
+	     test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) {
+		u32 timeout = wl->conf.rx_streaming.duration;
+
+		/* restart rx streaming */
+		if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
+			ieee80211_queue_work(wl->hw,
+					     &wl->rx_streaming_enable_work);
+
+		mod_timer(&wl->rx_streaming_timer,
+			  jiffies + msecs_to_jiffies(timeout));
+	}
 }
 }
 
 
 void wl1271_set_default_filters(struct wl1271 *wl)
 void wl1271_set_default_filters(struct wl1271 *wl)

+ 12 - 0
drivers/net/wireless/wl12xx/rx.h

@@ -97,6 +97,18 @@
 #define RX_BUF_SIZE_MASK      0xFFF00
 #define RX_BUF_SIZE_MASK      0xFFF00
 #define RX_BUF_SIZE_SHIFT_DIV 6
 #define RX_BUF_SIZE_SHIFT_DIV 6
 
 
+enum {
+	WL12XX_RX_CLASS_UNKNOWN,
+	WL12XX_RX_CLASS_MANAGEMENT,
+	WL12XX_RX_CLASS_DATA,
+	WL12XX_RX_CLASS_QOS_DATA,
+	WL12XX_RX_CLASS_BCN_PRBRSP,
+	WL12XX_RX_CLASS_EAPOL,
+	WL12XX_RX_CLASS_BA_EVENT,
+	WL12XX_RX_CLASS_AMSDU,
+	WL12XX_RX_CLASS_LOGGER,
+};
+
 struct wl1271_rx_descriptor {
 struct wl1271_rx_descriptor {
 	__le16 length;
 	__le16 length;
 	u8  status;
 	u8  status;

+ 30 - 33
drivers/net/wireless/wl12xx/scan.c

@@ -62,7 +62,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
 
 
 	if (wl->scan.failed) {
 	if (wl->scan.failed) {
 		wl1271_info("Scan completed due to error.");
 		wl1271_info("Scan completed due to error.");
-		ieee80211_queue_work(wl->hw, &wl->recovery_work);
+		wl12xx_queue_recovery_work(wl);
 	}
 	}
 
 
 out:
 out:
@@ -326,7 +326,7 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
 				    struct cfg80211_sched_scan_request *req,
 				    struct cfg80211_sched_scan_request *req,
 				    struct conn_scan_ch_params *channels,
 				    struct conn_scan_ch_params *channels,
 				    u32 band, bool radar, bool passive,
 				    u32 band, bool radar, bool passive,
-				    int start)
+				    int start, int max_channels)
 {
 {
 	struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
 	struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
 	int i, j;
 	int i, j;
@@ -334,7 +334,7 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
 	bool force_passive = !req->n_ssids;
 	bool force_passive = !req->n_ssids;
 
 
 	for (i = 0, j = start;
 	for (i = 0, j = start;
-	     i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS;
+	     i < req->n_channels && j < max_channels;
 	     i++) {
 	     i++) {
 		flags = req->channels[i]->flags;
 		flags = req->channels[i]->flags;
 
 
@@ -380,46 +380,42 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
 	return j - start;
 	return j - start;
 }
 }
 
 
-static int
+static bool
 wl1271_scan_sched_scan_channels(struct wl1271 *wl,
 wl1271_scan_sched_scan_channels(struct wl1271 *wl,
 				struct cfg80211_sched_scan_request *req,
 				struct cfg80211_sched_scan_request *req,
 				struct wl1271_cmd_sched_scan_config *cfg)
 				struct wl1271_cmd_sched_scan_config *cfg)
 {
 {
-	int idx = 0;
-
 	cfg->passive[0] =
 	cfg->passive[0] =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
 						    IEEE80211_BAND_2GHZ,
 						    IEEE80211_BAND_2GHZ,
-						    false, true, idx);
-	idx += cfg->passive[0];
-
+						    false, true, 0,
+						    MAX_CHANNELS_2GHZ);
 	cfg->active[0] =
 	cfg->active[0] =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
 						    IEEE80211_BAND_2GHZ,
 						    IEEE80211_BAND_2GHZ,
-						    false, false, idx);
-	/*
-	 * 5GHz channels always start at position 14, not immediately
-	 * after the last 2.4GHz channel
-	 */
-	idx = 14;
-
+						    false, false,
+						    cfg->passive[0],
+						    MAX_CHANNELS_2GHZ);
 	cfg->passive[1] =
 	cfg->passive[1] =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
 						    IEEE80211_BAND_5GHZ,
 						    IEEE80211_BAND_5GHZ,
-						    false, true, idx);
-	idx += cfg->passive[1];
-
+						    false, true, 0,
+						    MAX_CHANNELS_5GHZ);
 	cfg->dfs =
 	cfg->dfs =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
 						    IEEE80211_BAND_5GHZ,
 						    IEEE80211_BAND_5GHZ,
-						    true, true, idx);
-	idx += cfg->dfs;
-
+						    true, true,
+						    cfg->passive[1],
+						    MAX_CHANNELS_5GHZ);
 	cfg->active[1] =
 	cfg->active[1] =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
 						    IEEE80211_BAND_5GHZ,
 						    IEEE80211_BAND_5GHZ,
-						    false, false, idx);
-	idx += cfg->active[1];
+						    false, false,
+						    cfg->passive[1] + cfg->dfs,
+						    MAX_CHANNELS_5GHZ);
+	/* 802.11j channels are not supported yet */
+	cfg->passive[2] = 0;
+	cfg->active[2] = 0;
 
 
 	wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
 	wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
 		     cfg->active[0], cfg->passive[0]);
 		     cfg->active[0], cfg->passive[0]);
@@ -427,7 +423,9 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
 		     cfg->active[1], cfg->passive[1]);
 		     cfg->active[1], cfg->passive[1]);
 	wl1271_debug(DEBUG_SCAN, "    DFS: %d", cfg->dfs);
 	wl1271_debug(DEBUG_SCAN, "    DFS: %d", cfg->dfs);
 
 
-	return idx;
+	return  cfg->passive[0] || cfg->active[0] ||
+		cfg->passive[1] || cfg->active[1] || cfg->dfs ||
+		cfg->passive[2] || cfg->active[2];
 }
 }
 
 
 int wl1271_scan_sched_scan_config(struct wl1271 *wl,
 int wl1271_scan_sched_scan_config(struct wl1271 *wl,
@@ -436,7 +434,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
 {
 {
 	struct wl1271_cmd_sched_scan_config *cfg = NULL;
 	struct wl1271_cmd_sched_scan_config *cfg = NULL;
 	struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
 	struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
-	int i, total_channels, ret;
+	int i, ret;
 	bool force_passive = !req->n_ssids;
 	bool force_passive = !req->n_ssids;
 
 
 	wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
 	wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
@@ -471,8 +469,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
 		cfg->ssid_len = 0;
 		cfg->ssid_len = 0;
 	}
 	}
 
 
-	total_channels = wl1271_scan_sched_scan_channels(wl, req, cfg);
-	if (total_channels == 0) {
+	if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) {
 		wl1271_error("scan channel list is empty");
 		wl1271_error("scan channel list is empty");
 		ret = -EINVAL;
 		ret = -EINVAL;
 		goto out;
 		goto out;

+ 7 - 10
drivers/net/wireless/wl12xx/scan.h

@@ -112,18 +112,13 @@ struct wl1271_cmd_trigger_scan_to {
 	__le32 timeout;
 	__le32 timeout;
 } __packed;
 } __packed;
 
 
-#define MAX_CHANNELS_ALL_BANDS 41
+#define MAX_CHANNELS_2GHZ	14
+#define MAX_CHANNELS_5GHZ	23
+#define MAX_CHANNELS_4GHZ	4
+
 #define SCAN_MAX_CYCLE_INTERVALS 16
 #define SCAN_MAX_CYCLE_INTERVALS 16
 #define SCAN_MAX_BANDS 3
 #define SCAN_MAX_BANDS 3
 
 
-enum {
-	SCAN_CHANNEL_TYPE_2GHZ_PASSIVE,
-	SCAN_CHANNEL_TYPE_2GHZ_ACTIVE,
-	SCAN_CHANNEL_TYPE_5GHZ_PASSIVE,
-	SCAN_CHANNEL_TYPE_5GHZ_ACTIVE,
-	SCAN_CHANNEL_TYPE_5GHZ_DFS,
-};
-
 enum {
 enum {
 	SCAN_SSID_FILTER_ANY      = 0,
 	SCAN_SSID_FILTER_ANY      = 0,
 	SCAN_SSID_FILTER_SPECIFIC = 1,
 	SCAN_SSID_FILTER_SPECIFIC = 1,
@@ -182,7 +177,9 @@ struct wl1271_cmd_sched_scan_config {
 
 
 	u8 padding[3];
 	u8 padding[3];
 
 
-	struct conn_scan_ch_params channels[MAX_CHANNELS_ALL_BANDS];
+	struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+	struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
+	struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
 } __packed;
 } __packed;
 
 
 
 

+ 28 - 43
drivers/net/wireless/wl12xx/sdio.c

@@ -23,7 +23,6 @@
 
 
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/module.h>
-#include <linux/crc7.h>
 #include <linux/vmalloc.h>
 #include <linux/vmalloc.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/sdio_ids.h>
@@ -45,7 +44,7 @@
 #define SDIO_DEVICE_ID_TI_WL1271	0x4076
 #define SDIO_DEVICE_ID_TI_WL1271	0x4076
 #endif
 #endif
 
 
-static const struct sdio_device_id wl1271_devices[] = {
+static const struct sdio_device_id wl1271_devices[] __devinitconst = {
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
 	{}
 	{}
 };
 };
@@ -107,14 +106,6 @@ static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
 	enable_irq(wl->irq);
 	enable_irq(wl->irq);
 }
 }
 
 
-static void wl1271_sdio_reset(struct wl1271 *wl)
-{
-}
-
-static void wl1271_sdio_init(struct wl1271 *wl)
-{
-}
-
 static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
 static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
 				 size_t len, bool fixed)
 				 size_t len, bool fixed)
 {
 {
@@ -170,10 +161,12 @@ static int wl1271_sdio_power_on(struct wl1271 *wl)
 	struct sdio_func *func = wl_to_func(wl);
 	struct sdio_func *func = wl_to_func(wl);
 	int ret;
 	int ret;
 
 
-	/* Make sure the card will not be powered off by runtime PM */
-	ret = pm_runtime_get_sync(&func->dev);
-	if (ret < 0)
-		goto out;
+	/* If enabled, tell runtime PM not to power off the card */
+	if (pm_runtime_enabled(&func->dev)) {
+		ret = pm_runtime_get_sync(&func->dev);
+		if (ret)
+			goto out;
+	}
 
 
 	/* Runtime PM might be disabled, so power up the card manually */
 	/* Runtime PM might be disabled, so power up the card manually */
 	ret = mmc_power_restore_host(func->card->host);
 	ret = mmc_power_restore_host(func->card->host);
@@ -200,8 +193,11 @@ static int wl1271_sdio_power_off(struct wl1271 *wl)
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	/* Let runtime PM know the card is powered off */
-	return pm_runtime_put_sync(&func->dev);
+	/* If enabled, let runtime PM know the card is powered off */
+	if (pm_runtime_enabled(&func->dev))
+		ret = pm_runtime_put_sync(&func->dev);
+
+	return ret;
 }
 }
 
 
 static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
 static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
@@ -215,8 +211,6 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
 static struct wl1271_if_operations sdio_ops = {
 static struct wl1271_if_operations sdio_ops = {
 	.read		= wl1271_sdio_raw_read,
 	.read		= wl1271_sdio_raw_read,
 	.write		= wl1271_sdio_raw_write,
 	.write		= wl1271_sdio_raw_write,
-	.reset		= wl1271_sdio_reset,
-	.init		= wl1271_sdio_init,
 	.power		= wl1271_sdio_set_power,
 	.power		= wl1271_sdio_set_power,
 	.dev		= wl1271_sdio_wl_to_dev,
 	.dev		= wl1271_sdio_wl_to_dev,
 	.enable_irq	= wl1271_sdio_enable_interrupts,
 	.enable_irq	= wl1271_sdio_enable_interrupts,
@@ -278,17 +272,19 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 		goto out_free;
 		goto out_free;
 	}
 	}
 
 
-	enable_irq_wake(wl->irq);
-	device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1);
-
-	disable_irq(wl->irq);
+	ret = enable_irq_wake(wl->irq);
+	if (!ret) {
+		wl->irq_wake_enabled = true;
+		device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1);
 
 
-	/* if sdio can keep power while host is suspended, enable wow */
-	mmcflags = sdio_get_host_pm_caps(func);
-	wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags);
+		/* if sdio can keep power while host is suspended, enable wow */
+		mmcflags = sdio_get_host_pm_caps(func);
+		wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags);
 
 
-	if (mmcflags & MMC_PM_KEEP_POWER)
-		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
+		if (mmcflags & MMC_PM_KEEP_POWER)
+			hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
+	}
+	disable_irq(wl->irq);
 
 
 	ret = wl1271_init_ieee80211(wl);
 	ret = wl1271_init_ieee80211(wl);
 	if (ret)
 	if (ret)
@@ -303,8 +299,6 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 	/* Tell PM core that we don't need the card to be powered now */
 	/* Tell PM core that we don't need the card to be powered now */
 	pm_runtime_put_noidle(&func->dev);
 	pm_runtime_put_noidle(&func->dev);
 
 
-	wl1271_notice("initialized");
-
 	return 0;
 	return 0;
 
 
  out_irq:
  out_irq:
@@ -324,8 +318,10 @@ static void __devexit wl1271_remove(struct sdio_func *func)
 	pm_runtime_get_noresume(&func->dev);
 	pm_runtime_get_noresume(&func->dev);
 
 
 	wl1271_unregister_hw(wl);
 	wl1271_unregister_hw(wl);
-	device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0);
-	disable_irq_wake(wl->irq);
+	if (wl->irq_wake_enabled) {
+		device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0);
+		disable_irq_wake(wl->irq);
+	}
 	free_irq(wl->irq, wl);
 	free_irq(wl->irq, wl);
 	wl1271_free_hw(wl);
 	wl1271_free_hw(wl);
 }
 }
@@ -402,23 +398,12 @@ static struct sdio_driver wl1271_sdio_driver = {
 
 
 static int __init wl1271_init(void)
 static int __init wl1271_init(void)
 {
 {
-	int ret;
-
-	ret = sdio_register_driver(&wl1271_sdio_driver);
-	if (ret < 0) {
-		wl1271_error("failed to register sdio driver: %d", ret);
-		goto out;
-	}
-
-out:
-	return ret;
+	return sdio_register_driver(&wl1271_sdio_driver);
 }
 }
 
 
 static void __exit wl1271_exit(void)
 static void __exit wl1271_exit(void)
 {
 {
 	sdio_unregister_driver(&wl1271_sdio_driver);
 	sdio_unregister_driver(&wl1271_sdio_driver);
-
-	wl1271_notice("unloaded");
 }
 }
 
 
 module_init(wl1271_init);
 module_init(wl1271_init);

+ 1 - 14
drivers/net/wireless/wl12xx/spi.c

@@ -436,8 +436,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
 	if (ret)
 	if (ret)
 		goto out_irq;
 		goto out_irq;
 
 
-	wl1271_notice("initialized");
-
 	return 0;
 	return 0;
 
 
  out_irq:
  out_irq:
@@ -474,23 +472,12 @@ static struct spi_driver wl1271_spi_driver = {
 
 
 static int __init wl1271_init(void)
 static int __init wl1271_init(void)
 {
 {
-	int ret;
-
-	ret = spi_register_driver(&wl1271_spi_driver);
-	if (ret < 0) {
-		wl1271_error("failed to register spi driver: %d", ret);
-		goto out;
-	}
-
-out:
-	return ret;
+	return spi_register_driver(&wl1271_spi_driver);
 }
 }
 
 
 static void __exit wl1271_exit(void)
 static void __exit wl1271_exit(void)
 {
 {
 	spi_unregister_driver(&wl1271_spi_driver);
 	spi_unregister_driver(&wl1271_spi_driver);
-
-	wl1271_notice("unloaded");
 }
 }
 
 
 module_init(wl1271_init);
 module_init(wl1271_init);

+ 1 - 1
drivers/net/wireless/wl12xx/testmode.c

@@ -260,7 +260,7 @@ static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
 {
 {
 	wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover");
 	wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover");
 
 
-	ieee80211_queue_work(wl->hw, &wl->recovery_work);
+	wl12xx_queue_recovery_work(wl);
 
 
 	return 0;
 	return 0;
 }
 }

+ 29 - 4
drivers/net/wireless/wl12xx/tx.c

@@ -562,17 +562,29 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 }
 }
 
 
+static bool wl1271_tx_is_data_present(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+
+	return ieee80211_is_data_present(hdr->frame_control);
+}
+
 void wl1271_tx_work_locked(struct wl1271 *wl)
 void wl1271_tx_work_locked(struct wl1271 *wl)
 {
 {
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	u32 buf_offset = 0;
 	u32 buf_offset = 0;
 	bool sent_packets = false;
 	bool sent_packets = false;
+	bool had_data = false;
+	bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
 	int ret;
 	int ret;
 
 
 	if (unlikely(wl->state == WL1271_STATE_OFF))
 	if (unlikely(wl->state == WL1271_STATE_OFF))
 		return;
 		return;
 
 
 	while ((skb = wl1271_skb_dequeue(wl))) {
 	while ((skb = wl1271_skb_dequeue(wl))) {
+		if (wl1271_tx_is_data_present(skb))
+			had_data = true;
+
 		ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
 		ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
 		if (ret == -EAGAIN) {
 		if (ret == -EAGAIN) {
 			/*
 			/*
@@ -619,6 +631,19 @@ out_ack:
 
 
 		wl1271_handle_tx_low_watermark(wl);
 		wl1271_handle_tx_low_watermark(wl);
 	}
 	}
+	if (!is_ap && wl->conf.rx_streaming.interval && had_data &&
+	    (wl->conf.rx_streaming.always ||
+	     test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) {
+		u32 timeout = wl->conf.rx_streaming.duration;
+
+		/* enable rx streaming */
+		if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
+			ieee80211_queue_work(wl->hw,
+					     &wl->rx_streaming_enable_work);
+
+		mod_timer(&wl->rx_streaming_timer,
+			  jiffies + msecs_to_jiffies(timeout));
+	}
 }
 }
 
 
 void wl1271_tx_work(struct work_struct *work)
 void wl1271_tx_work(struct work_struct *work)
@@ -702,7 +727,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 
 
 	/* return the packet to the stack */
 	/* return the packet to the stack */
 	skb_queue_tail(&wl->deferred_tx_queue, skb);
 	skb_queue_tail(&wl->deferred_tx_queue, skb);
-	ieee80211_queue_work(wl->hw, &wl->netstack_work);
+	queue_work(wl->freezable_wq, &wl->netstack_work);
 	wl1271_free_tx_id(wl, result->id);
 	wl1271_free_tx_id(wl, result->id);
 }
 }
 
 
@@ -757,7 +782,7 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
 			info = IEEE80211_SKB_CB(skb);
 			info = IEEE80211_SKB_CB(skb);
 			info->status.rates[0].idx = -1;
 			info->status.rates[0].idx = -1;
 			info->status.rates[0].count = 0;
 			info->status.rates[0].count = 0;
-			ieee80211_tx_status(wl->hw, skb);
+			ieee80211_tx_status_ni(wl->hw, skb);
 			total++;
 			total++;
 		}
 		}
 	}
 	}
@@ -795,7 +820,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
 					info = IEEE80211_SKB_CB(skb);
 					info = IEEE80211_SKB_CB(skb);
 					info->status.rates[0].idx = -1;
 					info->status.rates[0].idx = -1;
 					info->status.rates[0].count = 0;
 					info->status.rates[0].count = 0;
-					ieee80211_tx_status(wl->hw, skb);
+					ieee80211_tx_status_ni(wl->hw, skb);
 				}
 				}
 			}
 			}
 		}
 		}
@@ -838,7 +863,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
 			info->status.rates[0].idx = -1;
 			info->status.rates[0].idx = -1;
 			info->status.rates[0].count = 0;
 			info->status.rates[0].count = 0;
 
 
-			ieee80211_tx_status(wl->hw, skb);
+			ieee80211_tx_status_ni(wl->hw, skb);
 		}
 		}
 	}
 	}
 }
 }

+ 36 - 2
drivers/net/wireless/wl12xx/wl12xx.h

@@ -226,6 +226,8 @@ enum {
 #define FW_VER_MINOR_1_SPARE_STA_MIN 58
 #define FW_VER_MINOR_1_SPARE_STA_MIN 58
 #define FW_VER_MINOR_1_SPARE_AP_MIN  47
 #define FW_VER_MINOR_1_SPARE_AP_MIN  47
 
 
+#define FW_VER_MINOR_FWLOG_STA_MIN 70
+
 struct wl1271_chip {
 struct wl1271_chip {
 	u32 id;
 	u32 id;
 	char fw_ver_str[ETHTOOL_BUSINFO_LEN];
 	char fw_ver_str[ETHTOOL_BUSINFO_LEN];
@@ -284,8 +286,7 @@ struct wl1271_fw_sta_status {
 	u8  tx_total;
 	u8  tx_total;
 	u8  reserved1;
 	u8  reserved1;
 	__le16 reserved2;
 	__le16 reserved2;
-	/* Total structure size is 68 bytes */
-	u32 padding;
+	__le32 log_start_addr;
 } __packed;
 } __packed;
 
 
 struct wl1271_fw_full_status {
 struct wl1271_fw_full_status {
@@ -359,6 +360,9 @@ enum wl12xx_flags {
 	WL1271_FLAG_DUMMY_PACKET_PENDING,
 	WL1271_FLAG_DUMMY_PACKET_PENDING,
 	WL1271_FLAG_SUSPENDED,
 	WL1271_FLAG_SUSPENDED,
 	WL1271_FLAG_PENDING_WORK,
 	WL1271_FLAG_PENDING_WORK,
+	WL1271_FLAG_SOFT_GEMINI,
+	WL1271_FLAG_RX_STREAMING_STARTED,
+	WL1271_FLAG_RECOVERY_IN_PROGRESS,
 };
 };
 
 
 struct wl1271_link {
 struct wl1271_link {
@@ -443,6 +447,7 @@ struct wl1271 {
 	struct sk_buff_head deferred_tx_queue;
 	struct sk_buff_head deferred_tx_queue;
 
 
 	struct work_struct tx_work;
 	struct work_struct tx_work;
+	struct workqueue_struct *freezable_wq;
 
 
 	/* Pending TX frames */
 	/* Pending TX frames */
 	unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)];
 	unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)];
@@ -468,6 +473,15 @@ struct wl1271 {
 	/* Network stack work  */
 	/* Network stack work  */
 	struct work_struct netstack_work;
 	struct work_struct netstack_work;
 
 
+	/* FW log buffer */
+	u8 *fwlog;
+
+	/* Number of valid bytes in the FW log buffer */
+	ssize_t fwlog_size;
+
+	/* Sysfs FW log entry readers wait queue */
+	wait_queue_head_t fwlog_waitq;
+
 	/* Hardware recovery work */
 	/* Hardware recovery work */
 	struct work_struct recovery_work;
 	struct work_struct recovery_work;
 
 
@@ -508,6 +522,11 @@ struct wl1271 {
 	/* Default key (for WEP) */
 	/* Default key (for WEP) */
 	u32 default_key;
 	u32 default_key;
 
 
+	/* Rx Streaming */
+	struct work_struct rx_streaming_enable_work;
+	struct work_struct rx_streaming_disable_work;
+	struct timer_list rx_streaming_timer;
+
 	unsigned int filters;
 	unsigned int filters;
 	unsigned int rx_config;
 	unsigned int rx_config;
 	unsigned int rx_filter;
 	unsigned int rx_filter;
@@ -573,6 +592,7 @@ struct wl1271 {
 	 * (currently, only "ANY" trigger is supported)
 	 * (currently, only "ANY" trigger is supported)
 	 */
 	 */
 	bool wow_enabled;
 	bool wow_enabled;
+	bool irq_wake_enabled;
 
 
 	/*
 	/*
 	 * AP-mode - links indexed by HLID. The global and broadcast links
 	 * AP-mode - links indexed by HLID. The global and broadcast links
@@ -602,6 +622,9 @@ struct wl1271_station {
 
 
 int wl1271_plt_start(struct wl1271 *wl);
 int wl1271_plt_start(struct wl1271 *wl);
 int wl1271_plt_stop(struct wl1271 *wl);
 int wl1271_plt_stop(struct wl1271 *wl);
+int wl1271_recalc_rx_streaming(struct wl1271 *wl);
+void wl12xx_queue_recovery_work(struct wl1271 *wl);
+size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
 
 
 #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
 #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
 
 
@@ -637,4 +660,15 @@ int wl1271_plt_stop(struct wl1271 *wl);
 /* WL128X requires aggregated packets to be aligned to the SDIO block size */
 /* WL128X requires aggregated packets to be aligned to the SDIO block size */
 #define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT	BIT(2)
 #define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT	BIT(2)
 
 
+/*
+ * WL127X AP mode requires Low Power DRPw (LPD) enable to reduce power
+ * consumption
+ */
+#define WL12XX_QUIRK_LPD_MODE                   BIT(3)
+
+/* Older firmwares did not implement the FW logger over bus feature */
+#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED	BIT(4)
+
+#define WL12XX_HW_BLOCK_SIZE	256
+
 #endif
 #endif

+ 12 - 12
drivers/nfc/Kconfig

@@ -2,17 +2,8 @@
 # Near Field Communication (NFC) devices
 # Near Field Communication (NFC) devices
 #
 #
 
 
-menuconfig NFC_DEVICES
-	bool "Near Field Communication (NFC) devices"
-	default n
-	---help---
-	  You'll have to say Y if your computer contains an NFC device that
-	  you want to use under Linux.
-
-	  You can say N here if you don't have any Near Field Communication
-	  devices connected to your computer.
-
-if NFC_DEVICES
+menu "Near Field Communication (NFC) devices"
+	depends on NFC
 
 
 config PN544_NFC
 config PN544_NFC
 	tristate "PN544 NFC driver"
 	tristate "PN544 NFC driver"
@@ -26,5 +17,14 @@ config PN544_NFC
 	  To compile this driver as a module, choose m here. The module will
 	  To compile this driver as a module, choose m here. The module will
 	  be called pn544.
 	  be called pn544.
 
 
+config NFC_PN533
+	tristate "NXP PN533 USB driver"
+	depends on USB
+	help
+	  NXP PN533 USB driver.
+	  This driver provides support for NFC NXP PN533 devices.
+
+	  Say Y here to compile support for PN533 devices into the
+	  kernel or say M to compile it as module (pn533).
 
 
-endif # NFC_DEVICES
+endmenu

+ 3 - 0
drivers/nfc/Makefile

@@ -3,3 +3,6 @@
 #
 #
 
 
 obj-$(CONFIG_PN544_NFC)		+= pn544.o
 obj-$(CONFIG_PN544_NFC)		+= pn544.o
+obj-$(CONFIG_NFC_PN533)		+= pn533.o
+
+ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG

+ 1632 - 0
drivers/nfc/pn533.c

@@ -0,0 +1,1632 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/nfc.h>
+#include <linux/netdevice.h>
+#include <net/nfc.h>
+
+#define VERSION "0.1"
+
+#define PN533_VENDOR_ID 0x4CC
+#define PN533_PRODUCT_ID 0x2533
+
+#define SCM_VENDOR_ID 0x4E6
+#define SCL3711_PRODUCT_ID 0x5591
+
+static const struct usb_device_id pn533_table[] = {
+	{ USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID) },
+	{ USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, pn533_table);
+
+/* frame definitions */
+#define PN533_FRAME_TAIL_SIZE 2
+#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
+				PN533_FRAME_TAIL_SIZE)
+#define PN533_FRAME_ACK_SIZE (sizeof(struct pn533_frame) + 1)
+#define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen])
+#define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
+
+/* start of frame */
+#define PN533_SOF 0x00FF
+
+/* frame identifier: in/out/error */
+#define PN533_FRAME_IDENTIFIER(f) (f->data[0])
+#define PN533_DIR_OUT 0xD4
+#define PN533_DIR_IN 0xD5
+
+/* PN533 Commands */
+#define PN533_FRAME_CMD(f) (f->data[1])
+#define PN533_FRAME_CMD_PARAMS_PTR(f) (&f->data[2])
+#define PN533_FRAME_CMD_PARAMS_LEN(f) (f->datalen - 2)
+
+#define PN533_CMD_GET_FIRMWARE_VERSION 0x02
+#define PN533_CMD_RF_CONFIGURATION 0x32
+#define PN533_CMD_IN_DATA_EXCHANGE 0x40
+#define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A
+#define PN533_CMD_IN_ATR 0x50
+#define PN533_CMD_IN_RELEASE 0x52
+
+#define PN533_CMD_RESPONSE(cmd) (cmd + 1)
+
+/* PN533 Return codes */
+#define PN533_CMD_RET_MASK 0x3F
+#define PN533_CMD_MI_MASK 0x40
+#define PN533_CMD_RET_SUCCESS 0x00
+
+struct pn533;
+
+typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg,
+					u8 *params, int params_len);
+
+/* structs for pn533 commands */
+
+/* PN533_CMD_GET_FIRMWARE_VERSION */
+struct pn533_fw_version {
+	u8 ic;
+	u8 ver;
+	u8 rev;
+	u8 support;
+};
+
+/* PN533_CMD_RF_CONFIGURATION */
+#define PN533_CFGITEM_MAX_RETRIES 0x05
+
+#define PN533_CONFIG_MAX_RETRIES_NO_RETRY 0x00
+#define PN533_CONFIG_MAX_RETRIES_ENDLESS 0xFF
+
+struct pn533_config_max_retries {
+	u8 mx_rty_atr;
+	u8 mx_rty_psl;
+	u8 mx_rty_passive_act;
+} __packed;
+
+/* PN533_CMD_IN_LIST_PASSIVE_TARGET */
+
+/* felica commands opcode */
+#define PN533_FELICA_OPC_SENSF_REQ 0
+#define PN533_FELICA_OPC_SENSF_RES 1
+/* felica SENSF_REQ parameters */
+#define PN533_FELICA_SENSF_SC_ALL 0xFFFF
+#define PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE 0
+#define PN533_FELICA_SENSF_RC_SYSTEM_CODE 1
+#define PN533_FELICA_SENSF_RC_ADVANCED_PROTOCOL 2
+
+/* type B initiator_data values */
+#define PN533_TYPE_B_AFI_ALL_FAMILIES 0
+#define PN533_TYPE_B_POLL_METHOD_TIMESLOT 0
+#define PN533_TYPE_B_POLL_METHOD_PROBABILISTIC 1
+
+union pn533_cmd_poll_initdata {
+	struct {
+		u8 afi;
+		u8 polling_method;
+	} __packed type_b;
+	struct {
+		u8 opcode;
+		__be16 sc;
+		u8 rc;
+		u8 tsn;
+	} __packed felica;
+};
+
+/* Poll modulations */
+enum {
+	PN533_POLL_MOD_106KBPS_A,
+	PN533_POLL_MOD_212KBPS_FELICA,
+	PN533_POLL_MOD_424KBPS_FELICA,
+	PN533_POLL_MOD_106KBPS_JEWEL,
+	PN533_POLL_MOD_847KBPS_B,
+
+	__PN533_POLL_MOD_AFTER_LAST,
+};
+#define PN533_POLL_MOD_MAX (__PN533_POLL_MOD_AFTER_LAST - 1)
+
+struct pn533_poll_modulations {
+	struct {
+		u8 maxtg;
+		u8 brty;
+		union pn533_cmd_poll_initdata initiator_data;
+	} __packed data;
+	u8 len;
+};
+
+const struct pn533_poll_modulations poll_mod[] = {
+	[PN533_POLL_MOD_106KBPS_A] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 0,
+		},
+		.len = 2,
+	},
+	[PN533_POLL_MOD_212KBPS_FELICA] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 1,
+			.initiator_data.felica = {
+				.opcode = PN533_FELICA_OPC_SENSF_REQ,
+				.sc = PN533_FELICA_SENSF_SC_ALL,
+				.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE,
+				.tsn = 0,
+			},
+		},
+		.len = 7,
+	},
+	[PN533_POLL_MOD_424KBPS_FELICA] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 2,
+			.initiator_data.felica = {
+				.opcode = PN533_FELICA_OPC_SENSF_REQ,
+				.sc = PN533_FELICA_SENSF_SC_ALL,
+				.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE,
+				.tsn = 0,
+			},
+		 },
+		.len = 7,
+	},
+	[PN533_POLL_MOD_106KBPS_JEWEL] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 4,
+		},
+		.len = 2,
+	},
+	[PN533_POLL_MOD_847KBPS_B] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 8,
+			.initiator_data.type_b = {
+				.afi = PN533_TYPE_B_AFI_ALL_FAMILIES,
+				.polling_method =
+					PN533_TYPE_B_POLL_METHOD_TIMESLOT,
+			},
+		},
+		.len = 3,
+	},
+};
+
+/* PN533_CMD_IN_ATR */
+
+struct pn533_cmd_activate_param {
+	u8 tg;
+	u8 next;
+} __packed;
+
+struct pn533_cmd_activate_response {
+	u8 status;
+	u8 nfcid3t[10];
+	u8 didt;
+	u8 bst;
+	u8 brt;
+	u8 to;
+	u8 ppt;
+	/* optional */
+	u8 gt[];
+} __packed;
+
+
+struct pn533 {
+	struct usb_device *udev;
+	struct usb_interface *interface;
+	struct nfc_dev *nfc_dev;
+
+	struct urb *out_urb;
+	int out_maxlen;
+	struct pn533_frame *out_frame;
+
+	struct urb *in_urb;
+	int in_maxlen;
+	struct pn533_frame *in_frame;
+
+	struct tasklet_struct tasklet;
+	struct pn533_frame *tklt_in_frame;
+	int tklt_in_error;
+
+	pn533_cmd_complete_t cmd_complete;
+	void *cmd_complete_arg;
+	struct semaphore cmd_lock;
+	u8 cmd;
+
+	struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
+	u8 poll_mod_count;
+	u8 poll_mod_curr;
+	u32 poll_protocols;
+
+	u8 tgt_available_prots;
+	u8 tgt_active_prot;
+};
+
+struct pn533_frame {
+	u8 preamble;
+	__be16 start_frame;
+	u8 datalen;
+	u8 datalen_checksum;
+	u8 data[];
+} __packed;
+
+/* The rule: value + checksum = 0 */
+static inline u8 pn533_checksum(u8 value)
+{
+	return ~value + 1;
+}
+
+/* The rule: sum(data elements) + checksum = 0 */
+static u8 pn533_data_checksum(u8 *data, int datalen)
+{
+	u8 sum = 0;
+	int i;
+
+	for (i = 0; i < datalen; i++)
+		sum += data[i];
+
+	return pn533_checksum(sum);
+}
+
+/**
+ * pn533_tx_frame_ack - create a ack frame
+ * @frame:	The frame to be set as ack
+ *
+ * Ack is different type of standard frame. As a standard frame, it has
+ * preamble and start_frame. However the checksum of this frame must fail,
+ * i.e. datalen + datalen_checksum must NOT be zero. When the checksum test
+ * fails and datalen = 0 and datalen_checksum = 0xFF, the frame is a ack.
+ * After datalen_checksum field, the postamble is placed.
+ */
+static void pn533_tx_frame_ack(struct pn533_frame *frame)
+{
+	frame->preamble = 0;
+	frame->start_frame = cpu_to_be16(PN533_SOF);
+	frame->datalen = 0;
+	frame->datalen_checksum = 0xFF;
+	/* data[0] is used as postamble */
+	frame->data[0] = 0;
+}
+
+static void pn533_tx_frame_init(struct pn533_frame *frame, u8 cmd)
+{
+	frame->preamble = 0;
+	frame->start_frame = cpu_to_be16(PN533_SOF);
+	PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT;
+	PN533_FRAME_CMD(frame) = cmd;
+	frame->datalen = 2;
+}
+
+static void pn533_tx_frame_finish(struct pn533_frame *frame)
+{
+	frame->datalen_checksum = pn533_checksum(frame->datalen);
+
+	PN533_FRAME_CHECKSUM(frame) =
+		pn533_data_checksum(frame->data, frame->datalen);
+
+	PN533_FRAME_POSTAMBLE(frame) = 0;
+}
+
+static bool pn533_rx_frame_is_valid(struct pn533_frame *frame)
+{
+	u8 checksum;
+
+	if (frame->start_frame != cpu_to_be16(PN533_SOF))
+		return false;
+
+	checksum = pn533_checksum(frame->datalen);
+	if (checksum != frame->datalen_checksum)
+		return false;
+
+	checksum = pn533_data_checksum(frame->data, frame->datalen);
+	if (checksum != PN533_FRAME_CHECKSUM(frame))
+		return false;
+
+	return true;
+}
+
+static bool pn533_rx_frame_is_ack(struct pn533_frame *frame)
+{
+	if (frame->start_frame != cpu_to_be16(PN533_SOF))
+		return false;
+
+	if (frame->datalen != 0 || frame->datalen_checksum != 0xFF)
+		return false;
+
+	return true;
+}
+
+static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd)
+{
+	return (PN533_FRAME_CMD(frame) == PN533_CMD_RESPONSE(cmd));
+}
+
+static void pn533_tasklet_cmd_complete(unsigned long arg)
+{
+	struct pn533 *dev = (struct pn533 *) arg;
+	struct pn533_frame *in_frame = dev->tklt_in_frame;
+	int rc;
+
+	if (dev->tklt_in_error)
+		rc = dev->cmd_complete(dev, dev->cmd_complete_arg, NULL,
+							dev->tklt_in_error);
+	else
+		rc = dev->cmd_complete(dev, dev->cmd_complete_arg,
+					PN533_FRAME_CMD_PARAMS_PTR(in_frame),
+					PN533_FRAME_CMD_PARAMS_LEN(in_frame));
+
+	if (rc != -EINPROGRESS)
+		up(&dev->cmd_lock);
+}
+
+static void pn533_recv_response(struct urb *urb)
+{
+	struct pn533 *dev = urb->context;
+	struct pn533_frame *in_frame;
+
+	dev->tklt_in_frame = NULL;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
+						" status: %d", urb->status);
+		dev->tklt_in_error = urb->status;
+		goto sched_tasklet;
+	default:
+		nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:"
+							" %d", urb->status);
+		dev->tklt_in_error = urb->status;
+		goto sched_tasklet;
+	}
+
+	in_frame = dev->in_urb->transfer_buffer;
+
+	if (!pn533_rx_frame_is_valid(in_frame)) {
+		nfc_dev_err(&dev->interface->dev, "Received an invalid frame");
+		dev->tklt_in_error = -EIO;
+		goto sched_tasklet;
+	}
+
+	if (!pn533_rx_frame_is_cmd_response(in_frame, dev->cmd)) {
+		nfc_dev_err(&dev->interface->dev, "The received frame is not "
+						"response to the last command");
+		dev->tklt_in_error = -EIO;
+		goto sched_tasklet;
+	}
+
+	nfc_dev_dbg(&dev->interface->dev, "Received a valid frame");
+	dev->tklt_in_error = 0;
+	dev->tklt_in_frame = in_frame;
+
+sched_tasklet:
+	tasklet_schedule(&dev->tasklet);
+}
+
+static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags)
+{
+	dev->in_urb->complete = pn533_recv_response;
+
+	return usb_submit_urb(dev->in_urb, flags);
+}
+
+static void pn533_recv_ack(struct urb *urb)
+{
+	struct pn533 *dev = urb->context;
+	struct pn533_frame *in_frame;
+	int rc;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
+						" status: %d", urb->status);
+		dev->tklt_in_error = urb->status;
+		goto sched_tasklet;
+	default:
+		nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:"
+							" %d", urb->status);
+		dev->tklt_in_error = urb->status;
+		goto sched_tasklet;
+	}
+
+	in_frame = dev->in_urb->transfer_buffer;
+
+	if (!pn533_rx_frame_is_ack(in_frame)) {
+		nfc_dev_err(&dev->interface->dev, "Received an invalid ack");
+		dev->tklt_in_error = -EIO;
+		goto sched_tasklet;
+	}
+
+	nfc_dev_dbg(&dev->interface->dev, "Received a valid ack");
+
+	rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC);
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev, "usb_submit_urb failed with"
+							" result %d", rc);
+		dev->tklt_in_error = rc;
+		goto sched_tasklet;
+	}
+
+	return;
+
+sched_tasklet:
+	dev->tklt_in_frame = NULL;
+	tasklet_schedule(&dev->tasklet);
+}
+
+static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags)
+{
+	dev->in_urb->complete = pn533_recv_ack;
+
+	return usb_submit_urb(dev->in_urb, flags);
+}
+
+static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
+{
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	pn533_tx_frame_ack(dev->out_frame);
+
+	dev->out_urb->transfer_buffer = dev->out_frame;
+	dev->out_urb->transfer_buffer_length = PN533_FRAME_ACK_SIZE;
+	rc = usb_submit_urb(dev->out_urb, flags);
+
+	return rc;
+}
+
+static int __pn533_send_cmd_frame_async(struct pn533 *dev,
+					struct pn533_frame *out_frame,
+					struct pn533_frame *in_frame,
+					int in_frame_len,
+					pn533_cmd_complete_t cmd_complete,
+					void *arg, gfp_t flags)
+{
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x",
+						PN533_FRAME_CMD(out_frame));
+
+	dev->cmd = PN533_FRAME_CMD(out_frame);
+	dev->cmd_complete = cmd_complete;
+	dev->cmd_complete_arg = arg;
+
+	dev->out_urb->transfer_buffer = out_frame;
+	dev->out_urb->transfer_buffer_length =
+				PN533_FRAME_SIZE(out_frame);
+
+	dev->in_urb->transfer_buffer = in_frame;
+	dev->in_urb->transfer_buffer_length = in_frame_len;
+
+	rc = usb_submit_urb(dev->out_urb, flags);
+	if (rc)
+		return rc;
+
+	rc = pn533_submit_urb_for_ack(dev, flags);
+	if (rc)
+		goto error;
+
+	return 0;
+
+error:
+	usb_unlink_urb(dev->out_urb);
+	return rc;
+}
+
+static int pn533_send_cmd_frame_async(struct pn533 *dev,
+					struct pn533_frame *out_frame,
+					struct pn533_frame *in_frame,
+					int in_frame_len,
+					pn533_cmd_complete_t cmd_complete,
+					void *arg, gfp_t flags)
+{
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (down_trylock(&dev->cmd_lock))
+		return -EBUSY;
+
+	rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
+					in_frame_len, cmd_complete, arg, flags);
+	if (rc)
+		goto error;
+
+	return 0;
+error:
+	up(&dev->cmd_lock);
+	return rc;
+}
+
+struct pn533_sync_cmd_response {
+	int rc;
+	struct completion done;
+};
+
+static int pn533_sync_cmd_complete(struct pn533 *dev, void *_arg,
+					u8 *params, int params_len)
+{
+	struct pn533_sync_cmd_response *arg = _arg;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	arg->rc = 0;
+
+	if (params_len < 0) /* error */
+		arg->rc = params_len;
+
+	complete(&arg->done);
+
+	return 0;
+}
+
+static int pn533_send_cmd_frame_sync(struct pn533 *dev,
+						struct pn533_frame *out_frame,
+						struct pn533_frame *in_frame,
+						int in_frame_len)
+{
+	int rc;
+	struct pn533_sync_cmd_response arg;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	init_completion(&arg.done);
+
+	rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, in_frame_len,
+				pn533_sync_cmd_complete, &arg, GFP_KERNEL);
+	if (rc)
+		return rc;
+
+	wait_for_completion(&arg.done);
+
+	return arg.rc;
+}
+
+static void pn533_send_complete(struct urb *urb)
+{
+	struct pn533 *dev = urb->context;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
+						" status: %d", urb->status);
+		break;
+	default:
+		nfc_dev_dbg(&dev->interface->dev, "Nonzero urb status received:"
+							" %d", urb->status);
+	}
+}
+
+struct pn533_target_type_a {
+	__be16 sens_res;
+	u8 sel_res;
+	u8 nfcid_len;
+	u8 nfcid_data[];
+} __packed;
+
+
+#define PN533_TYPE_A_SENS_RES_NFCID1(x) ((u8)((be16_to_cpu(x) & 0x00C0) >> 6))
+#define PN533_TYPE_A_SENS_RES_SSD(x) ((u8)((be16_to_cpu(x) & 0x001F) >> 0))
+#define PN533_TYPE_A_SENS_RES_PLATCONF(x) ((u8)((be16_to_cpu(x) & 0x0F00) >> 8))
+
+#define PN533_TYPE_A_SENS_RES_SSD_JEWEL 0x00
+#define PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL 0x0C
+
+#define PN533_TYPE_A_SEL_PROT(x) (((x) & 0x60) >> 5)
+#define PN533_TYPE_A_SEL_CASCADE(x) (((x) & 0x04) >> 2)
+
+#define PN533_TYPE_A_SEL_PROT_MIFARE 0
+#define PN533_TYPE_A_SEL_PROT_ISO14443 1
+#define PN533_TYPE_A_SEL_PROT_DEP 2
+#define PN533_TYPE_A_SEL_PROT_ISO14443_DEP 3
+
+static bool pn533_target_type_a_is_valid(struct pn533_target_type_a *type_a,
+							int target_data_len)
+{
+	u8 ssd;
+	u8 platconf;
+
+	if (target_data_len < sizeof(struct pn533_target_type_a))
+		return false;
+
+	/* The lenght check of nfcid[] and ats[] are not being performed because
+	   the values are not being used */
+
+	/* Requirement 4.6.3.3 from NFC Forum Digital Spec */
+	ssd = PN533_TYPE_A_SENS_RES_SSD(type_a->sens_res);
+	platconf = PN533_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res);
+
+	if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+			platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+			(ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+			platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+		return false;
+
+	/* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */
+	if (PN533_TYPE_A_SEL_CASCADE(type_a->sel_res) != 0)
+		return false;
+
+	return true;
+}
+
+static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn533_target_type_a *tgt_type_a;
+
+	tgt_type_a = (struct pn533_target_type_a *) tgt_data;
+
+	if (!pn533_target_type_a_is_valid(tgt_type_a, tgt_data_len))
+		return -EPROTO;
+
+	switch (PN533_TYPE_A_SEL_PROT(tgt_type_a->sel_res)) {
+	case PN533_TYPE_A_SEL_PROT_MIFARE:
+		nfc_tgt->supported_protocols = NFC_PROTO_MIFARE_MASK;
+		break;
+	case PN533_TYPE_A_SEL_PROT_ISO14443:
+		nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK;
+		break;
+	case PN533_TYPE_A_SEL_PROT_DEP:
+		nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+		break;
+	case PN533_TYPE_A_SEL_PROT_ISO14443_DEP:
+		nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK |
+							NFC_PROTO_NFC_DEP_MASK;
+		break;
+	}
+
+	nfc_tgt->sens_res = be16_to_cpu(tgt_type_a->sens_res);
+	nfc_tgt->sel_res = tgt_type_a->sel_res;
+
+	return 0;
+}
+
+struct pn533_target_felica {
+	u8 pol_res;
+	u8 opcode;
+	u8 nfcid2[8];
+	u8 pad[8];
+	/* optional */
+	u8 syst_code[];
+} __packed;
+
+#define PN533_FELICA_SENSF_NFCID2_DEP_B1 0x01
+#define PN533_FELICA_SENSF_NFCID2_DEP_B2 0xFE
+
+static bool pn533_target_felica_is_valid(struct pn533_target_felica *felica,
+							int target_data_len)
+{
+	if (target_data_len < sizeof(struct pn533_target_felica))
+		return false;
+
+	if (felica->opcode != PN533_FELICA_OPC_SENSF_RES)
+		return false;
+
+	return true;
+}
+
+static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn533_target_felica *tgt_felica;
+
+	tgt_felica = (struct pn533_target_felica *) tgt_data;
+
+	if (!pn533_target_felica_is_valid(tgt_felica, tgt_data_len))
+		return -EPROTO;
+
+	if (tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1 &&
+					tgt_felica->nfcid2[1] ==
+					PN533_FELICA_SENSF_NFCID2_DEP_B2)
+		nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+	else
+		nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK;
+
+	return 0;
+}
+
+struct pn533_target_jewel {
+	__be16 sens_res;
+	u8 jewelid[4];
+} __packed;
+
+static bool pn533_target_jewel_is_valid(struct pn533_target_jewel *jewel,
+							int target_data_len)
+{
+	u8 ssd;
+	u8 platconf;
+
+	if (target_data_len < sizeof(struct pn533_target_jewel))
+		return false;
+
+	/* Requirement 4.6.3.3 from NFC Forum Digital Spec */
+	ssd = PN533_TYPE_A_SENS_RES_SSD(jewel->sens_res);
+	platconf = PN533_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res);
+
+	if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+			platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+			(ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+			platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+		return false;
+
+	return true;
+}
+
+static int pn533_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn533_target_jewel *tgt_jewel;
+
+	tgt_jewel = (struct pn533_target_jewel *) tgt_data;
+
+	if (!pn533_target_jewel_is_valid(tgt_jewel, tgt_data_len))
+		return -EPROTO;
+
+	nfc_tgt->supported_protocols = NFC_PROTO_JEWEL_MASK;
+	nfc_tgt->sens_res = be16_to_cpu(tgt_jewel->sens_res);
+
+	return 0;
+}
+
+struct pn533_type_b_prot_info {
+	u8 bitrate;
+	u8 fsci_type;
+	u8 fwi_adc_fo;
+} __packed;
+
+#define PN533_TYPE_B_PROT_FCSI(x) (((x) & 0xF0) >> 4)
+#define PN533_TYPE_B_PROT_TYPE(x) (((x) & 0x0F) >> 0)
+#define PN533_TYPE_B_PROT_TYPE_RFU_MASK 0x8
+
+struct pn533_type_b_sens_res {
+	u8 opcode;
+	u8 nfcid[4];
+	u8 appdata[4];
+	struct pn533_type_b_prot_info prot_info;
+} __packed;
+
+#define PN533_TYPE_B_OPC_SENSB_RES 0x50
+
+struct pn533_target_type_b {
+	struct pn533_type_b_sens_res sensb_res;
+	u8 attrib_res_len;
+	u8 attrib_res[];
+} __packed;
+
+static bool pn533_target_type_b_is_valid(struct pn533_target_type_b *type_b,
+							int target_data_len)
+{
+	if (target_data_len < sizeof(struct pn533_target_type_b))
+		return false;
+
+	if (type_b->sensb_res.opcode != PN533_TYPE_B_OPC_SENSB_RES)
+		return false;
+
+	if (PN533_TYPE_B_PROT_TYPE(type_b->sensb_res.prot_info.fsci_type) &
+						PN533_TYPE_B_PROT_TYPE_RFU_MASK)
+		return false;
+
+	return true;
+}
+
+static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn533_target_type_b *tgt_type_b;
+
+	tgt_type_b = (struct pn533_target_type_b *) tgt_data;
+
+	if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len))
+		return -EPROTO;
+
+	nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK;
+
+	return 0;
+}
+
+struct pn533_poll_response {
+	u8 nbtg;
+	u8 tg;
+	u8 target_data[];
+} __packed;
+
+static int pn533_target_found(struct pn533 *dev,
+			struct pn533_poll_response *resp, int resp_len)
+{
+	int target_data_len;
+	struct nfc_target nfc_tgt;
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s - modulation=%d", __func__,
+							dev->poll_mod_curr);
+
+	if (resp->tg != 1)
+		return -EPROTO;
+
+	target_data_len = resp_len - sizeof(struct pn533_poll_response);
+
+	switch (dev->poll_mod_curr) {
+	case PN533_POLL_MOD_106KBPS_A:
+		rc = pn533_target_found_type_a(&nfc_tgt, resp->target_data,
+							target_data_len);
+		break;
+	case PN533_POLL_MOD_212KBPS_FELICA:
+	case PN533_POLL_MOD_424KBPS_FELICA:
+		rc = pn533_target_found_felica(&nfc_tgt, resp->target_data,
+							target_data_len);
+		break;
+	case PN533_POLL_MOD_106KBPS_JEWEL:
+		rc = pn533_target_found_jewel(&nfc_tgt, resp->target_data,
+							target_data_len);
+		break;
+	case PN533_POLL_MOD_847KBPS_B:
+		rc = pn533_target_found_type_b(&nfc_tgt, resp->target_data,
+							target_data_len);
+		break;
+	default:
+		nfc_dev_err(&dev->interface->dev, "Unknown current poll"
+								" modulation");
+		return -EPROTO;
+	}
+
+	if (rc)
+		return rc;
+
+	if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) {
+		nfc_dev_dbg(&dev->interface->dev, "The target found does not"
+						" have the desired protocol");
+		return -EAGAIN;
+	}
+
+	nfc_dev_dbg(&dev->interface->dev, "Target found - supported protocols: "
+					"0x%x", nfc_tgt.supported_protocols);
+
+	dev->tgt_available_prots = nfc_tgt.supported_protocols;
+
+	nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1);
+
+	return 0;
+}
+
+static void pn533_poll_reset_mod_list(struct pn533 *dev)
+{
+	dev->poll_mod_count = 0;
+}
+
+static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index)
+{
+	dev->poll_mod_active[dev->poll_mod_count] =
+		(struct pn533_poll_modulations *) &poll_mod[mod_index];
+	dev->poll_mod_count++;
+}
+
+static void pn533_poll_create_mod_list(struct pn533 *dev, u32 protocols)
+{
+	pn533_poll_reset_mod_list(dev);
+
+	if (protocols & NFC_PROTO_MIFARE_MASK
+					|| protocols & NFC_PROTO_ISO14443_MASK
+					|| protocols & NFC_PROTO_NFC_DEP_MASK)
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A);
+
+	if (protocols & NFC_PROTO_FELICA_MASK
+					|| protocols & NFC_PROTO_NFC_DEP_MASK) {
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA);
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA);
+	}
+
+	if (protocols & NFC_PROTO_JEWEL_MASK)
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL);
+
+	if (protocols & NFC_PROTO_ISO14443_MASK)
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B);
+}
+
+static void pn533_start_poll_frame(struct pn533_frame *frame,
+					struct pn533_poll_modulations *mod)
+{
+
+	pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
+
+	memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
+	frame->datalen += mod->len;
+
+	pn533_tx_frame_finish(frame);
+}
+
+static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
+						u8 *params, int params_len)
+{
+	struct pn533_poll_response *resp;
+	struct pn533_poll_modulations *next_mod;
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (params_len == -ENOENT) {
+		nfc_dev_dbg(&dev->interface->dev, "Polling operation has been"
+								" stopped");
+		goto stop_poll;
+	}
+
+	if (params_len < 0) {
+		nfc_dev_err(&dev->interface->dev, "Error %d when running poll",
+								params_len);
+		goto stop_poll;
+	}
+
+	resp = (struct pn533_poll_response *) params;
+	if (resp->nbtg) {
+		rc = pn533_target_found(dev, resp, params_len);
+
+		/* We must stop the poll after a valid target found */
+		if (rc == 0)
+			goto stop_poll;
+
+		if (rc != -EAGAIN)
+			nfc_dev_err(&dev->interface->dev, "The target found is"
+					" not valid - continuing to poll");
+	}
+
+	dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
+
+	next_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+	nfc_dev_dbg(&dev->interface->dev, "Polling next modulation (0x%x)",
+							dev->poll_mod_curr);
+
+	pn533_start_poll_frame(dev->out_frame, next_mod);
+
+	/* Don't need to down the semaphore again */
+	rc = __pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
+				dev->in_maxlen, pn533_start_poll_complete,
+				NULL, GFP_ATOMIC);
+
+	if (rc == -EPERM) {
+		nfc_dev_dbg(&dev->interface->dev, "Cannot poll next modulation"
+					" because poll has been stopped");
+		goto stop_poll;
+	}
+
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev, "Error %d when trying to poll"
+							" next modulation", rc);
+		goto stop_poll;
+	}
+
+	/* Inform caller function to do not up the semaphore */
+	return -EINPROGRESS;
+
+stop_poll:
+	pn533_poll_reset_mod_list(dev);
+	dev->poll_protocols = 0;
+	return 0;
+}
+
+static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	struct pn533_poll_modulations *start_mod;
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s - protocols=0x%x", __func__,
+								protocols);
+
+	if (dev->poll_mod_count) {
+		nfc_dev_err(&dev->interface->dev, "Polling operation already"
+								" active");
+		return -EBUSY;
+	}
+
+	if (dev->tgt_active_prot) {
+		nfc_dev_err(&dev->interface->dev, "Cannot poll with a target"
+							" already activated");
+		return -EBUSY;
+	}
+
+	pn533_poll_create_mod_list(dev, protocols);
+
+	if (!dev->poll_mod_count) {
+		nfc_dev_err(&dev->interface->dev, "No valid protocols"
+								" specified");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	nfc_dev_dbg(&dev->interface->dev, "It will poll %d modulations types",
+							dev->poll_mod_count);
+
+	dev->poll_mod_curr = 0;
+	start_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+	pn533_start_poll_frame(dev->out_frame, start_mod);
+
+	rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
+				dev->in_maxlen,	pn533_start_poll_complete,
+				NULL, GFP_KERNEL);
+
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
+							" start poll", rc);
+		goto error;
+	}
+
+	dev->poll_protocols = protocols;
+
+	return 0;
+
+error:
+	pn533_poll_reset_mod_list(dev);
+	return rc;
+}
+
+static void pn533_stop_poll(struct nfc_dev *nfc_dev)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (!dev->poll_mod_count) {
+		nfc_dev_dbg(&dev->interface->dev, "Polling operation was not"
+								" running");
+		return;
+	}
+
+	/* An ack will cancel the last issued command (poll) */
+	pn533_send_ack(dev, GFP_KERNEL);
+
+	/* prevent pn533_start_poll_complete to issue a new poll meanwhile */
+	usb_kill_urb(dev->in_urb);
+}
+
+static int pn533_activate_target_nfcdep(struct pn533 *dev)
+{
+	struct pn533_cmd_activate_param param;
+	struct pn533_cmd_activate_response *resp;
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_ATR);
+
+	param.tg = 1;
+	param.next = 0;
+	memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &param,
+				sizeof(struct pn533_cmd_activate_param));
+	dev->out_frame->datalen += sizeof(struct pn533_cmd_activate_param);
+
+	pn533_tx_frame_finish(dev->out_frame);
+
+	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
+								dev->in_maxlen);
+	if (rc)
+		return rc;
+
+	resp = (struct pn533_cmd_activate_response *)
+				PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
+	rc = resp->status & PN533_CMD_RET_MASK;
+	if (rc != PN533_CMD_RET_SUCCESS)
+		return -EIO;
+
+	return 0;
+}
+
+static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx,
+								u32 protocol)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s - protocol=%u", __func__,
+								protocol);
+
+	if (dev->poll_mod_count) {
+		nfc_dev_err(&dev->interface->dev, "Cannot activate while"
+								" polling");
+		return -EBUSY;
+	}
+
+	if (dev->tgt_active_prot) {
+		nfc_dev_err(&dev->interface->dev, "There is already an active"
+								" target");
+		return -EBUSY;
+	}
+
+	if (!dev->tgt_available_prots) {
+		nfc_dev_err(&dev->interface->dev, "There is no available target"
+								" to activate");
+		return -EINVAL;
+	}
+
+	if (!(dev->tgt_available_prots & (1 << protocol))) {
+		nfc_dev_err(&dev->interface->dev, "The target does not support"
+					" the requested protocol %u", protocol);
+		return -EINVAL;
+	}
+
+	if (protocol == NFC_PROTO_NFC_DEP) {
+		rc = pn533_activate_target_nfcdep(dev);
+		if (rc) {
+			nfc_dev_err(&dev->interface->dev, "Error %d when"
+						" activating target with"
+						" NFC_DEP protocol", rc);
+			return rc;
+		}
+	}
+
+	dev->tgt_active_prot = protocol;
+	dev->tgt_available_prots = 0;
+
+	return 0;
+}
+
+static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	u8 tg;
+	u8 status;
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (!dev->tgt_active_prot) {
+		nfc_dev_err(&dev->interface->dev, "There is no active target");
+		return;
+	}
+
+	dev->tgt_active_prot = 0;
+
+	pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_RELEASE);
+
+	tg = 1;
+	memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &tg, sizeof(u8));
+	dev->out_frame->datalen += sizeof(u8);
+
+	pn533_tx_frame_finish(dev->out_frame);
+
+	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
+								dev->in_maxlen);
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev, "Error when sending release"
+						" command to the controller");
+		return;
+	}
+
+	status = PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame)[0];
+	rc = status & PN533_CMD_RET_MASK;
+	if (rc != PN533_CMD_RET_SUCCESS)
+		nfc_dev_err(&dev->interface->dev, "Error 0x%x when releasing"
+							" the target", rc);
+
+	return;
+}
+
+#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
+#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
+
+static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
+{
+	int payload_len = skb->len;
+	struct pn533_frame *out_frame;
+	struct sk_buff *discarded;
+	u8 tg;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__,
+								payload_len);
+
+	if (payload_len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
+		/* TODO: Implement support to multi-part data exchange */
+		nfc_dev_err(&dev->interface->dev, "Data length greater than the"
+						" max allowed: %d",
+						PN533_CMD_DATAEXCH_DATA_MAXLEN);
+		return -ENOSYS;
+	}
+
+	/* Reserving header space */
+	if (skb_cow_head(skb, PN533_CMD_DATAEXCH_HEAD_LEN)) {
+		nfc_dev_err(&dev->interface->dev, "Error to add header data");
+		return -ENOMEM;
+	}
+
+	/* Reserving tail space, see pn533_tx_frame_finish */
+	if (skb_cow_data(skb, PN533_FRAME_TAIL_SIZE, &discarded) < 0) {
+		nfc_dev_err(&dev->interface->dev, "Error to add tail data");
+		return -ENOMEM;
+	}
+
+	skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
+	out_frame = (struct pn533_frame *) skb->data;
+
+	pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE);
+
+	tg = 1;
+	memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
+	out_frame->datalen += sizeof(u8);
+
+	/* The data is already in the out_frame, just update the datalen */
+	out_frame->datalen += payload_len;
+
+	pn533_tx_frame_finish(out_frame);
+	skb_put(skb, PN533_FRAME_TAIL_SIZE);
+
+	return 0;
+}
+
+struct pn533_data_exchange_arg {
+	struct sk_buff *skb_resp;
+	struct sk_buff *skb_out;
+	data_exchange_cb_t cb;
+	void *cb_context;
+};
+
+static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
+						u8 *params, int params_len)
+{
+	struct pn533_data_exchange_arg *arg = _arg;
+	struct sk_buff *skb_resp = arg->skb_resp;
+	struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
+	int err = 0;
+	u8 status;
+	u8 cmd_ret;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	dev_kfree_skb_irq(arg->skb_out);
+
+	if (params_len < 0) { /* error */
+		err = params_len;
+		goto error;
+	}
+
+	skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
+
+	status = params[0];
+
+	cmd_ret = status & PN533_CMD_RET_MASK;
+	if (cmd_ret != PN533_CMD_RET_SUCCESS) {
+		nfc_dev_err(&dev->interface->dev, "PN533 reported error %d when"
+						" exchanging data", cmd_ret);
+		err = -EIO;
+		goto error;
+	}
+
+	if (status & PN533_CMD_MI_MASK) {
+		/* TODO: Implement support to multi-part data exchange */
+		nfc_dev_err(&dev->interface->dev, "Multi-part message not yet"
+								" supported");
+		/* Prevent the other messages from controller */
+		pn533_send_ack(dev, GFP_ATOMIC);
+		err = -ENOSYS;
+		goto error;
+	}
+
+	skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
+	skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
+
+	arg->cb(arg->cb_context, skb_resp, 0);
+	kfree(arg);
+	return 0;
+
+error:
+	dev_kfree_skb_irq(skb_resp);
+	arg->cb(arg->cb_context, NULL, err);
+	kfree(arg);
+	return 0;
+}
+
+int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
+						struct sk_buff *skb,
+						data_exchange_cb_t cb,
+						void *cb_context)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	struct pn533_frame *out_frame, *in_frame;
+	struct pn533_data_exchange_arg *arg;
+	struct sk_buff *skb_resp;
+	int skb_resp_len;
+	int rc;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (!dev->tgt_active_prot) {
+		nfc_dev_err(&dev->interface->dev, "Cannot exchange data if"
+						" there is no active target");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	rc = pn533_data_exchange_tx_frame(dev, skb);
+	if (rc)
+		goto error;
+
+	skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
+			PN533_CMD_DATAEXCH_DATA_MAXLEN +
+			PN533_FRAME_TAIL_SIZE;
+
+	skb_resp = nfc_alloc_skb(skb_resp_len, GFP_KERNEL);
+	if (!skb_resp) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	in_frame = (struct pn533_frame *) skb_resp->data;
+	out_frame = (struct pn533_frame *) skb->data;
+
+	arg = kmalloc(sizeof(struct pn533_data_exchange_arg), GFP_KERNEL);
+	if (!arg) {
+		rc = -ENOMEM;
+		goto free_skb_resp;
+	}
+
+	arg->skb_resp = skb_resp;
+	arg->skb_out = skb;
+	arg->cb = cb;
+	arg->cb_context = cb_context;
+
+	rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, skb_resp_len,
+					pn533_data_exchange_complete, arg,
+					GFP_KERNEL);
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
+						" perform data_exchange", rc);
+		goto free_arg;
+	}
+
+	return 0;
+
+free_arg:
+	kfree(arg);
+free_skb_resp:
+	kfree_skb(skb_resp);
+error:
+	kfree_skb(skb);
+	return rc;
+}
+
+static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
+								u8 cfgdata_len)
+{
+	int rc;
+	u8 *params;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	pn533_tx_frame_init(dev->out_frame, PN533_CMD_RF_CONFIGURATION);
+
+	params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame);
+	params[0] = cfgitem;
+	memcpy(&params[1], cfgdata, cfgdata_len);
+	dev->out_frame->datalen += (1 + cfgdata_len);
+
+	pn533_tx_frame_finish(dev->out_frame);
+
+	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
+								dev->in_maxlen);
+
+	return rc;
+}
+
+struct nfc_ops pn533_nfc_ops = {
+	.start_poll = pn533_start_poll,
+	.stop_poll = pn533_stop_poll,
+	.activate_target = pn533_activate_target,
+	.deactivate_target = pn533_deactivate_target,
+	.data_exchange = pn533_data_exchange,
+};
+
+static int pn533_probe(struct usb_interface *interface,
+			const struct usb_device_id *id)
+{
+	struct pn533_fw_version *fw_ver;
+	struct pn533 *dev;
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	struct pn533_config_max_retries max_retries;
+	int in_endpoint = 0;
+	int out_endpoint = 0;
+	int rc = -ENOMEM;
+	int i;
+	u32 protocols;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->udev = usb_get_dev(interface_to_usbdev(interface));
+	dev->interface = interface;
+	sema_init(&dev->cmd_lock, 1);
+
+	iface_desc = interface->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+
+		if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+			dev->in_maxlen = le16_to_cpu(endpoint->wMaxPacketSize);
+			in_endpoint = endpoint->bEndpointAddress;
+		}
+
+		if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint)) {
+			dev->out_maxlen =
+				le16_to_cpu(endpoint->wMaxPacketSize);
+			out_endpoint = endpoint->bEndpointAddress;
+		}
+	}
+
+	if (!in_endpoint || !out_endpoint) {
+		nfc_dev_err(&interface->dev, "Could not find bulk-in or"
+							" bulk-out endpoint");
+		rc = -ENODEV;
+		goto error;
+	}
+
+	dev->in_frame = kmalloc(dev->in_maxlen, GFP_KERNEL);
+	dev->in_urb = usb_alloc_urb(0, GFP_KERNEL);
+	dev->out_frame = kmalloc(dev->out_maxlen, GFP_KERNEL);
+	dev->out_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+	if (!dev->in_frame || !dev->out_frame ||
+		!dev->in_urb || !dev->out_urb)
+		goto error;
+
+	usb_fill_bulk_urb(dev->in_urb, dev->udev,
+			usb_rcvbulkpipe(dev->udev, in_endpoint),
+			NULL, 0, NULL, dev);
+	usb_fill_bulk_urb(dev->out_urb, dev->udev,
+			usb_sndbulkpipe(dev->udev, out_endpoint),
+			NULL, 0,
+			pn533_send_complete, dev);
+
+	tasklet_init(&dev->tasklet, pn533_tasklet_cmd_complete, (ulong)dev);
+
+	usb_set_intfdata(interface, dev);
+
+	pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION);
+	pn533_tx_frame_finish(dev->out_frame);
+
+	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
+								dev->in_maxlen);
+	if (rc)
+		goto kill_tasklet;
+
+	fw_ver = (struct pn533_fw_version *)
+				PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
+	nfc_dev_info(&dev->interface->dev, "NXP PN533 firmware ver %d.%d now"
+					" attached", fw_ver->ver, fw_ver->rev);
+
+	protocols = NFC_PROTO_JEWEL_MASK
+			| NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
+			| NFC_PROTO_ISO14443_MASK
+			| NFC_PROTO_NFC_DEP_MASK;
+
+	dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols);
+	if (!dev->nfc_dev)
+		goto kill_tasklet;
+
+	nfc_set_parent_dev(dev->nfc_dev, &interface->dev);
+	nfc_set_drvdata(dev->nfc_dev, dev);
+
+	rc = nfc_register_device(dev->nfc_dev);
+	if (rc)
+		goto free_nfc_dev;
+
+	max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS;
+	max_retries.mx_rty_psl = 2;
+	max_retries.mx_rty_passive_act = PN533_CONFIG_MAX_RETRIES_NO_RETRY;
+
+	rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES,
+				(u8 *) &max_retries, sizeof(max_retries));
+
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev, "Error on setting MAX_RETRIES"
+								" config");
+		goto free_nfc_dev;
+	}
+
+	return 0;
+
+free_nfc_dev:
+	nfc_free_device(dev->nfc_dev);
+kill_tasklet:
+	tasklet_kill(&dev->tasklet);
+error:
+	kfree(dev->in_frame);
+	usb_free_urb(dev->in_urb);
+	kfree(dev->out_frame);
+	usb_free_urb(dev->out_urb);
+	kfree(dev);
+	return rc;
+}
+
+static void pn533_disconnect(struct usb_interface *interface)
+{
+	struct pn533 *dev;
+
+	dev = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	nfc_unregister_device(dev->nfc_dev);
+	nfc_free_device(dev->nfc_dev);
+
+	usb_kill_urb(dev->in_urb);
+	usb_kill_urb(dev->out_urb);
+
+	tasklet_kill(&dev->tasklet);
+
+	kfree(dev->in_frame);
+	usb_free_urb(dev->in_urb);
+	kfree(dev->out_frame);
+	usb_free_urb(dev->out_urb);
+	kfree(dev);
+
+	nfc_dev_info(&dev->interface->dev, "NXP PN533 NFC device disconnected");
+}
+
+static struct usb_driver pn533_driver = {
+	.name =		"pn533",
+	.probe =	pn533_probe,
+	.disconnect =	pn533_disconnect,
+	.id_table =	pn533_table,
+};
+
+static int __init pn533_init(void)
+{
+	int rc;
+
+	rc = usb_register(&pn533_driver);
+	if (rc)
+		err("usb_register failed. Error number %d", rc);
+
+	return rc;
+}
+
+static void __exit pn533_exit(void)
+{
+	usb_deregister(&pn533_driver);
+}
+
+module_init(pn533_init);
+module_exit(pn533_exit);
+
+MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>,"
+			" Aloisio Almeida Jr <aloisio.almeida@openbossa.org>");
+MODULE_DESCRIPTION("PN533 usb driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");

+ 3 - 6
drivers/ssb/pci.c

@@ -734,12 +734,9 @@ out_free:
 static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
 static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
 				  struct ssb_boardinfo *bi)
 				  struct ssb_boardinfo *bi)
 {
 {
-	pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
-			     &bi->vendor);
-	pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
-			     &bi->type);
-	pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
-			     &bi->rev);
+	bi->vendor = bus->host_pci->subsystem_vendor;
+	bi->type = bus->host_pci->subsystem_device;
+	bi->rev = bus->host_pci->revision;
 }
 }
 
 
 int ssb_pci_get_invariants(struct ssb_bus *bus,
 int ssb_pci_get_invariants(struct ssb_bus *bus,

+ 126 - 0
include/linux/nfc.h

@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LINUX_NFC_H
+#define __LINUX_NFC_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+
+#define NFC_GENL_NAME "nfc"
+#define NFC_GENL_VERSION 1
+
+#define NFC_GENL_MCAST_EVENT_NAME "events"
+
+/**
+ * enum nfc_commands - supported nfc commands
+ *
+ * @NFC_CMD_UNSPEC: unspecified command
+ *
+ * @NFC_CMD_GET_DEVICE: request information about a device (requires
+ *	%NFC_ATTR_DEVICE_INDEX) or dump request to get a list of all nfc devices
+ * @NFC_CMD_START_POLL: start polling for targets using the given protocols
+ *	(requires %NFC_ATTR_DEVICE_INDEX and %NFC_ATTR_PROTOCOLS)
+ * @NFC_CMD_STOP_POLL: stop polling for targets (requires
+ *	%NFC_ATTR_DEVICE_INDEX)
+ * @NFC_CMD_GET_TARGET: dump all targets found by the previous poll (requires
+ *	%NFC_ATTR_DEVICE_INDEX)
+ * @NFC_EVENT_TARGETS_FOUND: event emitted when a new target is found
+ *	(it sends %NFC_ATTR_DEVICE_INDEX)
+ * @NFC_EVENT_DEVICE_ADDED: event emitted when a new device is registred
+ *	(it sends %NFC_ATTR_DEVICE_NAME, %NFC_ATTR_DEVICE_INDEX and
+ *	%NFC_ATTR_PROTOCOLS)
+ * @NFC_EVENT_DEVICE_REMOVED: event emitted when a device is removed
+ *	(it sends %NFC_ATTR_DEVICE_INDEX)
+ */
+enum nfc_commands {
+	NFC_CMD_UNSPEC,
+	NFC_CMD_GET_DEVICE,
+	NFC_CMD_START_POLL,
+	NFC_CMD_STOP_POLL,
+	NFC_CMD_GET_TARGET,
+	NFC_EVENT_TARGETS_FOUND,
+	NFC_EVENT_DEVICE_ADDED,
+	NFC_EVENT_DEVICE_REMOVED,
+/* private: internal use only */
+	__NFC_CMD_AFTER_LAST
+};
+#define NFC_CMD_MAX (__NFC_CMD_AFTER_LAST - 1)
+
+/**
+ * enum nfc_attrs - supported nfc attributes
+ *
+ * @NFC_ATTR_UNSPEC: unspecified attribute
+ *
+ * @NFC_ATTR_DEVICE_INDEX: index of nfc device
+ * @NFC_ATTR_DEVICE_NAME: device name, max 8 chars
+ * @NFC_ATTR_PROTOCOLS: nfc protocols - bitwise or-ed combination from
+ *	NFC_PROTO_*_MASK constants
+ * @NFC_ATTR_TARGET_INDEX: index of the nfc target
+ * @NFC_ATTR_TARGET_SENS_RES: NFC-A targets extra information such as NFCID
+ * @NFC_ATTR_TARGET_SEL_RES: NFC-A targets extra information (useful if the
+ *	target is not NFC-Forum compliant)
+ */
+enum nfc_attrs {
+	NFC_ATTR_UNSPEC,
+	NFC_ATTR_DEVICE_INDEX,
+	NFC_ATTR_DEVICE_NAME,
+	NFC_ATTR_PROTOCOLS,
+	NFC_ATTR_TARGET_INDEX,
+	NFC_ATTR_TARGET_SENS_RES,
+	NFC_ATTR_TARGET_SEL_RES,
+/* private: internal use only */
+	__NFC_ATTR_AFTER_LAST
+};
+#define NFC_ATTR_MAX (__NFC_ATTR_AFTER_LAST - 1)
+
+#define NFC_DEVICE_NAME_MAXSIZE 8
+
+/* NFC protocols */
+#define NFC_PROTO_JEWEL		1
+#define NFC_PROTO_MIFARE	2
+#define NFC_PROTO_FELICA	3
+#define NFC_PROTO_ISO14443	4
+#define NFC_PROTO_NFC_DEP	5
+
+#define NFC_PROTO_MAX		6
+
+/* NFC protocols masks used in bitsets */
+#define NFC_PROTO_JEWEL_MASK	(1 << NFC_PROTO_JEWEL)
+#define NFC_PROTO_MIFARE_MASK	(1 << NFC_PROTO_MIFARE)
+#define NFC_PROTO_FELICA_MASK	(1 << NFC_PROTO_FELICA)
+#define NFC_PROTO_ISO14443_MASK	(1 << NFC_PROTO_ISO14443)
+#define NFC_PROTO_NFC_DEP_MASK	(1 << NFC_PROTO_NFC_DEP)
+
+struct sockaddr_nfc {
+	sa_family_t sa_family;
+	__u32 dev_idx;
+	__u32 target_idx;
+	__u32 nfc_protocol;
+};
+
+/* NFC socket protocols */
+#define NFC_SOCKPROTO_RAW	0
+#define NFC_SOCKPROTO_MAX	1
+
+#endif /*__LINUX_NFC_H */

+ 39 - 0
include/linux/nl80211.h

@@ -483,6 +483,14 @@
  *	more background information, see
  *	more background information, see
  *	http://wireless.kernel.org/en/users/Documentation/WoWLAN.
  *	http://wireless.kernel.org/en/users/Documentation/WoWLAN.
  *
  *
+ * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
+ *	the necessary information for supporting GTK rekey offload. This
+ *	feature is typically used during WoWLAN. The configuration data
+ *	is contained in %NL80211_ATTR_REKEY_DATA (which is nested and
+ *	contains the data in sub-attributes). After rekeying happened,
+ *	this command may also be sent by the driver as an MLME event to
+ *	inform userspace of the new replay counter.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
  */
@@ -605,6 +613,8 @@ enum nl80211_commands {
 	NL80211_CMD_SCHED_SCAN_RESULTS,
 	NL80211_CMD_SCHED_SCAN_RESULTS,
 	NL80211_CMD_SCHED_SCAN_STOPPED,
 	NL80211_CMD_SCHED_SCAN_STOPPED,
 
 
+	NL80211_CMD_SET_REKEY_OFFLOAD,
+
 	/* add new commands above here */
 	/* add new commands above here */
 
 
 	/* used to define NL80211_CMD_MAX below */
 	/* used to define NL80211_CMD_MAX below */
@@ -996,6 +1006,9 @@ enum nl80211_commands {
  *	are managed in software: interfaces of these types aren't subject to
  *	are managed in software: interfaces of these types aren't subject to
  *	any restrictions in their number or combinations.
  *	any restrictions in their number or combinations.
  *
  *
+ * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ *	necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
  */
@@ -1194,6 +1207,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_INTERFACE_COMBINATIONS,
 	NL80211_ATTR_INTERFACE_COMBINATIONS,
 	NL80211_ATTR_SOFTWARE_IFTYPES,
 	NL80211_ATTR_SOFTWARE_IFTYPES,
 
 
+	NL80211_ATTR_REKEY_DATA,
+
 	/* add attributes here, update the policy in nl80211.c */
 	/* add attributes here, update the policy in nl80211.c */
 
 
 	__NL80211_ATTR_AFTER_LAST,
 	__NL80211_ATTR_AFTER_LAST,
@@ -2361,4 +2376,28 @@ enum nl80211_plink_state {
 	MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
 	MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
 };
 };
 
 
+#define NL80211_KCK_LEN			16
+#define NL80211_KEK_LEN			16
+#define NL80211_REPLAY_CTR_LEN		8
+
+/**
+ * enum nl80211_rekey_data - attributes for GTK rekey offload
+ * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes
+ * @NL80211_REKEY_DATA_KEK: key encryption key (binary)
+ * @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
+ * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
+ * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
+ */
+enum nl80211_rekey_data {
+	__NL80211_REKEY_DATA_INVALID,
+	NL80211_REKEY_DATA_KEK,
+	NL80211_REKEY_DATA_KCK,
+	NL80211_REKEY_DATA_REPLAY_CTR,
+
+	/* keep last */
+	NUM_NL80211_REKEY_DATA,
+	MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1
+};
+
 #endif /* __LINUX_NL80211_H */
 #endif /* __LINUX_NL80211_H */

+ 3 - 1
include/linux/socket.h

@@ -192,7 +192,8 @@ struct ucred {
 #define AF_IEEE802154	36	/* IEEE802154 sockets		*/
 #define AF_IEEE802154	36	/* IEEE802154 sockets		*/
 #define AF_CAIF		37	/* CAIF sockets			*/
 #define AF_CAIF		37	/* CAIF sockets			*/
 #define AF_ALG		38	/* Algorithm sockets		*/
 #define AF_ALG		38	/* Algorithm sockets		*/
-#define AF_MAX		39	/* For now.. */
+#define AF_NFC		39	/* NFC sockets			*/
+#define AF_MAX		40	/* For now.. */
 
 
 /* Protocol families, same as address families. */
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
 #define PF_UNSPEC	AF_UNSPEC
@@ -234,6 +235,7 @@ struct ucred {
 #define PF_IEEE802154	AF_IEEE802154
 #define PF_IEEE802154	AF_IEEE802154
 #define PF_CAIF		AF_CAIF
 #define PF_CAIF		AF_CAIF
 #define PF_ALG		AF_ALG
 #define PF_ALG		AF_ALG
+#define PF_NFC		AF_NFC
 #define PF_MAX		AF_MAX
 #define PF_MAX		AF_MAX
 
 
 /* Maximum queue length specifiable by listen.  */
 /* Maximum queue length specifiable by listen.  */

+ 1 - 1
include/linux/ssb/ssb.h

@@ -99,7 +99,7 @@ struct ssb_sprom {
 struct ssb_boardinfo {
 struct ssb_boardinfo {
 	u16 vendor;
 	u16 vendor;
 	u16 type;
 	u16 type;
-	u16 rev;
+	u8  rev;
 };
 };
 
 
 
 

+ 26 - 0
include/net/cfg80211.h

@@ -1153,6 +1153,18 @@ struct cfg80211_wowlan {
 	int n_patterns;
 	int n_patterns;
 };
 };
 
 
+/**
+ * struct cfg80211_gtk_rekey_data - rekey data
+ * @kek: key encryption key
+ * @kck: key confirmation key
+ * @replay_ctr: replay counter
+ */
+struct cfg80211_gtk_rekey_data {
+	u8 kek[NL80211_KEK_LEN];
+	u8 kck[NL80211_KCK_LEN];
+	u8 replay_ctr[NL80211_REPLAY_CTR_LEN];
+};
+
 /**
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  * struct cfg80211_ops - backend description for wireless configuration
  *
  *
@@ -1197,6 +1209,8 @@ struct cfg80211_wowlan {
  *
  *
  * @set_default_mgmt_key: set the default management frame key on an interface
  * @set_default_mgmt_key: set the default management frame key on an interface
  *
  *
+ * @set_rekey_data: give the data necessary for GTK rekeying to the driver
+ *
  * @add_beacon: Add a beacon with given parameters, @head, @interval
  * @add_beacon: Add a beacon with given parameters, @head, @interval
  *	and @dtim_period will be valid, @tail is optional.
  *	and @dtim_period will be valid, @tail is optional.
  * @set_beacon: Change the beacon parameters for an access point mode
  * @set_beacon: Change the beacon parameters for an access point mode
@@ -1499,6 +1513,9 @@ struct cfg80211_ops {
 				struct net_device *dev,
 				struct net_device *dev,
 				struct cfg80211_sched_scan_request *request);
 				struct cfg80211_sched_scan_request *request);
 	int	(*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev);
 	int	(*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev);
+
+	int	(*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev,
+				  struct cfg80211_gtk_rekey_data *data);
 };
 };
 
 
 /*
 /*
@@ -3033,6 +3050,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 void cfg80211_cqm_pktloss_notify(struct net_device *dev,
 void cfg80211_cqm_pktloss_notify(struct net_device *dev,
 				 const u8 *peer, u32 num_packets, gfp_t gfp);
 				 const u8 *peer, u32 num_packets, gfp_t gfp);
 
 
+/**
+ * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
+ * @dev: network device
+ * @bssid: BSSID of AP (to avoid races)
+ * @replay_ctr: new replay counter
+ */
+void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
+			       const u8 *replay_ctr, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 
 /* wiphy_printk helpers, similar to dev_printk */
 /* wiphy_printk helpers, similar to dev_printk */

+ 47 - 0
include/net/mac80211.h

@@ -1628,6 +1628,10 @@ enum ieee80211_ampdu_mlme_action {
  *	ask the device to suspend. This is only invoked when WoWLAN is
  *	ask the device to suspend. This is only invoked when WoWLAN is
  *	configured, otherwise the device is deconfigured completely and
  *	configured, otherwise the device is deconfigured completely and
  *	reconfigured at resume time.
  *	reconfigured at resume time.
+ *	The driver may also impose special conditions under which it
+ *	wants to use the "normal" suspend (deconfigure), say if it only
+ *	supports WoWLAN when the device is associated. In this case, it
+ *	must return 1 from this function.
  *
  *
  * @resume: If WoWLAN was configured, this indicates that mac80211 is
  * @resume: If WoWLAN was configured, this indicates that mac80211 is
  *	now resuming its operation, after this the device must be fully
  *	now resuming its operation, after this the device must be fully
@@ -1696,6 +1700,12 @@ enum ieee80211_ampdu_mlme_action {
  * 	which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
  * 	which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
  *	The callback must be atomic.
  *	The callback must be atomic.
  *
  *
+ * @set_rekey_data: If the device supports GTK rekeying, for example while the
+ *	host is suspended, it can assign this callback to retrieve the data
+ *	necessary to do GTK rekeying, this is the KEK, KCK and replay counter.
+ *	After rekeying was done it should (for example during resume) notify
+ *	userspace of the new replay counter using ieee80211_gtk_rekey_notify().
+ *
  * @hw_scan: Ask the hardware to service the scan request, no need to start
  * @hw_scan: Ask the hardware to service the scan request, no need to start
  *	the scan state machine in stack. The scan must honour the channel
  *	the scan state machine in stack. The scan must honour the channel
  *	configuration done by the regulatory agent in the wiphy's
  *	configuration done by the regulatory agent in the wiphy's
@@ -1908,6 +1918,9 @@ struct ieee80211_ops {
 				struct ieee80211_key_conf *conf,
 				struct ieee80211_key_conf *conf,
 				struct ieee80211_sta *sta,
 				struct ieee80211_sta *sta,
 				u32 iv32, u16 *phase1key);
 				u32 iv32, u16 *phase1key);
+	void (*set_rekey_data)(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct cfg80211_gtk_rekey_data *data);
 	int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		       struct cfg80211_scan_request *req);
 		       struct cfg80211_scan_request *req);
 	void (*cancel_hw_scan)(struct ieee80211_hw *hw,
 	void (*cancel_hw_scan)(struct ieee80211_hw *hw,
@@ -2581,6 +2594,17 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
 void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
 				struct sk_buff *skb,
 				struct sk_buff *skb,
 				enum ieee80211_tkip_key_type type, u8 *key);
 				enum ieee80211_tkip_key_type type, u8 *key);
+
+/**
+ * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying
+ * @vif: virtual interface the rekeying was done on
+ * @bssid: The BSSID of the AP, for checking association
+ * @replay_ctr: the new replay counter after GTK rekeying
+ * @gfp: allocation flags
+ */
+void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
+				const u8 *replay_ctr, gfp_t gfp);
+
 /**
 /**
  * ieee80211_wake_queue - wake specific queue
  * ieee80211_wake_queue - wake specific queue
  * @hw: pointer as obtained from ieee80211_alloc_hw().
  * @hw: pointer as obtained from ieee80211_alloc_hw().
@@ -2845,6 +2869,29 @@ struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
 void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
 void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
 			       struct ieee80211_sta *pubsta, bool block);
 			       struct ieee80211_sta *pubsta, bool block);
 
 
+/**
+ * ieee80211_iter_keys - iterate keys programmed into the device
+ * @hw: pointer obtained from ieee80211_alloc_hw()
+ * @vif: virtual interface to iterate, may be %NULL for all
+ * @iter: iterator function that will be called for each key
+ * @iter_data: custom data to pass to the iterator function
+ *
+ * This function can be used to iterate all the keys known to
+ * mac80211, even those that weren't previously programmed into
+ * the device. This is intended for use in WoWLAN if the device
+ * needs reprogramming of the keys during suspend. Note that due
+ * to locking reasons, it is also only safe to call this at few
+ * spots since it must hold the RTNL and be able to sleep.
+ */
+void ieee80211_iter_keys(struct ieee80211_hw *hw,
+			 struct ieee80211_vif *vif,
+			 void (*iter)(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif,
+				      struct ieee80211_sta *sta,
+				      struct ieee80211_key_conf *key,
+				      void *data),
+			 void *iter_data);
+
 /**
 /**
  * ieee80211_ap_probereq_get - retrieve a Probe Request template
  * ieee80211_ap_probereq_get - retrieve a Probe Request template
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @hw: pointer obtained from ieee80211_alloc_hw().

部分文件因文件數量過多而無法顯示