Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
John W. Linville [Wed, 15 Feb 2012 21:24:37 +0000 (16:24 -0500)]
Conflicts:
net/mac80211/debugfs_sta.c
net/mac80211/sta_info.h

335 files changed:
Documentation/DocBook/80211.tmpl
MAINTAINERS
arch/mips/pci/pci-bcm47xx.c
drivers/bcma/bcma_private.h
drivers/bcma/driver_pci.c
drivers/bcma/driver_pci_host.c
drivers/bcma/host_pci.c
drivers/bcma/main.c
drivers/bcma/scan.c
drivers/bcma/sprom.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath6kl/Kconfig
drivers/net/wireless/ath/ath6kl/Makefile
drivers/net/wireless/ath/ath6kl/bmi.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.h
drivers/net/wireless/ath/ath6kl/common.h
drivers/net/wireless/ath/ath6kl/core.c [new file with mode: 0644]
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/debug.c
drivers/net/wireless/ath/ath6kl/debug.h
drivers/net/wireless/ath/ath6kl/hif.c
drivers/net/wireless/ath/ath6kl/htc.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath6kl/testmode.c
drivers/net/wireless/ath/ath6kl/testmode.h
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/usb.c [new file with mode: 0644]
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.h
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/hif_usb.h
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/carl9170/carl9170.h
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/ath/carl9170/mac.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/phy.c
drivers/net/wireless/ath/carl9170/tx.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/phy_n.h
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/b43/tables_nphy.h
drivers/net/wireless/brcm80211/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/dma.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/main.h
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
drivers/net/wireless/brcm80211/brcmutil/utils.c
drivers/net/wireless/brcm80211/include/brcmu_utils.h
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/3945-rs.c
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlegacy/3945.h
drivers/net/wireless/iwlegacy/4965-calib.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/4965-rs.c
drivers/net/wireless/iwlegacy/4965.c
drivers/net/wireless/iwlegacy/4965.h
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlegacy/debug.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.h
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.h
drivers/net/wireless/iwlwifi/iwl-agn-rx.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-sta.c
drivers/net/wireless/iwlwifi/iwl-agn-tt.c
drivers/net/wireless/iwlwifi/iwl-agn-tt.h
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-bus.h
drivers/net/wireless/iwlwifi/iwl-cfg.h
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-eeprom.h
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-led.h
drivers/net/wireless/iwlwifi/iwl-mac80211.c
drivers/net/wireless/iwlwifi/iwl-pci.c
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-power.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-shared.h
drivers/net/wireless/iwlwifi/iwl-testmode.c
drivers/net/wireless/iwlwifi/iwl-testmode.h
drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
drivers/net/wireless/iwlwifi/iwl-trans.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/iwl-ucode.c
drivers/net/wireless/iwlwifi/iwl-ucode.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-wifi.h
drivers/net/wireless/iwmc3200wifi/trace.h
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/decl.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/mwifiex/sta_rx.c
drivers/net/wireless/mwifiex/sta_tx.c
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/util.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/mwifiex/wmm.h
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/orinoco_usb.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rtlwifi/Kconfig
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/base.h
drivers/net/wireless/rtlwifi/cam.c
drivers/net/wireless/rtlwifi/cam.h
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/core.h
drivers/net/wireless/rtlwifi/debug.c
drivers/net/wireless/rtlwifi/debug.h
drivers/net/wireless/rtlwifi/efuse.c
drivers/net/wireless/rtlwifi/efuse.h
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/pci.h
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/ps.h
drivers/net/wireless/rtlwifi/rc.c
drivers/net/wireless/rtlwifi/rc.h
drivers/net/wireless/rtlwifi/regd.c
drivers/net/wireless/rtlwifi/regd.h
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
drivers/net/wireless/rtlwifi/rtl8192c/main.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
drivers/net/wireless/rtlwifi/rtl8192ce/def.h
drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
drivers/net/wireless/rtlwifi/rtl8192ce/led.c
drivers/net/wireless/rtlwifi/rtl8192ce/led.h
drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
drivers/net/wireless/rtlwifi/rtl8192ce/rf.h
drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
drivers/net/wireless/rtlwifi/rtl8192ce/sw.h
drivers/net/wireless/rtlwifi/rtl8192ce/table.c
drivers/net/wireless/rtlwifi/rtl8192ce/table.h
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
drivers/net/wireless/rtlwifi/rtl8192cu/def.h
drivers/net/wireless/rtlwifi/rtl8192cu/dm.c
drivers/net/wireless/rtlwifi/rtl8192cu/dm.h
drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
drivers/net/wireless/rtlwifi/rtl8192cu/led.c
drivers/net/wireless/rtlwifi/rtl8192cu/led.h
drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
drivers/net/wireless/rtlwifi/rtl8192cu/phy.h
drivers/net/wireless/rtlwifi/rtl8192cu/reg.h
drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
drivers/net/wireless/rtlwifi/rtl8192cu/rf.h
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.h
drivers/net/wireless/rtlwifi/rtl8192cu/table.c
drivers/net/wireless/rtlwifi/rtl8192cu/table.h
drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
drivers/net/wireless/rtlwifi/rtl8192de/def.h
drivers/net/wireless/rtlwifi/rtl8192de/dm.c
drivers/net/wireless/rtlwifi/rtl8192de/dm.h
drivers/net/wireless/rtlwifi/rtl8192de/fw.c
drivers/net/wireless/rtlwifi/rtl8192de/fw.h
drivers/net/wireless/rtlwifi/rtl8192de/hw.c
drivers/net/wireless/rtlwifi/rtl8192de/hw.h
drivers/net/wireless/rtlwifi/rtl8192de/led.c
drivers/net/wireless/rtlwifi/rtl8192de/led.h
drivers/net/wireless/rtlwifi/rtl8192de/phy.c
drivers/net/wireless/rtlwifi/rtl8192de/phy.h
drivers/net/wireless/rtlwifi/rtl8192de/reg.h
drivers/net/wireless/rtlwifi/rtl8192de/rf.c
drivers/net/wireless/rtlwifi/rtl8192de/rf.h
drivers/net/wireless/rtlwifi/rtl8192de/sw.c
drivers/net/wireless/rtlwifi/rtl8192de/sw.h
drivers/net/wireless/rtlwifi/rtl8192de/table.c
drivers/net/wireless/rtlwifi/rtl8192de/table.h
drivers/net/wireless/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.h
drivers/net/wireless/rtlwifi/rtl8192se/def.h
drivers/net/wireless/rtlwifi/rtl8192se/dm.c
drivers/net/wireless/rtlwifi/rtl8192se/dm.h
drivers/net/wireless/rtlwifi/rtl8192se/fw.c
drivers/net/wireless/rtlwifi/rtl8192se/fw.h
drivers/net/wireless/rtlwifi/rtl8192se/hw.c
drivers/net/wireless/rtlwifi/rtl8192se/hw.h
drivers/net/wireless/rtlwifi/rtl8192se/led.c
drivers/net/wireless/rtlwifi/rtl8192se/led.h
drivers/net/wireless/rtlwifi/rtl8192se/phy.c
drivers/net/wireless/rtlwifi/rtl8192se/phy.h
drivers/net/wireless/rtlwifi/rtl8192se/reg.h
drivers/net/wireless/rtlwifi/rtl8192se/rf.c
drivers/net/wireless/rtlwifi/rtl8192se/rf.h
drivers/net/wireless/rtlwifi/rtl8192se/sw.c
drivers/net/wireless/rtlwifi/rtl8192se/sw.h
drivers/net/wireless/rtlwifi/rtl8192se/table.c
drivers/net/wireless/rtlwifi/rtl8192se/table.h
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.h
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/usb.h
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/wl1251/main.c
drivers/net/wireless/wl12xx/main.c
drivers/nfc/nfcwilink.c
drivers/ssb/driver_chipcommon_pmu.c
drivers/ssb/driver_mipscore.c
drivers/ssb/main.c
drivers/ssb/pci.c
drivers/ssb/scan.c
drivers/ssb/ssb_private.h
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/bcma/bcma_driver_pci.h
include/linux/bcma/bcma_regs.h
include/linux/nfc.h
include/linux/nl80211.h
include/linux/ssb/ssb.h
include/linux/ssb/ssb_regs.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/nfc/nci.h
include/net/nfc/nci_core.h
include/net/nfc/nfc.h
net/mac80211/Makefile
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs.c
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/work.c
net/nfc/core.c
net/nfc/nci/core.c
net/nfc/nci/data.c
net/nfc/nci/ntf.c
net/nfc/nci/rsp.c
net/nfc/netlink.c
net/nfc/rawsock.c
net/wireless/core.h
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/scan.c
net/wireless/sme.c

index 2014155..c5ac692 100644 (file)
 !Finclude/net/cfg80211.h cfg80211_pmksa
 !Finclude/net/cfg80211.h cfg80211_send_rx_auth
 !Finclude/net/cfg80211.h cfg80211_send_auth_timeout
-!Finclude/net/cfg80211.h __cfg80211_auth_canceled
 !Finclude/net/cfg80211.h cfg80211_send_rx_assoc
 !Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
 !Finclude/net/cfg80211.h cfg80211_send_deauth
index 93c68d5..48418c8 100644 (file)
@@ -1412,7 +1412,7 @@ F:        net/ax25/
 B43 WIRELESS DRIVER
 M:     Stefano Brivio <stefano.brivio@polimi.it>
 L:     linux-wireless@vger.kernel.org
-L:     b43-dev@lists.infradead.org (moderated for non-subscribers)
+L:     b43-dev@lists.infradead.org
 W:     http://linuxwireless.org/en/users/Drivers/b43
 S:     Maintained
 F:     drivers/net/wireless/b43/
@@ -1421,6 +1421,7 @@ B43LEGACY WIRELESS DRIVER
 M:     Larry Finger <Larry.Finger@lwfinger.net>
 M:     Stefano Brivio <stefano.brivio@polimi.it>
 L:     linux-wireless@vger.kernel.org
+L:     b43-dev@lists.infradead.org
 W:     http://linuxwireless.org/en/users/Drivers/b43
 S:     Maintained
 F:     drivers/net/wireless/b43legacy/
@@ -4915,8 +4916,6 @@ F:        fs/ocfs2/
 
 ORINOCO DRIVER
 L:     linux-wireless@vger.kernel.org
-L:     orinoco-users@lists.sourceforge.net
-L:     orinoco-devel@lists.sourceforge.net
 W:     http://linuxwireless.org/en/users/Drivers/orinoco
 W:     http://www.nongnu.org/orinoco/
 S:     Orphan
index 400535a..c682468 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/ssb/ssb.h>
+#include <linux/bcma/bcma.h>
 #include <bcm47xx.h>
 
 int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
@@ -32,15 +33,12 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return 0;
 }
 
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
 #ifdef CONFIG_BCM47XX_SSB
+static int bcm47xx_pcibios_plat_dev_init_ssb(struct pci_dev *dev)
+{
        int res;
        u8 slot, pin;
 
-       if (bcm47xx_bus_type !=  BCM47XX_BUS_TYPE_SSB)
-               return 0;
-
        res = ssb_pcibios_plat_dev_init(dev);
        if (res < 0) {
                printk(KERN_ALERT "PCI: Failed to init device %s\n",
@@ -60,6 +58,47 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
        }
 
        dev->irq = res;
+       return 0;
+}
 #endif
+
+#ifdef CONFIG_BCM47XX_BCMA
+static int bcm47xx_pcibios_plat_dev_init_bcma(struct pci_dev *dev)
+{
+       int res;
+
+       res = bcma_core_pci_plat_dev_init(dev);
+       if (res < 0) {
+               printk(KERN_ALERT "PCI: Failed to init device %s\n",
+                      pci_name(dev));
+               return res;
+       }
+
+       res = bcma_core_pci_pcibios_map_irq(dev);
+
+       /* IRQ-0 and IRQ-1 are software interrupts. */
+       if (res < 2) {
+               printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n",
+                      pci_name(dev));
+               return res;
+       }
+
+       dev->irq = res;
        return 0;
 }
+#endif
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+#ifdef CONFIG_BCM47XX_SSB
+       if (bcm47xx_bus_type ==  BCM47XX_BUS_TYPE_SSB)
+               return bcm47xx_pcibios_plat_dev_init_ssb(dev);
+       else
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+       if  (bcm47xx_bus_type ==  BCM47XX_BUS_TYPE_BCMA)
+               return bcm47xx_pcibios_plat_dev_init_bcma(dev);
+       else
+#endif
+               return 0;
+}
index 0def898..b81755b 100644 (file)
@@ -13,7 +13,7 @@
 struct bcma_bus;
 
 /* main.c */
-int bcma_bus_register(struct bcma_bus *bus);
+int __devinit bcma_bus_register(struct bcma_bus *bus);
 void bcma_bus_unregister(struct bcma_bus *bus);
 int __init bcma_bus_early_register(struct bcma_bus *bus,
                                   struct bcma_device *core_cc,
@@ -48,8 +48,12 @@ extern int __init bcma_host_pci_init(void);
 extern void __exit bcma_host_pci_exit(void);
 #endif /* CONFIG_BCMA_HOST_PCI */
 
+/* driver_pci.c */
+u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
+
 #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
-void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
+void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
 #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
 
 #endif
index 4fde625..4d38ae1 100644 (file)
@@ -2,8 +2,9 @@
  * Broadcom specific AMBA
  * PCI Core
  *
- * Copyright 2005, Broadcom Corporation
+ * Copyright 2005, 2011, Broadcom Corporation
  * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
  *
  * Licensed under the GNU/GPL. See COPYING for details.
  */
  * R/W ops.
  **************************************************/
 
-static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
+u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
 {
-       pcicore_write32(pc, 0x130, address);
-       pcicore_read32(pc, 0x130);
-       return pcicore_read32(pc, 0x134);
+       pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
+       pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
+       return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA);
 }
 
 #if 0
 static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
 {
-       pcicore_write32(pc, 0x130, address);
-       pcicore_read32(pc, 0x130);
-       pcicore_write32(pc, 0x134, data);
+       pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
+       pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
+       pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data);
 }
 #endif
 
 static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
 {
-       const u16 mdio_control = 0x128;
-       const u16 mdio_data = 0x12C;
        u32 v;
        int i;
 
-       v = (1 << 30); /* Start of Transaction */
-       v |= (1 << 28); /* Write Transaction */
-       v |= (1 << 17); /* Turnaround */
-       v |= (0x1F << 18);
+       v = BCMA_CORE_PCI_MDIODATA_START;
+       v |= BCMA_CORE_PCI_MDIODATA_WRITE;
+       v |= (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
+             BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
+       v |= (BCMA_CORE_PCI_MDIODATA_BLK_ADDR <<
+             BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
+       v |= BCMA_CORE_PCI_MDIODATA_TA;
        v |= (phy << 4);
-       pcicore_write32(pc, mdio_data, v);
+       pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
 
        udelay(10);
        for (i = 0; i < 200; i++) {
-               v = pcicore_read32(pc, mdio_control);
-               if (v & 0x100 /* Trans complete */)
+               v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
+               if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
                        break;
                msleep(1);
        }
@@ -57,79 +59,84 @@ static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
 
 static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
 {
-       const u16 mdio_control = 0x128;
-       const u16 mdio_data = 0x12C;
        int max_retries = 10;
        u16 ret = 0;
        u32 v;
        int i;
 
-       v = 0x80; /* Enable Preamble Sequence */
-       v |= 0x2; /* MDIO Clock Divisor */
-       pcicore_write32(pc, mdio_control, v);
+       /* enable mdio access to SERDES */
+       v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
+       v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
+       pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
 
        if (pc->core->id.rev >= 10) {
                max_retries = 200;
                bcma_pcie_mdio_set_phy(pc, device);
+               v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
+                    BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
+               v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
+       } else {
+               v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
+               v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
        }
 
-       v = (1 << 30); /* Start of Transaction */
-       v |= (1 << 29); /* Read Transaction */
-       v |= (1 << 17); /* Turnaround */
-       if (pc->core->id.rev < 10)
-               v |= (u32)device << 22;
-       v |= (u32)address << 18;
-       pcicore_write32(pc, mdio_data, v);
+       v = BCMA_CORE_PCI_MDIODATA_START;
+       v |= BCMA_CORE_PCI_MDIODATA_READ;
+       v |= BCMA_CORE_PCI_MDIODATA_TA;
+
+       pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
        /* Wait for the device to complete the transaction */
        udelay(10);
        for (i = 0; i < max_retries; i++) {
-               v = pcicore_read32(pc, mdio_control);
-               if (v & 0x100 /* Trans complete */) {
+               v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
+               if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE) {
                        udelay(10);
-                       ret = pcicore_read32(pc, mdio_data);
+                       ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA);
                        break;
                }
                msleep(1);
        }
-       pcicore_write32(pc, mdio_control, 0);
+       pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
        return ret;
 }
 
 static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
                                u8 address, u16 data)
 {
-       const u16 mdio_control = 0x128;
-       const u16 mdio_data = 0x12C;
        int max_retries = 10;
        u32 v;
        int i;
 
-       v = 0x80; /* Enable Preamble Sequence */
-       v |= 0x2; /* MDIO Clock Divisor */
-       pcicore_write32(pc, mdio_control, v);
+       /* enable mdio access to SERDES */
+       v = BCMA_CORE_PCI_MDIOCTL_PREAM_EN;
+       v |= BCMA_CORE_PCI_MDIOCTL_DIVISOR_VAL;
+       pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, v);
 
        if (pc->core->id.rev >= 10) {
                max_retries = 200;
                bcma_pcie_mdio_set_phy(pc, device);
+               v = (BCMA_CORE_PCI_MDIODATA_DEV_ADDR <<
+                    BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF);
+               v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF);
+       } else {
+               v = (device << BCMA_CORE_PCI_MDIODATA_DEVADDR_SHF_OLD);
+               v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD);
        }
 
-       v = (1 << 30); /* Start of Transaction */
-       v |= (1 << 28); /* Write Transaction */
-       v |= (1 << 17); /* Turnaround */
-       if (pc->core->id.rev < 10)
-               v |= (u32)device << 22;
-       v |= (u32)address << 18;
+       v = BCMA_CORE_PCI_MDIODATA_START;
+       v |= BCMA_CORE_PCI_MDIODATA_WRITE;
+       v |= BCMA_CORE_PCI_MDIODATA_TA;
        v |= data;
-       pcicore_write32(pc, mdio_data, v);
+       pcicore_write32(pc, BCMA_CORE_PCI_MDIO_DATA, v);
        /* Wait for the device to complete the transaction */
        udelay(10);
        for (i = 0; i < max_retries; i++) {
-               v = pcicore_read32(pc, mdio_control);
-               if (v & 0x100 /* Trans complete */)
+               v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
+               if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
                        break;
                msleep(1);
        }
-       pcicore_write32(pc, mdio_control, 0);
+       pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
 }
 
 /**************************************************
@@ -138,72 +145,53 @@ static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
 
 static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc)
 {
-       return (bcma_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
+       u32 tmp;
+
+       tmp = bcma_pcie_read(pc, BCMA_CORE_PCI_PLP_STATUSREG);
+       if (tmp & BCMA_CORE_PCI_PLP_POLARITYINV_STAT)
+               return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE |
+                      BCMA_CORE_PCI_SERDES_RX_CTRL_POLARITY;
+       else
+               return BCMA_CORE_PCI_SERDES_RX_CTRL_FORCE;
 }
 
 static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
 {
-       const u8 serdes_pll_device = 0x1D;
-       const u8 serdes_rx_device = 0x1F;
        u16 tmp;
 
-       bcma_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
-                             bcma_pcicore_polarity_workaround(pc));
-       tmp = bcma_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
-       if (tmp & 0x4000)
-               bcma_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
+       bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_RX,
+                            BCMA_CORE_PCI_SERDES_RX_CTRL,
+                            bcma_pcicore_polarity_workaround(pc));
+       tmp = bcma_pcie_mdio_read(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
+                                 BCMA_CORE_PCI_SERDES_PLL_CTRL);
+       if (tmp & BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN)
+               bcma_pcie_mdio_write(pc, BCMA_CORE_PCI_MDIODATA_DEV_PLL,
+                                    BCMA_CORE_PCI_SERDES_PLL_CTRL,
+                                    tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
 }
 
 /**************************************************
  * Init.
  **************************************************/
 
-static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
+static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *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;
-
-#ifdef CONFIG_SSB_DRIVER_PCICORE
-       if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
-               return false;
-#endif /* CONFIG_SSB_DRIVER_PCICORE */
-
-#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)
+void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc)
 {
        if (pc->setup_done)
                return;
 
-       if (bcma_core_pci_is_in_hostmode(pc)) {
 #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+       pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
+       if (pc->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);
-       }
 
-       pc->setup_done = true;
+       if (!pc->hostmode)
+               bcma_core_pci_clientmode_init(pc);
 }
 
 int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
index eb332b7..4e20bcf 100644 (file)
  * Broadcom specific AMBA
  * PCI Core in hostmode
  *
+ * Copyright 2005 - 2011, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
+ *
  * Licensed under the GNU/GPL. See COPYING for details.
  */
 
 #include "bcma_private.h"
+#include <linux/export.h>
 #include <linux/bcma/bcma.h>
+#include <asm/paccess.h>
+
+/* Probe a 32bit value on the bus and catch bus exceptions.
+ * Returns nonzero on a bus exception.
+ * This is MIPS specific */
+#define mips_busprobe32(val, addr)     get_dbe((val), ((u32 *)(addr)))
+
+/* Assume one-hot slot wiring */
+#define BCMA_PCI_SLOT_MAX      16
+#define        PCI_CONFIG_SPACE_SIZE   256
+
+bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
+{
+       struct bcma_bus *bus = pc->core->bus;
+       u16 chipid_top;
+       u32 tmp;
+
+       chipid_top = (bus->chipinfo.id & 0xFF00);
+       if (chipid_top != 0x4700 &&
+           chipid_top != 0x5300)
+               return false;
+
+       if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
+               pr_info("This PCI core is disabled and not working\n");
+               return false;
+       }
+
+       bcma_core_enable(pc->core, 0);
+
+       return !mips_busprobe32(tmp, pc->core->io_addr);
+}
+
+static u32 bcma_pcie_read_config(struct bcma_drv_pci *pc, u32 address)
+{
+       pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
+       pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
+       return pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_DATA);
+}
+
+static void bcma_pcie_write_config(struct bcma_drv_pci *pc, u32 address,
+                                  u32 data)
+{
+       pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_ADDR, address);
+       pcicore_read32(pc, BCMA_CORE_PCI_CONFIG_ADDR);
+       pcicore_write32(pc, BCMA_CORE_PCI_CONFIG_DATA, data);
+}
+
+static u32 bcma_get_cfgspace_addr(struct bcma_drv_pci *pc, unsigned int dev,
+                            unsigned int func, unsigned int off)
+{
+       u32 addr = 0;
+
+       /* Issue config commands only when the data link is up (atleast
+        * one external pcie device is present).
+        */
+       if (dev >= 2 || !(bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_LSREG)
+                         & BCMA_CORE_PCI_DLLP_LSREG_LINKUP))
+               goto out;
+
+       /* Type 0 transaction */
+       /* Slide the PCI window to the appropriate slot */
+       pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI1, BCMA_CORE_PCI_SBTOPCI_CFG0);
+       /* Calculate the address */
+       addr = pc->host_controller->host_cfg_addr;
+       addr |= (dev << BCMA_CORE_PCI_CFG_SLOT_SHIFT);
+       addr |= (func << BCMA_CORE_PCI_CFG_FUN_SHIFT);
+       addr |= (off & ~3);
+
+out:
+       return addr;
+}
 
-void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
+                                 unsigned int func, unsigned int off,
+                                 void *buf, int len)
 {
-       pr_err("No support for PCI core in hostmode yet\n");
+       int err = -EINVAL;
+       u32 addr, val;
+       void __iomem *mmio = 0;
+
+       WARN_ON(!pc->hostmode);
+       if (unlikely(len != 1 && len != 2 && len != 4))
+               goto out;
+       if (dev == 0) {
+               /* we support only two functions on device 0 */
+               if (func > 1)
+                       return -EINVAL;
+
+               /* accesses to config registers with offsets >= 256
+                * requires indirect access.
+                */
+               if (off >= PCI_CONFIG_SPACE_SIZE) {
+                       addr = (func << 12);
+                       addr |= (off & 0x0FFF);
+                       val = bcma_pcie_read_config(pc, addr);
+               } else {
+                       addr = BCMA_CORE_PCI_PCICFG0;
+                       addr |= (func << 8);
+                       addr |= (off & 0xfc);
+                       val = pcicore_read32(pc, addr);
+               }
+       } else {
+               addr = bcma_get_cfgspace_addr(pc, dev, func, off);
+               if (unlikely(!addr))
+                       goto out;
+               err = -ENOMEM;
+               mmio = ioremap_nocache(addr, len);
+               if (!mmio)
+                       goto out;
+
+               if (mips_busprobe32(val, mmio)) {
+                       val = 0xffffffff;
+                       goto unmap;
+               }
+
+               val = readl(mmio);
+       }
+       val >>= (8 * (off & 3));
+
+       switch (len) {
+       case 1:
+               *((u8 *)buf) = (u8)val;
+               break;
+       case 2:
+               *((u16 *)buf) = (u16)val;
+               break;
+       case 4:
+               *((u32 *)buf) = (u32)val;
+               break;
+       }
+       err = 0;
+unmap:
+       if (mmio)
+               iounmap(mmio);
+out:
+       return err;
+}
+
+static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
+                                  unsigned int func, unsigned int off,
+                                  const void *buf, int len)
+{
+       int err = -EINVAL;
+       u32 addr = 0, val = 0;
+       void __iomem *mmio = 0;
+       u16 chipid = pc->core->bus->chipinfo.id;
+
+       WARN_ON(!pc->hostmode);
+       if (unlikely(len != 1 && len != 2 && len != 4))
+               goto out;
+       if (dev == 0) {
+               /* accesses to config registers with offsets >= 256
+                * requires indirect access.
+                */
+               if (off < PCI_CONFIG_SPACE_SIZE) {
+                       addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
+                       addr |= (func << 8);
+                       addr |= (off & 0xfc);
+                       mmio = ioremap_nocache(addr, len);
+                       if (!mmio)
+                               goto out;
+               }
+       } else {
+               addr = bcma_get_cfgspace_addr(pc, dev, func, off);
+               if (unlikely(!addr))
+                       goto out;
+               err = -ENOMEM;
+               mmio = ioremap_nocache(addr, len);
+               if (!mmio)
+                       goto out;
+
+               if (mips_busprobe32(val, mmio)) {
+                       val = 0xffffffff;
+                       goto unmap;
+               }
+       }
+
+       switch (len) {
+       case 1:
+               val = readl(mmio);
+               val &= ~(0xFF << (8 * (off & 3)));
+               val |= *((const u8 *)buf) << (8 * (off & 3));
+               break;
+       case 2:
+               val = readl(mmio);
+               val &= ~(0xFFFF << (8 * (off & 3)));
+               val |= *((const u16 *)buf) << (8 * (off & 3));
+               break;
+       case 4:
+               val = *((const u32 *)buf);
+               break;
+       }
+       if (dev == 0 && !addr) {
+               /* accesses to config registers with offsets >= 256
+                * requires indirect access.
+                */
+               addr = (func << 12);
+               addr |= (off & 0x0FFF);
+               bcma_pcie_write_config(pc, addr, val);
+       } else {
+               writel(val, mmio);
+
+               if (chipid == 0x4716 || chipid == 0x4748)
+                       readl(mmio);
+       }
+
+       err = 0;
+unmap:
+       if (mmio)
+               iounmap(mmio);
+out:
+       return err;
+}
+
+static int bcma_core_pci_hostmode_read_config(struct pci_bus *bus,
+                                             unsigned int devfn,
+                                             int reg, int size, u32 *val)
+{
+       unsigned long flags;
+       int err;
+       struct bcma_drv_pci *pc;
+       struct bcma_drv_pci_host *pc_host;
+
+       pc_host = container_of(bus->ops, struct bcma_drv_pci_host, pci_ops);
+       pc = pc_host->pdev;
+
+       spin_lock_irqsave(&pc_host->cfgspace_lock, flags);
+       err = bcma_extpci_read_config(pc, PCI_SLOT(devfn),
+                                    PCI_FUNC(devfn), reg, val, size);
+       spin_unlock_irqrestore(&pc_host->cfgspace_lock, flags);
+
+       return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int bcma_core_pci_hostmode_write_config(struct pci_bus *bus,
+                                              unsigned int devfn,
+                                              int reg, int size, u32 val)
+{
+       unsigned long flags;
+       int err;
+       struct bcma_drv_pci *pc;
+       struct bcma_drv_pci_host *pc_host;
+
+       pc_host = container_of(bus->ops, struct bcma_drv_pci_host, pci_ops);
+       pc = pc_host->pdev;
+
+       spin_lock_irqsave(&pc_host->cfgspace_lock, flags);
+       err = bcma_extpci_write_config(pc, PCI_SLOT(devfn),
+                                     PCI_FUNC(devfn), reg, &val, size);
+       spin_unlock_irqrestore(&pc_host->cfgspace_lock, flags);
+
+       return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+/* return cap_offset if requested capability exists in the PCI config space */
+static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc,
+                                            unsigned int dev,
+                                            unsigned int func, u8 req_cap_id,
+                                            unsigned char *buf, u32 *buflen)
+{
+       u8 cap_id;
+       u8 cap_ptr = 0;
+       u32 bufsize;
+       u8 byte_val;
+
+       /* check for Header type 0 */
+       bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val,
+                               sizeof(u8));
+       if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
+               return cap_ptr;
+
+       /* check if the capability pointer field exists */
+       bcma_extpci_read_config(pc, dev, func, PCI_STATUS, &byte_val,
+                               sizeof(u8));
+       if (!(byte_val & PCI_STATUS_CAP_LIST))
+               return cap_ptr;
+
+       /* check if the capability pointer is 0x00 */
+       bcma_extpci_read_config(pc, dev, func, PCI_CAPABILITY_LIST, &cap_ptr,
+                               sizeof(u8));
+       if (cap_ptr == 0x00)
+               return cap_ptr;
+
+       /* loop thr'u the capability list and see if the requested capabilty
+        * exists */
+       bcma_extpci_read_config(pc, dev, func, cap_ptr, &cap_id, sizeof(u8));
+       while (cap_id != req_cap_id) {
+               bcma_extpci_read_config(pc, dev, func, cap_ptr + 1, &cap_ptr,
+                                       sizeof(u8));
+               if (cap_ptr == 0x00)
+                       return cap_ptr;
+               bcma_extpci_read_config(pc, dev, func, cap_ptr, &cap_id,
+                                       sizeof(u8));
+       }
+
+       /* found the caller requested capability */
+       if ((buf != NULL) && (buflen != NULL)) {
+               u8 cap_data;
+
+               bufsize = *buflen;
+               if (!bufsize)
+                       return cap_ptr;
+
+               *buflen = 0;
+
+               /* copy the cpability data excluding cap ID and next ptr */
+               cap_data = cap_ptr + 2;
+               if ((bufsize + cap_data)  > PCI_CONFIG_SPACE_SIZE)
+                       bufsize = PCI_CONFIG_SPACE_SIZE - cap_data;
+               *buflen = bufsize;
+               while (bufsize--) {
+                       bcma_extpci_read_config(pc, dev, func, cap_data, buf,
+                                               sizeof(u8));
+                       cap_data++;
+                       buf++;
+               }
+       }
+
+       return cap_ptr;
+}
+
+/* If the root port is capable of returning Config Request
+ * Retry Status (CRS) Completion Status to software then
+ * enable the feature.
+ */
+static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc)
+{
+       u8 cap_ptr, root_ctrl, root_cap, dev;
+       u16 val16;
+       int i;
+
+       cap_ptr = bcma_find_pci_capability(pc, 0, 0, PCI_CAP_ID_EXP, NULL,
+                                          NULL);
+       root_cap = cap_ptr + PCI_EXP_RTCAP;
+       bcma_extpci_read_config(pc, 0, 0, root_cap, &val16, sizeof(u16));
+       if (val16 & BCMA_CORE_PCI_RC_CRS_VISIBILITY) {
+               /* Enable CRS software visibility */
+               root_ctrl = cap_ptr + PCI_EXP_RTCTL;
+               val16 = PCI_EXP_RTCTL_CRSSVE;
+               bcma_extpci_read_config(pc, 0, 0, root_ctrl, &val16,
+                                       sizeof(u16));
+
+               /* Initiate a configuration request to read the vendor id
+                * field of the device function's config space header after
+                * 100 ms wait time from the end of Reset. If the device is
+                * not done with its internal initialization, it must at
+                * least return a completion TLP, with a completion status
+                * of "Configuration Request Retry Status (CRS)". The root
+                * complex must complete the request to the host by returning
+                * a read-data value of 0001h for the Vendor ID field and
+                * all 1s for any additional bytes included in the request.
+                * Poll using the config reads for max wait time of 1 sec or
+                * until we receive the successful completion status. Repeat
+                * the procedure for all the devices.
+                */
+               for (dev = 1; dev < BCMA_PCI_SLOT_MAX; dev++) {
+                       for (i = 0; i < 100000; i++) {
+                               bcma_extpci_read_config(pc, dev, 0,
+                                                       PCI_VENDOR_ID, &val16,
+                                                       sizeof(val16));
+                               if (val16 != 0x1)
+                                       break;
+                               udelay(10);
+                       }
+                       if (val16 == 0x1)
+                               pr_err("PCI: Broken device in slot %d\n", dev);
+               }
+       }
+}
+
+void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+{
+       struct bcma_bus *bus = pc->core->bus;
+       struct bcma_drv_pci_host *pc_host;
+       u32 tmp;
+       u32 pci_membase_1G;
+       unsigned long io_map_base;
+
+       pr_info("PCIEcore in host mode found\n");
+
+       pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
+       if (!pc_host)  {
+               pr_err("can not allocate memory");
+               return;
+       }
+
+       pc->host_controller = pc_host;
+       pc_host->pci_controller.io_resource = &pc_host->io_resource;
+       pc_host->pci_controller.mem_resource = &pc_host->mem_resource;
+       pc_host->pci_controller.pci_ops = &pc_host->pci_ops;
+       pc_host->pdev = pc;
+
+       pci_membase_1G = BCMA_SOC_PCI_DMA;
+       pc_host->host_cfg_addr = BCMA_SOC_PCI_CFG;
+
+       pc_host->pci_ops.read = bcma_core_pci_hostmode_read_config;
+       pc_host->pci_ops.write = bcma_core_pci_hostmode_write_config;
+
+       pc_host->mem_resource.name = "BCMA PCIcore external memory",
+       pc_host->mem_resource.start = BCMA_SOC_PCI_DMA;
+       pc_host->mem_resource.end = BCMA_SOC_PCI_DMA + BCMA_SOC_PCI_DMA_SZ - 1;
+       pc_host->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
+
+       pc_host->io_resource.name = "BCMA PCIcore external I/O",
+       pc_host->io_resource.start = 0x100;
+       pc_host->io_resource.end = 0x7FF;
+       pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
+
+       /* Reset RC */
+       udelay(3000);
+       pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
+       udelay(1000);
+       pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
+                       BCMA_CORE_PCI_CTL_RST_OE);
+
+       /* 64 MB I/O access window. On 4716, use
+        * sbtopcie0 to access the device registers. We
+        * can't use address match 2 (1 GB window) region
+        * as mips can't generate 64-bit address on the
+        * backplane.
+        */
+       if (bus->chipinfo.id == 0x4716 || bus->chipinfo.id == 0x4748) {
+               pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
+               pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
+                                           BCMA_SOC_PCI_MEM_SZ - 1;
+               pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
+                               BCMA_CORE_PCI_SBTOPCI_MEM | BCMA_SOC_PCI_MEM);
+       } else if (bus->chipinfo.id == 0x5300) {
+               tmp = BCMA_CORE_PCI_SBTOPCI_MEM;
+               tmp |= BCMA_CORE_PCI_SBTOPCI_PREF;
+               tmp |= BCMA_CORE_PCI_SBTOPCI_BURST;
+               if (pc->core->core_unit == 0) {
+                       pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
+                       pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
+                                                   BCMA_SOC_PCI_MEM_SZ - 1;
+                       pci_membase_1G = BCMA_SOC_PCIE_DMA_H32;
+                       pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
+                                       tmp | BCMA_SOC_PCI_MEM);
+               } else if (pc->core->core_unit == 1) {
+                       pc_host->mem_resource.start = BCMA_SOC_PCI1_MEM;
+                       pc_host->mem_resource.end = BCMA_SOC_PCI1_MEM +
+                                                   BCMA_SOC_PCI_MEM_SZ - 1;
+                       pci_membase_1G = BCMA_SOC_PCIE1_DMA_H32;
+                       pc_host->host_cfg_addr = BCMA_SOC_PCI1_CFG;
+                       pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
+                                       tmp | BCMA_SOC_PCI1_MEM);
+               }
+       } else
+               pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
+                               BCMA_CORE_PCI_SBTOPCI_IO);
+
+       /* 64 MB configuration access window */
+       pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI1, BCMA_CORE_PCI_SBTOPCI_CFG0);
+
+       /* 1 GB memory access window */
+       pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI2,
+                       BCMA_CORE_PCI_SBTOPCI_MEM | pci_membase_1G);
+
+
+       /* As per PCI Express Base Spec 1.1 we need to wait for
+        * at least 100 ms from the end of a reset (cold/warm/hot)
+        * before issuing configuration requests to PCI Express
+        * devices.
+        */
+       udelay(100000);
+
+       bcma_core_pci_enable_crs(pc);
+
+       /* Enable PCI bridge BAR0 memory & master access */
+       tmp = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       bcma_extpci_write_config(pc, 0, 0, PCI_COMMAND, &tmp, sizeof(tmp));
+
+       /* Enable PCI interrupts */
+       pcicore_write32(pc, BCMA_CORE_PCI_IMASK, BCMA_CORE_PCI_IMASK_INTA);
+
+       /* Ok, ready to run, register it to the system.
+        * The following needs change, if we want to port hostmode
+        * to non-MIPS platform. */
+       io_map_base = (unsigned long)ioremap_nocache(BCMA_SOC_PCI_MEM,
+                                                    0x04000000);
+       pc_host->pci_controller.io_map_base = io_map_base;
+       set_io_port_base(pc_host->pci_controller.io_map_base);
+       /* Give some time to the PCI controller to configure itself with the new
+        * values. Not waiting at this point causes crashes of the machine. */
+       mdelay(10);
+       register_pci_controller(&pc_host->pci_controller);
+       return;
+}
+
+/* Early PCI fixup for a device on the PCI-core bridge. */
+static void bcma_core_pci_fixup_pcibridge(struct pci_dev *dev)
+{
+       if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
+               /* This is not a device on the PCI-core bridge. */
+               return;
+       }
+       if (PCI_SLOT(dev->devfn) != 0)
+               return;
+
+       pr_info("PCI: Fixing up bridge %s\n", pci_name(dev));
+
+       /* Enable PCI bridge bus mastering and memory space */
+       pci_set_master(dev);
+       if (pcibios_enable_device(dev, ~0) < 0) {
+               pr_err("PCI: BCMA bridge enable failed\n");
+               return;
+       }
+
+       /* Enable PCI bridge BAR1 prefetch and burst */
+       pci_write_config_dword(dev, BCMA_PCI_BAR1_CONTROL, 3);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_pcibridge);
+
+/* Early PCI fixup for all PCI-cores to set the correct memory address. */
+static void bcma_core_pci_fixup_addresses(struct pci_dev *dev)
+{
+       struct resource *res;
+       int pos;
+
+       if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
+               /* This is not a device on the PCI-core bridge. */
+               return;
+       }
+       if (PCI_SLOT(dev->devfn) == 0)
+               return;
+
+       pr_info("PCI: Fixing up addresses %s\n", pci_name(dev));
+
+       for (pos = 0; pos < 6; pos++) {
+               res = &dev->resource[pos];
+               if (res->flags & (IORESOURCE_IO | IORESOURCE_MEM))
+                       pci_assign_resource(dev, pos);
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, bcma_core_pci_fixup_addresses);
+
+/* This function is called when doing a pci_enable_device().
+ * We must first check if the device is a device on the PCI-core bridge. */
+int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
+{
+       struct bcma_drv_pci_host *pc_host;
+
+       if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
+               /* This is not a device on the PCI-core bridge. */
+               return -ENODEV;
+       }
+       pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
+                              pci_ops);
+
+       pr_info("PCI: Fixing up device %s\n", pci_name(dev));
+
+       /* Fix up interrupt lines */
+       dev->irq = bcma_core_mips_irq(pc_host->pdev->core) + 2;
+       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+
+       return 0;
+}
+EXPORT_SYMBOL(bcma_core_pci_plat_dev_init);
+
+/* PCI device IRQ mapping. */
+int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
+{
+       struct bcma_drv_pci_host *pc_host;
+
+       if (dev->bus->ops->read != bcma_core_pci_hostmode_read_config) {
+               /* This is not a device on the PCI-core bridge. */
+               return -ENODEV;
+       }
+
+       pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
+                              pci_ops);
+       return bcma_core_mips_irq(pc_host->pdev->core) + 2;
 }
+EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
index f59244e..e3928d6 100644 (file)
@@ -154,8 +154,8 @@ const struct bcma_host_ops bcma_host_pci_ops = {
        .awrite32       = bcma_host_pci_awrite32,
 };
 
-static int bcma_host_pci_probe(struct pci_dev *dev,
-                            const struct pci_device_id *id)
+static int __devinit bcma_host_pci_probe(struct pci_dev *dev,
+                                        const struct pci_device_id *id)
 {
        struct bcma_bus *bus;
        int err = -ENOMEM;
index ec31f7d..b8379b9 100644 (file)
 MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
 MODULE_LICENSE("GPL");
 
+/* contains the number the next bus should get. */
+static unsigned int bcma_bus_next_num = 0;
+
+/* bcma_buses_mutex locks the bcma_bus_next_num */
+static DEFINE_MUTEX(bcma_buses_mutex);
+
 static int bcma_bus_match(struct device *dev, struct device_driver *drv);
 static int bcma_device_probe(struct device *dev);
 static int bcma_device_remove(struct device *dev);
@@ -93,7 +99,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
 
                core->dev.release = bcma_release_core_dev;
                core->dev.bus = &bcma_bus_type;
-               dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
+               dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
 
                switch (bus->hosttype) {
                case BCMA_HOSTTYPE_PCI:
@@ -132,11 +138,15 @@ static void bcma_unregister_cores(struct bcma_bus *bus)
        }
 }
 
-int bcma_bus_register(struct bcma_bus *bus)
+int __devinit bcma_bus_register(struct bcma_bus *bus)
 {
        int err;
        struct bcma_device *core;
 
+       mutex_lock(&bcma_buses_mutex);
+       bus->num = bcma_bus_next_num++;
+       mutex_unlock(&bcma_buses_mutex);
+
        /* Scan for devices (cores) */
        err = bcma_bus_scan(bus);
        if (err) {
index 3a2f672..f94cccc 100644 (file)
@@ -212,6 +212,17 @@ static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
        return NULL;
 }
 
+static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 coreid)
+{
+       struct bcma_device *core;
+
+       list_for_each_entry_reverse(core, &bus->cores, list) {
+               if (core->id.id == coreid)
+                       return core;
+       }
+       return NULL;
+}
+
 static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                              struct bcma_device_id *match, int core_num,
                              struct bcma_device *core)
@@ -353,6 +364,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
 void bcma_init_bus(struct bcma_bus *bus)
 {
        s32 tmp;
+       struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
 
        if (bus->init_done)
                return;
@@ -363,9 +375,12 @@ void bcma_init_bus(struct bcma_bus *bus)
        bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
 
        tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
-       bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
-       bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
-       bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+       chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
+       chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
+       chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+       pr_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
+               chipinfo->id, chipinfo->rev, chipinfo->pkg);
+
        bus->init_done = true;
 }
 
@@ -392,6 +407,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
        bcma_scan_switch_core(bus, erombase);
 
        while (eromptr < eromend) {
+               struct bcma_device *other_core;
                struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
                if (!core)
                        return -ENOMEM;
@@ -414,6 +430,8 @@ int bcma_bus_scan(struct bcma_bus *bus)
 
                core->core_index = core_num++;
                bus->nr_cores++;
+               other_core = bcma_find_core_reverse(bus, core->id.id);
+               core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
 
                pr_info("Core %d found: %s "
                        "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
index 6f230fb..ca77525 100644 (file)
@@ -14,8 +14,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 
-#define SPOFF(offset)  ((offset) / sizeof(u16))
-
 /**************************************************
  * R/W ops.
  **************************************************/
@@ -124,10 +122,21 @@ static int bcma_sprom_valid(const u16 *sprom)
  * SPROM extraction.
  **************************************************/
 
+#define SPOFF(offset)  ((offset) / sizeof(u16))
+
+#define SPEX(_field, _offset, _mask, _shift)   \
+       bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
+
 static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
 {
-       u16 v;
+       u16 v, o;
        int i;
+       u16 pwr_info_offset[] = {
+               SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
+               SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
+       };
+       BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
+                       ARRAY_SIZE(bus->sprom.core_pwr_info));
 
        bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
                SSB_SPROM_REVISION_REV;
@@ -137,78 +146,111 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
                *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
        }
 
-       bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
-
-       bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
-            SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
-       bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
-            SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
-       bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
-            SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
-       bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
-            SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
-
-       bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
-            SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
-       bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
-            SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
-       bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
-            SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
-       bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
-            SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
-
-       bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
-            SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
-       bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
-            SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
-       bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
-            SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
-       bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
-            SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
-
-       bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
-            SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
-       bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
-            SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
-       bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
-            SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
-       bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
-            SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
-
-       bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
-       bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
-       bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
-       bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
-
-       bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
-
-       bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-               SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
-       bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-               SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
-       bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-               SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
-       bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-               SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
-       bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-               SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
-
-       bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-               SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
-       bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-               SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
-       bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-               SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
-       bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-               SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
-       bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-               SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
+       SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
+
+       SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
+            SSB_SPROM4_TXPID2G0_SHIFT);
+       SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
+            SSB_SPROM4_TXPID2G1_SHIFT);
+       SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2,
+            SSB_SPROM4_TXPID2G2_SHIFT);
+       SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3,
+            SSB_SPROM4_TXPID2G3_SHIFT);
+
+       SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0,
+            SSB_SPROM4_TXPID5GL0_SHIFT);
+       SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1,
+            SSB_SPROM4_TXPID5GL1_SHIFT);
+       SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2,
+            SSB_SPROM4_TXPID5GL2_SHIFT);
+       SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3,
+            SSB_SPROM4_TXPID5GL3_SHIFT);
+
+       SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0,
+            SSB_SPROM4_TXPID5G0_SHIFT);
+       SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1,
+            SSB_SPROM4_TXPID5G1_SHIFT);
+       SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2,
+            SSB_SPROM4_TXPID5G2_SHIFT);
+       SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3,
+            SSB_SPROM4_TXPID5G3_SHIFT);
+
+       SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0,
+            SSB_SPROM4_TXPID5GH0_SHIFT);
+       SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1,
+            SSB_SPROM4_TXPID5GH1_SHIFT);
+       SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2,
+            SSB_SPROM4_TXPID5GH2_SHIFT);
+       SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3,
+            SSB_SPROM4_TXPID5GH3_SHIFT);
+
+       SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0);
+       SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0);
+       SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
+       SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
+
+       SPEX(country_code, SSB_SPROM8_CCODE, ~0, 0);
+
+       /* Extract cores power info info */
+       for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
+               o = pwr_info_offset[i];
+               SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
+                       SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT);
+               SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI,
+                       SSB_SPROM8_2G_MAXP, 0);
+
+               SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0);
+               SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0);
+               SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0);
+
+               SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
+                       SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT);
+               SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI,
+                       SSB_SPROM8_5G_MAXP, 0);
+               SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP,
+                       SSB_SPROM8_5GH_MAXP, 0);
+               SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP,
+                       SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT);
+
+               SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0);
+               SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0);
+               SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0);
+               SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0);
+               SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0);
+               SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0);
+               SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0);
+               SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
+               SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
+       }
+
+       SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
+            SSB_SROM8_FEM_TSSIPOS_SHIFT);
+       SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
+            SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
+       SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE,
+            SSB_SROM8_FEM_PDET_RANGE_SHIFT);
+       SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO,
+            SSB_SROM8_FEM_TR_ISO_SHIFT);
+       SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT,
+            SSB_SROM8_FEM_ANTSWLUT_SHIFT);
+
+       SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS,
+            SSB_SROM8_FEM_TSSIPOS_SHIFT);
+       SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN,
+            SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
+       SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE,
+            SSB_SROM8_FEM_PDET_RANGE_SHIFT);
+       SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO,
+            SSB_SROM8_FEM_TR_ISO_SHIFT);
+       SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
+            SSB_SROM8_FEM_ANTSWLUT_SHIFT);
 }
 
 int bcma_sprom_get(struct bcma_bus *bus)
 {
        u16 offset;
        u16 *sprom;
+       u32 sromctrl;
        int err = 0;
 
        if (!bus->drv_cc.core)
@@ -217,6 +259,12 @@ int bcma_sprom_get(struct bcma_bus *bus)
        if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
                return -ENOENT;
 
+       if (bus->drv_cc.core->id.rev >= 32) {
+               sromctrl = bcma_read32(bus->drv_cc.core, BCMA_CC_SROM_CONTROL);
+               if (!(sromctrl & BCMA_CC_SROM_CONTROL_PRESENT))
+                       return -ENOENT;
+       }
+
        sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
                        GFP_KERNEL);
        if (!sprom)
@@ -230,6 +278,7 @@ int bcma_sprom_get(struct bcma_bus *bus)
         * TODO: understand this condition and use it */
        offset = (bus->chipinfo.id == 0x4331) ? BCMA_CC_SPROM :
                BCMA_CC_SPROM_PCIE6;
+       pr_debug("SPROM offset 0x%x\n", offset);
        bcma_sprom_read(bus, offset, sprom);
 
        if (bus->chipinfo.id == 0x4331)
index d366dad..a339693 100644 (file)
@@ -80,7 +80,7 @@ static bool modparam_fastchanswitch;
 module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO);
 MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios.");
 
-static int ath5k_modparam_no_hw_rfkill_switch;
+static bool ath5k_modparam_no_hw_rfkill_switch;
 module_param_named(no_hw_rfkill_switch, ath5k_modparam_no_hw_rfkill_switch,
                                                                bool, S_IRUGO);
 MODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state");
@@ -2442,6 +2442,9 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
                BIT(NL80211_IFTYPE_ADHOC) |
                BIT(NL80211_IFTYPE_MESH_POINT);
 
+       /* SW support for IBSS_RSN is provided by mac80211 */
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
        /* both antennas can be configured as RX or TX */
        hw->wiphy->available_antennas_tx = 0x3;
        hw->wiphy->available_antennas_rx = 0x3;
index 6ed4c07..af4c7ec 100644 (file)
@@ -483,6 +483,14 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        if (ath5k_modparam_nohwcrypt)
                return -EOPNOTSUPP;
 
+       if (vif->type == NL80211_IFTYPE_ADHOC &&
+           (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
+            key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
+           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               /* don't program group keys when using IBSS_RSN */
+               return -EOPNOTSUPP;
+       }
+
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_WEP104:
index 3d5f8be..d755a5e 100644 (file)
@@ -1,12 +1,29 @@
 config ATH6KL
-       tristate "Atheros ath6kl support"
+       tristate "Atheros mobile chipsets support"
+
+config ATH6KL_SDIO
+       tristate "Atheros ath6kl SDIO support"
+       depends on ATH6KL
        depends on MMC
        depends on CFG80211
        ---help---
          This module adds support for wireless adapters based on
-         Atheros AR6003 chipset running over SDIO. If you choose to
-         build it as a module, it will be called ath6kl. Pls note
-         that AR6002 and AR6001 are not supported by this driver.
+         Atheros AR6003 and AR6004 chipsets running over SDIO. If you
+         choose to build it as a module, it will be called ath6kl_sdio.
+         Please note that AR6002 and AR6001 are not supported by this
+         driver.
+
+config ATH6KL_USB
+       tristate "Atheros ath6kl USB support"
+       depends on ATH6KL
+       depends on USB
+       depends on CFG80211
+       depends on EXPERIMENTAL
+       ---help---
+         This module adds support for wireless adapters based on
+         Atheros AR6004 chipset running over USB. This is still under
+         implementation and it isn't functional. If you choose to
+         build it as a module, it will be called ath6kl_usb.
 
 config ATH6KL_DEBUG
        bool "Atheros ath6kl debugging"
index 7070693..9ba42fa 100644 (file)
 # Author(s): ="Atheros"
 #------------------------------------------------------------------------------
 
-obj-$(CONFIG_ATH6KL) := ath6kl.o
-ath6kl-y += debug.o
-ath6kl-y += hif.o
-ath6kl-y += htc.o
-ath6kl-y += bmi.o
-ath6kl-y += cfg80211.o
-ath6kl-y += init.o
-ath6kl-y += main.o
-ath6kl-y += txrx.o
-ath6kl-y += wmi.o
-ath6kl-y += sdio.o
-ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o
+obj-$(CONFIG_ATH6KL) += ath6kl_core.o
+ath6kl_core-y += debug.o
+ath6kl_core-y += hif.o
+ath6kl_core-y += htc.o
+ath6kl_core-y += bmi.o
+ath6kl_core-y += cfg80211.o
+ath6kl_core-y += init.o
+ath6kl_core-y += main.o
+ath6kl_core-y += txrx.o
+ath6kl_core-y += wmi.o
+ath6kl_core-y += core.o
+ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
 
-ccflags-y += -D__CHECK_ENDIAN__
+obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o
+ath6kl_sdio-y += sdio.o
+
+obj-$(CONFIG_ATH6KL_USB) += ath6kl_usb.o
+ath6kl_usb-y += usb.o
index bce3575..aef00d5 100644 (file)
@@ -57,8 +57,14 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
                return ret;
        }
 
-       ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
-                                 sizeof(targ_info->version));
+       if (ar->hif_type == ATH6KL_HIF_TYPE_USB) {
+               ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info,
+                                         sizeof(*targ_info));
+       } else {
+               ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
+                               sizeof(targ_info->version));
+       }
+
        if (ret) {
                ath6kl_err("Unable to recv target info: %d\n", ret);
                return ret;
index 6c59a21..d1922d8 100644 (file)
@@ -15,6 +15,8 @@
  */
 
 #include <linux/moduleparam.h>
+#include <linux/inetdevice.h>
+#include <linux/export.h>
 
 #include "core.h"
 #include "cfg80211.h"
 #include "hif-ops.h"
 #include "testmode.h"
 
-static unsigned int ath6kl_p2p;
-
-module_param(ath6kl_p2p, uint, 0644);
-
 #define RATETAB_ENT(_rate, _rateid, _flags) {   \
        .bitrate    = (_rate),                  \
        .flags      = (_flags),                 \
@@ -196,7 +194,7 @@ static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
                break;
 
        default:
-               ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
+               ath6kl_err("%s: 0x%x not supported\n", __func__, auth_type);
                return -ENOTSUPP;
        }
 
@@ -461,13 +459,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                }
        }
 
-       if (sme->ie && (sme->ie_len > 0)) {
-               status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
-               if (status) {
-                       up(&ar->sem);
-                       return status;
-               }
-       } else
+       status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
+       if (status) {
+               up(&ar->sem);
+               return status;
+       }
+
+       if (sme->ie == NULL || sme->ie_len == 0)
                ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
 
        if (test_bit(CONNECTED, &vif->flags) &&
@@ -523,8 +521,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
            (vif->prwise_crypto == WEP_CRYPT)) {
                struct ath6kl_key *key = NULL;
 
-               if (sme->key_idx < WMI_MIN_KEY_INDEX ||
-                   sme->key_idx > WMI_MAX_KEY_INDEX) {
+               if (sme->key_idx > WMI_MAX_KEY_INDEX) {
                        ath6kl_err("key index %d out of bounds\n",
                                   sme->key_idx);
                        up(&ar->sem);
@@ -605,11 +602,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
-static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
-                                   enum network_type nw_type,
-                                   const u8 *bssid,
-                                   struct ieee80211_channel *chan,
-                                   const u8 *beacon_ie, size_t beacon_ie_len)
+static struct cfg80211_bss *
+ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
+                        enum network_type nw_type,
+                        const u8 *bssid,
+                        struct ieee80211_channel *chan,
+                        const u8 *beacon_ie,
+                        size_t beacon_ie_len)
 {
        struct ath6kl *ar = vif->ar;
        struct cfg80211_bss *bss;
@@ -638,7 +637,7 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
                 */
                ie = kmalloc(2 + vif->ssid_len + beacon_ie_len, GFP_KERNEL);
                if (ie == NULL)
-                       return -ENOMEM;
+                       return NULL;
                ie[0] = WLAN_EID_SSID;
                ie[1] = vif->ssid_len;
                memcpy(ie + 2, vif->ssid, vif->ssid_len);
@@ -652,15 +651,9 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
                                   "cfg80211\n", bssid);
                kfree(ie);
        } else
-               ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
-                          "entry\n");
-
-       if (bss == NULL)
-               return -ENOMEM;
+               ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
 
-       cfg80211_put_bss(bss);
-
-       return 0;
+       return bss;
 }
 
 void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
@@ -672,6 +665,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
 {
        struct ieee80211_channel *chan;
        struct ath6kl *ar = vif->ar;
+       struct cfg80211_bss *bss;
 
        /* capinfo + listen interval */
        u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16);
@@ -712,8 +706,9 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
 
        chan = ieee80211_get_channel(ar->wiphy, (int) channel);
 
-       if (ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, assoc_info,
-                                    beacon_ie_len) < 0) {
+       bss = ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan,
+                                      assoc_info, beacon_ie_len);
+       if (!bss) {
                ath6kl_err("could not add cfg80211 bss entry\n");
                return;
        }
@@ -722,6 +717,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
                           nw_type & ADHOC_CREATOR ? "creator" : "joiner");
                cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
+               cfg80211_put_bss(bss);
                return;
        }
 
@@ -732,11 +728,11 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
                                        assoc_req_ie, assoc_req_len,
                                        assoc_resp_ie, assoc_resp_len,
                                        WLAN_STATUS_SUCCESS, GFP_KERNEL);
+               cfg80211_put_bss(bss);
        } else if (vif->sme_state == SME_CONNECTED) {
                /* inform roam event to cfg80211 */
-               cfg80211_roamed(vif->ndev, chan, bssid,
-                               assoc_req_ie, assoc_req_len,
-                               assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
+               cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
+                                   assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
        }
 }
 
@@ -984,6 +980,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
        struct ath6kl *ar = ath6kl_priv(ndev);
        struct ath6kl_vif *vif = netdev_priv(ndev);
        struct ath6kl_key *key = NULL;
+       int seq_len;
        u8 key_usage;
        u8 key_type;
 
@@ -997,7 +994,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                                              params->key);
        }
 
-       if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+       if (key_index > WMI_MAX_KEY_INDEX) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                           "%s: key index %d out of bounds\n", __func__,
                           key_index);
@@ -1012,23 +1009,21 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
        else
                key_usage = GROUP_USAGE;
 
-       if (params) {
-               int seq_len = params->seq_len;
-               if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
-                   seq_len > ATH6KL_KEY_SEQ_LEN) {
-                       /* Only first half of the WPI PN is configured */
-                       seq_len = ATH6KL_KEY_SEQ_LEN;
-               }
-               if (params->key_len > WLAN_MAX_KEY_LEN ||
-                   seq_len > sizeof(key->seq))
-                       return -EINVAL;
-
-               key->key_len = params->key_len;
-               memcpy(key->key, params->key, key->key_len);
-               key->seq_len = seq_len;
-               memcpy(key->seq, params->seq, key->seq_len);
-               key->cipher = params->cipher;
+       seq_len = params->seq_len;
+       if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
+           seq_len > ATH6KL_KEY_SEQ_LEN) {
+               /* Only first half of the WPI PN is configured */
+               seq_len = ATH6KL_KEY_SEQ_LEN;
        }
+       if (params->key_len > WLAN_MAX_KEY_LEN ||
+           seq_len > sizeof(key->seq))
+               return -EINVAL;
+
+       key->key_len = params->key_len;
+       memcpy(key->key, params->key, key->key_len);
+       key->seq_len = seq_len;
+       memcpy(key->seq, params->seq, key->seq_len);
+       key->cipher = params->cipher;
 
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
@@ -1115,7 +1110,7 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
        if (!ath6kl_cfg80211_ready(vif))
                return -EIO;
 
-       if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+       if (key_index > WMI_MAX_KEY_INDEX) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                           "%s: key index %d out of bounds\n", __func__,
                           key_index);
@@ -1148,7 +1143,7 @@ static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
        if (!ath6kl_cfg80211_ready(vif))
                return -EIO;
 
-       if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+       if (key_index > WMI_MAX_KEY_INDEX) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                           "%s: key index %d out of bounds\n", __func__,
                           key_index);
@@ -1184,7 +1179,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
        if (!ath6kl_cfg80211_ready(vif))
                return -EIO;
 
-       if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) {
+       if (key_index > WMI_MAX_KEY_INDEX) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                           "%s: key index %d out of bounds\n",
                           __func__, key_index);
@@ -1403,7 +1398,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
 
        ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
 
-       ath6kl_deinit_if_data(vif);
+       ath6kl_cfg80211_vif_cleanup(vif);
 
        return 0;
 }
@@ -1728,29 +1723,14 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
        return 0;
 }
 
-static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,
+                         struct cfg80211_wowlan *wow, u32 *filter)
 {
-       struct ath6kl_vif *vif;
-       int ret, pos, left;
-       u32 filter = 0;
-       u16 i;
+       int ret, pos;
        u8 mask[WOW_MASK_SIZE];
+       u16 i;
 
-       vif = ath6kl_vif_first(ar);
-       if (!vif)
-               return -EIO;
-
-       if (!ath6kl_cfg80211_ready(vif))
-               return -EIO;
-
-       if (!test_bit(CONNECTED, &vif->flags))
-               return -EINVAL;
-
-       /* Clear existing WOW patterns */
-       for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
-               ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
-                                              WOW_LIST_ID, i);
-       /* Configure new WOW patterns */
+       /* Configure the patterns that we received from the user. */
        for (i = 0; i < wow->n_patterns; i++) {
 
                /*
@@ -1773,29 +1753,221 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
                 * matched from the first byte of received pkt in the firmware.
                 */
                ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
-                                       vif->fw_vif_idx, WOW_LIST_ID,
-                                       wow->patterns[i].pattern_len,
-                                       0 /* pattern offset */,
-                                       wow->patterns[i].pattern, mask);
+                               vif->fw_vif_idx, WOW_LIST_ID,
+                               wow->patterns[i].pattern_len,
+                               0 /* pattern offset */,
+                               wow->patterns[i].pattern, mask);
                if (ret)
                        return ret;
        }
 
        if (wow->disconnect)
-               filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
+               *filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
 
        if (wow->magic_pkt)
-               filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
+               *filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
 
        if (wow->gtk_rekey_failure)
-               filter |= WOW_FILTER_OPTION_GTK_ERROR;
+               *filter |= WOW_FILTER_OPTION_GTK_ERROR;
 
        if (wow->eap_identity_req)
-               filter |= WOW_FILTER_OPTION_EAP_REQ;
+               *filter |= WOW_FILTER_OPTION_EAP_REQ;
 
        if (wow->four_way_handshake)
-               filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
+               *filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
+
+       return 0;
+}
+
+static int ath6kl_wow_ap(struct ath6kl *ar, struct ath6kl_vif *vif)
+{
+       static const u8 unicst_pattern[] = { 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x08 };
+       static const u8 unicst_mask[] = { 0x01, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x7f };
+       u8 unicst_offset = 0;
+       static const u8 arp_pattern[] = { 0x08, 0x06 };
+       static const u8 arp_mask[] = { 0xff, 0xff };
+       u8 arp_offset = 20;
+       static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
+       static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
+       u8 discvr_offset = 38;
+       static const u8 dhcp_pattern[] = { 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x43 /* port 67 */ };
+       static const u8 dhcp_mask[] = { 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0xff, 0xff /* port 67 */ };
+       u8 dhcp_offset = 0;
+       int ret;
+
+       /* Setup unicast IP, EAPOL-like and ARP pkt pattern */
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                       vif->fw_vif_idx, WOW_LIST_ID,
+                       sizeof(unicst_pattern), unicst_offset,
+                       unicst_pattern, unicst_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW unicast IP pattern\n");
+               return ret;
+       }
+
+       /* Setup all ARP pkt pattern */
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                       vif->fw_vif_idx, WOW_LIST_ID,
+                       sizeof(arp_pattern), arp_offset,
+                       arp_pattern, arp_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW ARP pattern\n");
+               return ret;
+       }
 
+       /*
+        * Setup multicast pattern for mDNS 224.0.0.251,
+        * SSDP 239.255.255.250 and LLMNR  224.0.0.252
+        */
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                       vif->fw_vif_idx, WOW_LIST_ID,
+                       sizeof(discvr_pattern), discvr_offset,
+                       discvr_pattern, discvr_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
+               return ret;
+       }
+
+       /* Setup all DHCP broadcast pkt pattern */
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                       vif->fw_vif_idx, WOW_LIST_ID,
+                       sizeof(dhcp_pattern), dhcp_offset,
+                       dhcp_pattern, dhcp_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW DHCP broadcast pattern\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
+{
+       struct net_device *ndev = vif->ndev;
+       static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
+       static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
+       u8 discvr_offset = 38;
+       u8 mac_mask[ETH_ALEN];
+       int ret;
+
+       /* Setup unicast pkt pattern */
+       memset(mac_mask, 0xff, ETH_ALEN);
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                               vif->fw_vif_idx, WOW_LIST_ID,
+                               ETH_ALEN, 0, ndev->dev_addr,
+                               mac_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW unicast pattern\n");
+               return ret;
+       }
+
+       /*
+        * Setup multicast pattern for mDNS 224.0.0.251,
+        * SSDP 239.255.255.250 and LLMNR 224.0.0.252
+        */
+       if ((ndev->flags & IFF_ALLMULTI) ||
+           (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) {
+               ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                               vif->fw_vif_idx, WOW_LIST_ID,
+                               sizeof(discvr_pattern), discvr_offset,
+                               discvr_pattern, discvr_mask);
+               if (ret) {
+                       ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR "
+                                  "pattern\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+{
+       struct in_device *in_dev;
+       struct in_ifaddr *ifa;
+       struct ath6kl_vif *vif;
+       int ret, left;
+       u32 filter = 0;
+       u16 i;
+       u8 index = 0;
+       __be32 ips[MAX_IP_ADDRS];
+
+       vif = ath6kl_vif_first(ar);
+       if (!vif)
+               return -EIO;
+
+       if (!ath6kl_cfg80211_ready(vif))
+               return -EIO;
+
+       if (!test_bit(CONNECTED, &vif->flags))
+               return -ENOTCONN;
+
+       if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
+               return -EINVAL;
+
+       /* Clear existing WOW patterns */
+       for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
+               ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
+                                              WOW_LIST_ID, i);
+
+       /*
+        * Skip the default WOW pattern configuration
+        * if the driver receives any WOW patterns from
+        * the user.
+        */
+       if (wow)
+               ret = ath6kl_wow_usr(ar, vif, wow, &filter);
+       else if (vif->nw_type == AP_NETWORK)
+               ret = ath6kl_wow_ap(ar, vif);
+       else
+               ret = ath6kl_wow_sta(ar, vif);
+
+       if (ret)
+               return ret;
+
+       /* Setup own IP addr for ARP agent. */
+       in_dev = __in_dev_get_rtnl(vif->ndev);
+       if (!in_dev)
+               goto skip_arp;
+
+       ifa = in_dev->ifa_list;
+       memset(&ips, 0, sizeof(ips));
+
+       /* Configure IP addr only if IP address count < MAX_IP_ADDRS */
+       while (index < MAX_IP_ADDRS && ifa) {
+               ips[index] = ifa->ifa_local;
+               ifa = ifa->ifa_next;
+               index++;
+       }
+
+       if (ifa) {
+               ath6kl_err("total IP addr count is exceeding fw limit\n");
+               return -EINVAL;
+       }
+
+       ret = ath6kl_wmi_set_ip_cmd(ar->wmi, vif->fw_vif_idx, ips[0], ips[1]);
+       if (ret) {
+               ath6kl_err("fail to setup ip for arp agent\n");
+               return ret;
+       }
+
+skip_arp:
        ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
                                          ATH6KL_WOW_MODE_ENABLE,
                                          filter,
@@ -1803,11 +1975,26 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
        if (ret)
                return ret;
 
+       clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
+
        ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
                                                 ATH6KL_HOST_MODE_ASLEEP);
        if (ret)
                return ret;
 
+       left = wait_event_interruptible_timeout(ar->event_wq,
+                       test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags),
+                       WMI_TIMEOUT);
+       if (left == 0) {
+               ath6kl_warn("timeout, didn't get host sleep cmd "
+                           "processed event\n");
+               ret = -ETIMEDOUT;
+       } else if (left < 0) {
+               ath6kl_warn("error while waiting for host sleep cmd "
+                           "processed event %d\n", left);
+               ret = left;
+       }
+
        if (ar->tx_pending[ar->ctrl_ep]) {
                left = wait_event_interruptible_timeout(ar->event_wq,
                                ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
@@ -1911,6 +2098,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
 
        return 0;
 }
+EXPORT_SYMBOL(ath6kl_cfg80211_suspend);
 
 int ath6kl_cfg80211_resume(struct ath6kl *ar)
 {
@@ -1962,6 +2150,7 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
 
        return 0;
 }
+EXPORT_SYMBOL(ath6kl_cfg80211_resume);
 
 #ifdef CONFIG_PM
 
@@ -2014,7 +2203,18 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
                              struct ieee80211_channel *chan,
                              enum nl80211_channel_type channel_type)
 {
-       struct ath6kl_vif *vif = netdev_priv(dev);
+       struct ath6kl_vif *vif;
+
+       /*
+        * 'dev' could be NULL if a channel change is required for the hardware
+        * device itself, instead of a particular VIF.
+        *
+        * FIXME: To be handled properly when monitor mode is supported.
+        */
+       if (!dev)
+               return -EBUSY;
+
+       vif = netdev_priv(dev);
 
        if (!ath6kl_cfg80211_ready(vif))
                return -EIO;
@@ -2214,6 +2414,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
        p.dot11_auth_mode = vif->dot11_auth_mode;
        p.ch = cpu_to_le16(vif->next_chan);
 
+       /* Enable uAPSD support by default */
+       res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
+       if (res < 0)
+               return res;
+
        if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
                p.nw_subtype = SUBTYPE_P2PGO;
        } else {
@@ -2259,6 +2464,19 @@ static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
        return 0;
 }
 
+static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
+                             u8 *mac)
+{
+       struct ath6kl *ar = ath6kl_priv(dev);
+       struct ath6kl_vif *vif = netdev_priv(dev);
+       const u8 *addr = mac ? mac : bcast_addr;
+
+       return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
+                                     addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
 static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac, struct station_parameters *params)
 {
@@ -2518,6 +2736,12 @@ ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
                .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
                BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
        },
+       [NL80211_IFTYPE_AP] = {
+               .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
        [NL80211_IFTYPE_P2P_CLIENT] = {
                .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
                BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
@@ -2562,6 +2786,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
        .add_beacon = ath6kl_add_beacon,
        .set_beacon = ath6kl_set_beacon,
        .del_beacon = ath6kl_del_beacon,
+       .del_station = ath6kl_del_station,
        .change_station = ath6kl_change_station,
        .remain_on_channel = ath6kl_remain_on_channel,
        .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
@@ -2629,122 +2854,9 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
                ath6kl_cfg80211_stop(vif);
 }
 
-struct ath6kl *ath6kl_core_alloc(struct device *dev)
-{
-       struct ath6kl *ar;
-       struct wiphy *wiphy;
-       u8 ctr;
-
-       /* create a new wiphy for use with cfg80211 */
-       wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
-
-       if (!wiphy) {
-               ath6kl_err("couldn't allocate wiphy device\n");
-               return NULL;
-       }
-
-       ar = wiphy_priv(wiphy);
-       ar->p2p = !!ath6kl_p2p;
-       ar->wiphy = wiphy;
-       ar->dev = dev;
-
-       ar->vif_max = 1;
-
-       ar->max_norm_iface = 1;
-
-       spin_lock_init(&ar->lock);
-       spin_lock_init(&ar->mcastpsq_lock);
-       spin_lock_init(&ar->list_lock);
-
-       init_waitqueue_head(&ar->event_wq);
-       sema_init(&ar->sem, 1);
-
-       INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
-       INIT_LIST_HEAD(&ar->vif_list);
-
-       clear_bit(WMI_ENABLED, &ar->flag);
-       clear_bit(SKIP_SCAN, &ar->flag);
-       clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
-
-       ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
-       ar->listen_intvl_b = 0;
-       ar->tx_pwr = 0;
-
-       ar->intra_bss = 1;
-       ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
-
-       ar->state = ATH6KL_STATE_OFF;
-
-       memset((u8 *)ar->sta_list, 0,
-              AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
-
-       /* Init the PS queues */
-       for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
-               spin_lock_init(&ar->sta_list[ctr].psq_lock);
-               skb_queue_head_init(&ar->sta_list[ctr].psq);
-       }
-
-       skb_queue_head_init(&ar->mcastpsq);
-
-       memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
-
-       return ar;
-}
-
-int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
-{
-       struct wiphy *wiphy = ar->wiphy;
-       int ret;
-
-       wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
-
-       wiphy->max_remain_on_channel_duration = 5000;
-
-       /* set device pointer for wiphy */
-       set_wiphy_dev(wiphy, ar->dev);
-
-       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-                                BIT(NL80211_IFTYPE_ADHOC) |
-                                BIT(NL80211_IFTYPE_AP);
-       if (ar->p2p) {
-               wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
-                                         BIT(NL80211_IFTYPE_P2P_CLIENT);
-       }
-
-       /* max num of ssids that can be probed during scanning */
-       wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
-       wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
-       wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
-       wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
-       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-
-       wiphy->cipher_suites = cipher_suites;
-       wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
-
-       wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                             WIPHY_WOWLAN_DISCONNECT |
-                             WIPHY_WOWLAN_GTK_REKEY_FAILURE  |
-                             WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
-                             WIPHY_WOWLAN_EAP_IDENTITY_REQ   |
-                             WIPHY_WOWLAN_4WAY_HANDSHAKE;
-       wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
-       wiphy->wowlan.pattern_min_len = 1;
-       wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
-
-       wiphy->max_sched_scan_ssids = 10;
-
-       ret = wiphy_register(wiphy);
-       if (ret < 0) {
-               ath6kl_err("couldn't register wiphy device\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static int ath6kl_init_if_data(struct ath6kl_vif *vif)
+static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
 {
-       vif->aggr_cntxt = aggr_init(vif->ndev);
+       vif->aggr_cntxt = aggr_init(vif);
        if (!vif->aggr_cntxt) {
                ath6kl_err("failed to initialize aggr\n");
                return -ENOMEM;
@@ -2758,12 +2870,15 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)
        set_bit(WMM_ENABLED, &vif->flags);
        spin_lock_init(&vif->if_lock);
 
+       INIT_LIST_HEAD(&vif->mc_filter);
+
        return 0;
 }
 
-void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
+void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
 {
        struct ath6kl *ar = vif->ar;
+       struct ath6kl_mc_filter *mc_filter, *tmp;
 
        aggr_module_destroy(vif->aggr_cntxt);
 
@@ -2772,6 +2887,11 @@ void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
        if (vif->nw_type == ADHOC_NETWORK)
                ar->ibss_if_active = false;
 
+       list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
+               list_del(&mc_filter->list);
+               kfree(mc_filter);
+       }
+
        unregister_netdevice(vif->ndev);
 
        ar->num_vif--;
@@ -2808,8 +2928,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
 
        ath6kl_init_control_info(vif);
 
-       /* TODO: Pass interface specific pointer instead of ar */
-       if (ath6kl_init_if_data(vif))
+       if (ath6kl_cfg80211_vif_init(vif))
                goto err;
 
        if (register_netdevice(ndev))
@@ -2836,8 +2955,89 @@ err:
        return NULL;
 }
 
-void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
+int ath6kl_cfg80211_init(struct ath6kl *ar)
+{
+       struct wiphy *wiphy = ar->wiphy;
+       int ret;
+
+       wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
+
+       wiphy->max_remain_on_channel_duration = 5000;
+
+       /* set device pointer for wiphy */
+       set_wiphy_dev(wiphy, ar->dev);
+
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_ADHOC) |
+                                BIT(NL80211_IFTYPE_AP);
+       if (ar->p2p) {
+               wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
+                                         BIT(NL80211_IFTYPE_P2P_CLIENT);
+       }
+
+       /* max num of ssids that can be probed during scanning */
+       wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
+       wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
+       wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
+       wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+       wiphy->cipher_suites = cipher_suites;
+       wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+       wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+                             WIPHY_WOWLAN_DISCONNECT |
+                             WIPHY_WOWLAN_GTK_REKEY_FAILURE  |
+                             WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+                             WIPHY_WOWLAN_EAP_IDENTITY_REQ   |
+                             WIPHY_WOWLAN_4WAY_HANDSHAKE;
+       wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
+       wiphy->wowlan.pattern_min_len = 1;
+       wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
+
+       wiphy->max_sched_scan_ssids = 10;
+
+       ret = wiphy_register(wiphy);
+       if (ret < 0) {
+               ath6kl_err("couldn't register wiphy device\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
 {
        wiphy_unregister(ar->wiphy);
+}
+
+struct ath6kl *ath6kl_cfg80211_create(void)
+{
+       struct ath6kl *ar;
+       struct wiphy *wiphy;
+
+       /* create a new wiphy for use with cfg80211 */
+       wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
+
+       if (!wiphy) {
+               ath6kl_err("couldn't allocate wiphy device\n");
+               return NULL;
+       }
+
+       ar = wiphy_priv(wiphy);
+       ar->wiphy = wiphy;
+
+       return ar;
+}
+
+/* Note: ar variable must not be accessed after calling this! */
+void ath6kl_cfg80211_destroy(struct ath6kl *ar)
+{
+       int i;
+
+       for (i = 0; i < AP_MAX_NUM_STA; i++)
+               kfree(ar->sta_list[i].aggr_conn);
+
        wiphy_free(ar->wiphy);
 }
+
index 81f20a5..3c693b7 100644 (file)
@@ -27,10 +27,6 @@ enum ath6kl_cfg_suspend_mode {
 struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
                                        enum nl80211_iftype type,
                                        u8 fw_vif_idx, u8 nw_type);
-int ath6kl_register_ieee80211_hw(struct ath6kl *ar);
-struct ath6kl *ath6kl_core_alloc(struct device *dev);
-void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar);
-
 void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted);
 
 void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
@@ -53,7 +49,15 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
 
 int ath6kl_cfg80211_resume(struct ath6kl *ar);
 
+void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif);
+
 void ath6kl_cfg80211_stop(struct ath6kl_vif *vif);
 void ath6kl_cfg80211_stop_all(struct ath6kl *ar);
 
+int ath6kl_cfg80211_init(struct ath6kl *ar);
+void ath6kl_cfg80211_cleanup(struct ath6kl *ar);
+
+struct ath6kl *ath6kl_cfg80211_create(void);
+void ath6kl_cfg80211_destroy(struct ath6kl *ar);
+
 #endif /* ATH6KL_CFG80211_H */
index bfd6597..f89f1e1 100644 (file)
@@ -79,8 +79,5 @@ struct ath6kl;
 enum htc_credit_dist_reason;
 struct ath6kl_htc_credit_info;
 
-struct ath6kl *ath6kl_core_alloc(struct device *sdev);
-int ath6kl_core_init(struct ath6kl *ar);
-void ath6kl_core_cleanup(struct ath6kl *ar);
 struct sk_buff *ath6kl_buf_alloc(int size);
 #endif /* COMMON_H */
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c
new file mode 100644 (file)
index 0000000..722ca59
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2004-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/export.h>
+
+#include "debug.h"
+#include "hif-ops.h"
+#include "cfg80211.h"
+
+unsigned int debug_mask;
+static unsigned int suspend_mode;
+static unsigned int uart_debug;
+static unsigned int ath6kl_p2p;
+static unsigned int testmode;
+
+module_param(debug_mask, uint, 0644);
+module_param(suspend_mode, uint, 0644);
+module_param(uart_debug, uint, 0644);
+module_param(ath6kl_p2p, uint, 0644);
+module_param(testmode, uint, 0644);
+
+int ath6kl_core_init(struct ath6kl *ar)
+{
+       struct ath6kl_bmi_target_info targ_info;
+       struct net_device *ndev;
+       int ret = 0, i;
+
+       ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
+       if (!ar->ath6kl_wq)
+               return -ENOMEM;
+
+       ret = ath6kl_bmi_init(ar);
+       if (ret)
+               goto err_wq;
+
+       /*
+        * Turn on power to get hardware (target) version and leave power
+        * on delibrately as we will boot the hardware anyway within few
+        * seconds.
+        */
+       ret = ath6kl_hif_power_on(ar);
+       if (ret)
+               goto err_bmi_cleanup;
+
+       ret = ath6kl_bmi_get_target_info(ar, &targ_info);
+       if (ret)
+               goto err_power_off;
+
+       ar->version.target_ver = le32_to_cpu(targ_info.version);
+       ar->target_type = le32_to_cpu(targ_info.type);
+       ar->wiphy->hw_version = le32_to_cpu(targ_info.version);
+
+       ret = ath6kl_init_hw_params(ar);
+       if (ret)
+               goto err_power_off;
+
+       ar->htc_target = ath6kl_htc_create(ar);
+
+       if (!ar->htc_target) {
+               ret = -ENOMEM;
+               goto err_power_off;
+       }
+
+       ar->testmode = testmode;
+
+       ret = ath6kl_init_fetch_firmwares(ar);
+       if (ret)
+               goto err_htc_cleanup;
+
+       /* FIXME: we should free all firmwares in the error cases below */
+
+       /* Indicate that WMI is enabled (although not ready yet) */
+       set_bit(WMI_ENABLED, &ar->flag);
+       ar->wmi = ath6kl_wmi_init(ar);
+       if (!ar->wmi) {
+               ath6kl_err("failed to initialize wmi\n");
+               ret = -EIO;
+               goto err_htc_cleanup;
+       }
+
+       ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi);
+
+       ret = ath6kl_cfg80211_init(ar);
+       if (ret)
+               goto err_node_cleanup;
+
+       ret = ath6kl_debug_init(ar);
+       if (ret) {
+               wiphy_unregister(ar->wiphy);
+               goto err_node_cleanup;
+       }
+
+       for (i = 0; i < ar->vif_max; i++)
+               ar->avail_idx_map |= BIT(i);
+
+       rtnl_lock();
+
+       /* Add an initial station interface */
+       ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
+                                   INFRA_NETWORK);
+
+       rtnl_unlock();
+
+       if (!ndev) {
+               ath6kl_err("Failed to instantiate a network device\n");
+               ret = -ENOMEM;
+               wiphy_unregister(ar->wiphy);
+               goto err_debug_init;
+       }
+
+
+       ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
+                       __func__, ndev->name, ndev, ar);
+
+       /* setup access class priority mappings */
+       ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest  */
+       ar->ac_stream_pri_map[WMM_AC_BE] = 1;
+       ar->ac_stream_pri_map[WMM_AC_VI] = 2;
+       ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */
+
+       /* give our connected endpoints some buffers */
+       ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
+       ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
+
+       /* allocate some buffers that handle larger AMSDU frames */
+       ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS);
+
+       ath6kl_cookie_init(ar);
+
+       ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
+                        ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
+
+       if (suspend_mode &&
+               suspend_mode >= WLAN_POWER_STATE_CUT_PWR &&
+               suspend_mode <= WLAN_POWER_STATE_WOW)
+               ar->suspend_mode = suspend_mode;
+       else
+               ar->suspend_mode = 0;
+
+       if (uart_debug)
+               ar->conf_flags |= ATH6KL_CONF_UART_DEBUG;
+
+       ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
+                           WIPHY_FLAG_HAVE_AP_SME |
+                           WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+                           WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+
+       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
+               ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+
+       ar->wiphy->probe_resp_offload =
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
+
+       set_bit(FIRST_BOOT, &ar->flag);
+
+       ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+
+       ret = ath6kl_init_hw_start(ar);
+       if (ret) {
+               ath6kl_err("Failed to start hardware: %d\n", ret);
+               goto err_rxbuf_cleanup;
+       }
+
+       /*
+        * Set mac address which is received in ready event
+        * FIXME: Move to ath6kl_interface_add()
+        */
+       memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
+
+       return ret;
+
+err_rxbuf_cleanup:
+       ath6kl_htc_flush_rx_buf(ar->htc_target);
+       ath6kl_cleanup_amsdu_rxbufs(ar);
+       rtnl_lock();
+       ath6kl_cfg80211_vif_cleanup(netdev_priv(ndev));
+       rtnl_unlock();
+       wiphy_unregister(ar->wiphy);
+err_debug_init:
+       ath6kl_debug_cleanup(ar);
+err_node_cleanup:
+       ath6kl_wmi_shutdown(ar->wmi);
+       clear_bit(WMI_ENABLED, &ar->flag);
+       ar->wmi = NULL;
+err_htc_cleanup:
+       ath6kl_htc_cleanup(ar->htc_target);
+err_power_off:
+       ath6kl_hif_power_off(ar);
+err_bmi_cleanup:
+       ath6kl_bmi_cleanup(ar);
+err_wq:
+       destroy_workqueue(ar->ath6kl_wq);
+
+       return ret;
+}
+EXPORT_SYMBOL(ath6kl_core_init);
+
+struct ath6kl *ath6kl_core_create(struct device *dev)
+{
+       struct ath6kl *ar;
+       u8 ctr;
+
+       ar = ath6kl_cfg80211_create();
+       if (!ar)
+               return NULL;
+
+       ar->p2p = !!ath6kl_p2p;
+       ar->dev = dev;
+
+       ar->vif_max = 1;
+
+       ar->max_norm_iface = 1;
+
+       spin_lock_init(&ar->lock);
+       spin_lock_init(&ar->mcastpsq_lock);
+       spin_lock_init(&ar->list_lock);
+
+       init_waitqueue_head(&ar->event_wq);
+       sema_init(&ar->sem, 1);
+
+       INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
+       INIT_LIST_HEAD(&ar->vif_list);
+
+       clear_bit(WMI_ENABLED, &ar->flag);
+       clear_bit(SKIP_SCAN, &ar->flag);
+       clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
+
+       ar->listen_intvl_b = A_DEFAULT_LISTEN_INTERVAL;
+       ar->tx_pwr = 0;
+
+       ar->intra_bss = 1;
+       ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
+
+       ar->state = ATH6KL_STATE_OFF;
+
+       memset((u8 *)ar->sta_list, 0,
+              AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
+
+       /* Init the PS queues */
+       for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
+               spin_lock_init(&ar->sta_list[ctr].psq_lock);
+               skb_queue_head_init(&ar->sta_list[ctr].psq);
+               skb_queue_head_init(&ar->sta_list[ctr].apsdq);
+               ar->sta_list[ctr].aggr_conn =
+                       kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL);
+               if (!ar->sta_list[ctr].aggr_conn) {
+                       ath6kl_err("Failed to allocate memory for sta aggregation information\n");
+                       ath6kl_core_destroy(ar);
+                       return NULL;
+               }
+       }
+
+       skb_queue_head_init(&ar->mcastpsq);
+
+       memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
+
+       return ar;
+}
+EXPORT_SYMBOL(ath6kl_core_create);
+
+void ath6kl_core_cleanup(struct ath6kl *ar)
+{
+       ath6kl_hif_power_off(ar);
+
+       destroy_workqueue(ar->ath6kl_wq);
+
+       if (ar->htc_target)
+               ath6kl_htc_cleanup(ar->htc_target);
+
+       ath6kl_cookie_cleanup(ar);
+
+       ath6kl_cleanup_amsdu_rxbufs(ar);
+
+       ath6kl_bmi_cleanup(ar);
+
+       ath6kl_debug_cleanup(ar);
+
+       kfree(ar->fw_board);
+       kfree(ar->fw_otp);
+       kfree(ar->fw);
+       kfree(ar->fw_patch);
+       kfree(ar->fw_testscript);
+
+       ath6kl_cfg80211_cleanup(ar);
+}
+EXPORT_SYMBOL(ath6kl_core_cleanup);
+
+void ath6kl_core_destroy(struct ath6kl *ar)
+{
+       ath6kl_cfg80211_destroy(ar);
+}
+EXPORT_SYMBOL(ath6kl_core_destroy);
+
+MODULE_AUTHOR("Qualcomm Atheros");
+MODULE_DESCRIPTION("Core module for AR600x SDIO and USB devices.");
+MODULE_LICENSE("Dual BSD/GPL");
index c863a28..c4d66e0 100644 (file)
 #define ATH6KL_MAX_ENDPOINTS   4
 #define MAX_NODE_NUM           15
 
+#define ATH6KL_APSD_ALL_FRAME          0xFFFF
+#define ATH6KL_APSD_NUM_OF_AC          0x4
+#define ATH6KL_APSD_FRAME_MASK         0xF
+
 /* Extra bytes for htc header alignment */
 #define ATH6KL_HTC_ALIGN_BYTES 3
 
@@ -55,7 +59,7 @@
 #define MAX_DEFAULT_SEND_QUEUE_DEPTH      (MAX_DEF_COOKIE_NUM / WMM_NUM_AC)
 
 #define DISCON_TIMER_INTVAL               10000  /* in msec */
-#define A_DEFAULT_LISTEN_INTERVAL         100
+#define A_DEFAULT_LISTEN_INTERVAL         1      /* beacon intervals */
 #define A_MAX_WOW_LISTEN_INTERVAL         1000
 
 /* includes also the null byte */
@@ -97,45 +101,49 @@ struct ath6kl_fw_ie {
        u8 data[0];
 };
 
+#define ATH6KL_FW_API2_FILE "fw-2.bin"
+#define ATH6KL_FW_API3_FILE "fw-3.bin"
+
 /* AR6003 1.0 definitions */
 #define AR6003_HW_1_0_VERSION                 0x300002ba
 
 /* AR6003 2.0 definitions */
 #define AR6003_HW_2_0_VERSION                 0x30000384
 #define AR6003_HW_2_0_PATCH_DOWNLOAD_ADDRESS  0x57e910
-#define AR6003_HW_2_0_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
-#define AR6003_HW_2_0_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
-#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
-#define AR6003_HW_2_0_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
-#define AR6003_HW_2_0_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin"
+#define AR6003_HW_2_0_FW_DIR                   "ath6k/AR6003/hw2.0"
+#define AR6003_HW_2_0_OTP_FILE                 "otp.bin.z77"
+#define AR6003_HW_2_0_FIRMWARE_FILE            "athwlan.bin.z77"
+#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE       "athtcmd_ram.bin"
+#define AR6003_HW_2_0_PATCH_FILE               "data.patch.bin"
 #define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
 #define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \
                        "ath6k/AR6003/hw2.0/bdata.SD31.bin"
 
 /* AR6003 3.0 definitions */
 #define AR6003_HW_2_1_1_VERSION                 0x30000582
-#define AR6003_HW_2_1_1_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
-#define AR6003_HW_2_1_1_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
-#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE \
-                       "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
-#define AR6003_HW_2_1_1_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
-#define AR6003_HW_2_1_1_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
+#define AR6003_HW_2_1_1_FW_DIR                 "ath6k/AR6003/hw2.1.1"
+#define AR6003_HW_2_1_1_OTP_FILE               "otp.bin"
+#define AR6003_HW_2_1_1_FIRMWARE_FILE          "athwlan.bin"
+#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE     "athtcmd_ram.bin"
+#define AR6003_HW_2_1_1_UTF_FIRMWARE_FILE      "utf.bin"
+#define AR6003_HW_2_1_1_TESTSCRIPT_FILE        "nullTestFlow.bin"
+#define AR6003_HW_2_1_1_PATCH_FILE             "data.patch.bin"
 #define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
 #define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE        \
                        "ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
 
 /* AR6004 1.0 definitions */
 #define AR6004_HW_1_0_VERSION                 0x30000623
-#define AR6004_HW_1_0_FIRMWARE_2_FILE         "ath6k/AR6004/hw1.0/fw-2.bin"
-#define AR6004_HW_1_0_FIRMWARE_FILE           "ath6k/AR6004/hw1.0/fw.ram.bin"
+#define AR6004_HW_1_0_FW_DIR                   "ath6k/AR6004/hw1.0"
+#define AR6004_HW_1_0_FIRMWARE_FILE            "fw.ram.bin"
 #define AR6004_HW_1_0_BOARD_DATA_FILE         "ath6k/AR6004/hw1.0/bdata.bin"
 #define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \
        "ath6k/AR6004/hw1.0/bdata.DB132.bin"
 
 /* AR6004 1.1 definitions */
 #define AR6004_HW_1_1_VERSION                 0x30000001
-#define AR6004_HW_1_1_FIRMWARE_2_FILE         "ath6k/AR6004/hw1.1/fw-2.bin"
-#define AR6004_HW_1_1_FIRMWARE_FILE           "ath6k/AR6004/hw1.1/fw.ram.bin"
+#define AR6004_HW_1_1_FW_DIR                   "ath6k/AR6004/hw1.1"
+#define AR6004_HW_1_1_FIRMWARE_FILE            "fw.ram.bin"
 #define AR6004_HW_1_1_BOARD_DATA_FILE         "ath6k/AR6004/hw1.1/bdata.bin"
 #define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \
        "ath6k/AR6004/hw1.1/bdata.DB132.bin"
@@ -144,6 +152,8 @@ struct ath6kl_fw_ie {
 #define STA_PS_AWAKE           BIT(0)
 #define        STA_PS_SLEEP            BIT(1)
 #define        STA_PS_POLLED           BIT(2)
+#define STA_PS_APSD_TRIGGER     BIT(3)
+#define STA_PS_APSD_EOSP        BIT(4)
 
 /* HTC TX packet tagging definitions */
 #define ATH6KL_CONTROL_PKT_TAG    HTC_TX_PACKET_TAG_USER_DEFINED
@@ -186,7 +196,7 @@ struct ath6kl_fw_ie {
 #define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN  BIT(1)
 #define ATH6KL_CONF_ENABLE_11N                 BIT(2)
 #define ATH6KL_CONF_ENABLE_TX_BURST            BIT(3)
-#define ATH6KL_CONF_SUSPEND_CUTPOWER           BIT(4)
+#define ATH6KL_CONF_UART_DEBUG                 BIT(4)
 
 enum wlan_low_pwr_state {
        WLAN_POWER_STATE_ON,
@@ -231,14 +241,19 @@ struct rxtid_stats {
        u32 num_bar;
 };
 
-struct aggr_info {
+struct aggr_info_conn {
        u8 aggr_sz;
        u8 timer_scheduled;
        struct timer_list timer;
        struct net_device *dev;
        struct rxtid rx_tid[NUM_OF_TIDS];
-       struct sk_buff_head free_q;
        struct rxtid_stats stat[NUM_OF_TIDS];
+       struct aggr_info *aggr_info;
+};
+
+struct aggr_info {
+       struct aggr_info_conn *aggr_conn;
+       struct sk_buff_head rx_amsdu_freeq;
 };
 
 struct ath6kl_wep_key {
@@ -280,6 +295,9 @@ struct ath6kl_sta {
        u8 wpa_ie[ATH6KL_MAX_IE];
        struct sk_buff_head psq;
        spinlock_t psq_lock;
+       u8 apsd_info;
+       struct sk_buff_head apsdq;
+       struct aggr_info_conn *aggr_conn;
 };
 
 struct ath6kl_version {
@@ -408,6 +426,13 @@ enum ath6kl_hif_type {
        ATH6KL_HIF_TYPE_USB,
 };
 
+/* Max number of filters that hw supports */
+#define ATH6K_MAX_MC_FILTERS_PER_LIST 7
+struct ath6kl_mc_filter {
+       struct list_head list;
+       char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE];
+};
+
 /*
  * Driver's maximum limit, note that some firmwares support only one vif
  * and the runtime (current) limit must be checked from ar->vif_max.
@@ -426,6 +451,7 @@ enum ath6kl_vif_state {
        DTIM_PERIOD_AVAIL,
        WLAN_ENABLED,
        STATS_UPDATE_PEND,
+       HOST_SLEEP_MODE_CMD_PROCESSED,
 };
 
 struct ath6kl_vif {
@@ -471,6 +497,8 @@ struct ath6kl_vif {
        u8 assoc_bss_dtim_period;
        struct net_device_stats net_stats;
        struct target_stats target_stats;
+
+       struct list_head mc_filter;
 };
 
 #define WOW_LIST_ID            0
@@ -504,6 +532,7 @@ struct ath6kl {
        struct wiphy *wiphy;
 
        enum ath6kl_state state;
+       unsigned int testmode;
 
        struct ath6kl_bmi bmi;
        const struct ath6kl_hif_ops *hif_ops;
@@ -523,7 +552,6 @@ struct ath6kl {
        spinlock_t lock;
        struct semaphore sem;
        u16 listen_intvl_b;
-       u16 listen_intvl_t;
        u8 lrssi_roam_threshold;
        struct ath6kl_version version;
        u32 target_type;
@@ -574,17 +602,24 @@ struct ath6kl {
                u32 board_addr;
                u32 refclk_hz;
                u32 uarttx_pin;
+               u32 testscript_addr;
+
+               struct ath6kl_hw_fw {
+                       const char *dir;
+                       const char *otp;
+                       const char *fw;
+                       const char *tcmd;
+                       const char *patch;
+                       const char *utf;
+                       const char *testscript;
+               } fw;
 
-               const char *fw_otp;
-               const char *fw;
-               const char *fw_tcmd;
-               const char *fw_patch;
-               const char *fw_api2;
                const char *fw_board;
                const char *fw_default_board;
        } hw;
 
        u16 conf_flags;
+       u16 suspend_mode;
        wait_queue_head_t event_wq;
        struct ath6kl_mbox_info mbox_info;
 
@@ -603,6 +638,10 @@ struct ath6kl {
        u8 *fw_patch;
        size_t fw_patch_len;
 
+       u8 *fw_testscript;
+       size_t fw_testscript_len;
+
+       unsigned int fw_api;
        unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN];
 
        struct workqueue_struct *ath6kl_wq;
@@ -676,7 +715,9 @@ struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar);
 void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie);
 int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev);
 
-struct aggr_info *aggr_init(struct net_device *dev);
+struct aggr_info *aggr_init(struct ath6kl_vif *vif);
+void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info,
+                   struct aggr_info_conn *aggr_conn);
 void ath6kl_rx_refill(struct htc_target *target,
                      enum htc_endpoint_id endpoint);
 void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count);
@@ -684,7 +725,7 @@ struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
                                            enum htc_endpoint_id endpoint,
                                            int len);
 void aggr_module_destroy(struct aggr_info *aggr_info);
-void aggr_reset_state(struct aggr_info *aggr_info);
+void aggr_reset_state(struct aggr_info_conn *aggr_conn);
 
 struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 * node_addr);
 struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
@@ -700,7 +741,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel,
 void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel);
 void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
                                u8 keymgmt, u8 ucipher, u8 auth,
-                               u8 assoc_req_len, u8 *assoc_info);
+                               u8 assoc_req_len, u8 *assoc_info, u8 apsd_info);
 void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason,
                             u8 *bssid, u8 assoc_resp_len,
                             u8 *assoc_info, u16 prot_reason_status);
@@ -723,12 +764,18 @@ void ath6kl_wakeup_event(void *dev);
 void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
                         bool wait_fot_compltn, bool cold_reset);
 void ath6kl_init_control_info(struct ath6kl_vif *vif);
-void ath6kl_deinit_if_data(struct ath6kl_vif *vif);
-void ath6kl_core_free(struct ath6kl *ar);
 struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
 void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready);
 int ath6kl_init_hw_start(struct ath6kl *ar);
 int ath6kl_init_hw_stop(struct ath6kl *ar);
+int ath6kl_init_fetch_firmwares(struct ath6kl *ar);
+int ath6kl_init_hw_params(struct ath6kl *ar);
+
 void ath6kl_check_wow_status(struct ath6kl *ar);
 
+struct ath6kl *ath6kl_core_create(struct device *dev);
+int ath6kl_core_init(struct ath6kl *ar);
+void ath6kl_core_cleanup(struct ath6kl *ar);
+void ath6kl_core_destroy(struct ath6kl *ar);
+
 #endif /* CORE_H */
index eb808b4..d832058 100644 (file)
@@ -54,9 +54,42 @@ int ath6kl_printk(const char *level, const char *fmt, ...)
 
        return rtn;
 }
+EXPORT_SYMBOL(ath6kl_printk);
 
 #ifdef CONFIG_ATH6KL_DEBUG
 
+void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       if (!(debug_mask & mask))
+               return;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       ath6kl_printk(KERN_DEBUG, "%pV", &vaf);
+
+       va_end(args);
+}
+EXPORT_SYMBOL(ath6kl_dbg);
+
+void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
+                    const char *msg, const char *prefix,
+                    const void *buf, size_t len)
+{
+       if (debug_mask & mask) {
+               if (msg)
+                       ath6kl_dbg(mask, "%s\n", msg);
+
+               print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
+       }
+}
+EXPORT_SYMBOL(ath6kl_dbg_dump);
+
 #define REG_OUTPUT_LEN_PER_LINE        25
 #define REGTYPE_STR_LEN                100
 
@@ -82,31 +115,31 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
                           struct ath6kl_irq_enable_reg *irq_enable_reg)
 {
 
-       ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n"));
+       ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n"));
 
        if (irq_proc_reg != NULL) {
-               ath6kl_dbg(ATH6KL_DBG_ANY,
+               ath6kl_dbg(ATH6KL_DBG_IRQ,
                        "Host Int status:           0x%x\n",
                        irq_proc_reg->host_int_status);
-               ath6kl_dbg(ATH6KL_DBG_ANY,
+               ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "CPU Int status:            0x%x\n",
                        irq_proc_reg->cpu_int_status);
-               ath6kl_dbg(ATH6KL_DBG_ANY,
+               ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Error Int status:          0x%x\n",
                        irq_proc_reg->error_int_status);
-               ath6kl_dbg(ATH6KL_DBG_ANY,
+               ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Counter Int status:        0x%x\n",
                        irq_proc_reg->counter_int_status);
-               ath6kl_dbg(ATH6KL_DBG_ANY,
+               ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Mbox Frame:                0x%x\n",
                        irq_proc_reg->mbox_frame);
-               ath6kl_dbg(ATH6KL_DBG_ANY,
+               ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Rx Lookahead Valid:        0x%x\n",
                        irq_proc_reg->rx_lkahd_valid);
-               ath6kl_dbg(ATH6KL_DBG_ANY,
+               ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Rx Lookahead 0:            0x%x\n",
                        irq_proc_reg->rx_lkahd[0]);
-               ath6kl_dbg(ATH6KL_DBG_ANY,
+               ath6kl_dbg(ATH6KL_DBG_IRQ,
                           "Rx Lookahead 1:            0x%x\n",
                        irq_proc_reg->rx_lkahd[1]);
 
@@ -115,16 +148,16 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
                         * If the target supports GMBOX hardware, dump some
                         * additional state.
                         */
-                       ath6kl_dbg(ATH6KL_DBG_ANY,
+                       ath6kl_dbg(ATH6KL_DBG_IRQ,
                                "GMBOX Host Int status 2:   0x%x\n",
                                irq_proc_reg->host_int_status2);
-                       ath6kl_dbg(ATH6KL_DBG_ANY,
+                       ath6kl_dbg(ATH6KL_DBG_IRQ,
                                "GMBOX RX Avail:            0x%x\n",
                                irq_proc_reg->gmbox_rx_avail);
-                       ath6kl_dbg(ATH6KL_DBG_ANY,
+                       ath6kl_dbg(ATH6KL_DBG_IRQ,
                                "GMBOX lookahead alias 0:   0x%x\n",
                                irq_proc_reg->rx_gmbox_lkahd_alias[0]);
-                       ath6kl_dbg(ATH6KL_DBG_ANY,
+                       ath6kl_dbg(ATH6KL_DBG_IRQ,
                                "GMBOX lookahead alias 1:   0x%x\n",
                                irq_proc_reg->rx_gmbox_lkahd_alias[1]);
                }
@@ -132,13 +165,13 @@ void ath6kl_dump_registers(struct ath6kl_device *dev,
        }
 
        if (irq_enable_reg != NULL) {
-               ath6kl_dbg(ATH6KL_DBG_ANY,
+               ath6kl_dbg(ATH6KL_DBG_IRQ,
                        "Int status Enable:         0x%x\n",
                        irq_enable_reg->int_status_en);
-               ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n",
+               ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n",
                        irq_enable_reg->cntr_int_status_en);
        }
-       ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n");
+       ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n");
 }
 
 static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
@@ -175,9 +208,6 @@ void dump_cred_dist_stats(struct htc_target *target)
 {
        struct htc_endpoint_credit_dist *ep_list;
 
-       if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_CREDIT))
-               return;
-
        list_for_each_entry(ep_list, &target->cred_dist_list, list)
                dump_cred_dist(ep_list);
 
@@ -1411,6 +1441,8 @@ static ssize_t ath6kl_create_qos_write(struct file *file,
                return -EINVAL;
        pstream.medium_time = cpu_to_le32(val32);
 
+       pstream.nominal_phy = le32_to_cpu(pstream.min_phy_rate) / 1000000;
+
        ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream);
 
        return count;
@@ -1505,57 +1537,46 @@ static const struct file_operations fops_bgscan_int = {
 };
 
 static ssize_t ath6kl_listen_int_write(struct file *file,
-                                               const char __user *user_buf,
-                                               size_t count, loff_t *ppos)
+                                      const char __user *user_buf,
+                                      size_t count, loff_t *ppos)
 {
        struct ath6kl *ar = file->private_data;
-       u16 listen_int_t, listen_int_b;
+       struct ath6kl_vif *vif;
+       u16 listen_interval;
        char buf[32];
-       char *sptr, *token;
        ssize_t len;
 
+       vif = ath6kl_vif_first(ar);
+       if (!vif)
+               return -EIO;
+
        len = min(count, sizeof(buf) - 1);
        if (copy_from_user(buf, user_buf, len))
                return -EFAULT;
 
        buf[len] = '\0';
-       sptr = buf;
-
-       token = strsep(&sptr, " ");
-       if (!token)
-               return -EINVAL;
-
-       if (kstrtou16(token, 0, &listen_int_t))
-               return -EINVAL;
-
-       if (kstrtou16(sptr, 0, &listen_int_b))
-               return -EINVAL;
-
-       if ((listen_int_t < 15) || (listen_int_t > 5000))
+       if (kstrtou16(buf, 0, &listen_interval))
                return -EINVAL;
 
-       if ((listen_int_b < 1) || (listen_int_b > 50))
+       if ((listen_interval < 1) || (listen_interval > 50))
                return -EINVAL;
 
-       ar->listen_intvl_t = listen_int_t;
-       ar->listen_intvl_b = listen_int_b;
-
-       ath6kl_wmi_listeninterval_cmd(ar->wmi, 0, ar->listen_intvl_t,
+       ar->listen_intvl_b = listen_interval;
+       ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, 0,
                                      ar->listen_intvl_b);
 
        return count;
 }
 
 static ssize_t ath6kl_listen_int_read(struct file *file,
-                                               char __user *user_buf,
-                                               size_t count, loff_t *ppos)
+                                     char __user *user_buf,
+                                     size_t count, loff_t *ppos)
 {
        struct ath6kl *ar = file->private_data;
        char buf[32];
        int len;
 
-       len = scnprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t,
-                                       ar->listen_intvl_b);
+       len = scnprintf(buf, sizeof(buf), "%u\n", ar->listen_intvl_b);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
@@ -1710,6 +1731,9 @@ int ath6kl_debug_init(struct ath6kl *ar)
        debugfs_create_file("bgscan_interval", S_IWUSR,
                                ar->debugfs_phy, ar, &fops_bgscan_int);
 
+       debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR,
+                           ar->debugfs_phy, ar, &fops_listen_int);
+
        debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar,
                                                &fops_power_params);
 
index 9853c9c..c4be6e5 100644 (file)
@@ -41,6 +41,7 @@ enum ATH6K_DEBUG_MASK {
        ATH6KL_DBG_BOOT         = BIT(18),    /* driver init and fw boot */
        ATH6KL_DBG_WMI_DUMP     = BIT(19),
        ATH6KL_DBG_SUSPEND      = BIT(20),
+       ATH6KL_DBG_USB          = BIT(21),
        ATH6KL_DBG_ANY          = 0xffffffff  /* enable all logs */
 };
 
@@ -55,35 +56,16 @@ int ath6kl_printk(const char *level, const char *fmt, ...);
 #define ath6kl_warn(fmt, ...)                                  \
        ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__)
 
-#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask)
-
 enum ath6kl_war {
        ATH6KL_WAR_INVALID_RATE,
 };
 
 #ifdef CONFIG_ATH6KL_DEBUG
-#define ath6kl_dbg(mask, fmt, ...)                                     \
-       ({                                                              \
-        int rtn;                                                       \
-        if (debug_mask & mask)                                         \
-               rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__);    \
-        else                                                           \
-               rtn = 0;                                                \
-                                                                       \
-        rtn;                                                           \
-        })
 
-static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
-                                  const char *msg, const char *prefix,
-                                  const void *buf, size_t len)
-{
-       if (debug_mask & mask) {
-               if (msg)
-                       ath6kl_dbg(mask, "%s\n", msg);
-
-               print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
-       }
-}
+void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...);
+void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
+                    const char *msg, const char *prefix,
+                    const void *buf, size_t len);
 
 void ath6kl_dump_registers(struct ath6kl_device *dev,
                           struct ath6kl_irq_proc_registers *irq_proc_reg,
index e57da35..e911737 100644 (file)
@@ -15,6 +15,8 @@
  */
 #include "hif.h"
 
+#include <linux/export.h>
+
 #include "core.h"
 #include "target.h"
 #include "hif-ops.h"
@@ -59,6 +61,8 @@ int ath6kl_hif_rw_comp_handler(void *context, int status)
 
        return 0;
 }
+EXPORT_SYMBOL(ath6kl_hif_rw_comp_handler);
+
 #define REG_DUMP_COUNT_AR6003   60
 #define REGISTER_DUMP_LEN_MAX   60
 
@@ -429,9 +433,8 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
                if (status)
                        goto out;
 
-               if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ))
-                       ath6kl_dump_registers(dev, &dev->irq_proc_reg,
-                                        &dev->irq_en_reg);
+               ath6kl_dump_registers(dev, &dev->irq_proc_reg,
+                                     &dev->irq_en_reg);
 
                /* Update only those registers that are enabled */
                host_int_status = dev->irq_proc_reg.host_int_status &
@@ -561,6 +564,7 @@ int ath6kl_hif_intr_bh_handler(struct ath6kl *ar)
 
        return status;
 }
+EXPORT_SYMBOL(ath6kl_hif_intr_bh_handler);
 
 static int ath6kl_hif_enable_intrs(struct ath6kl_device *dev)
 {
@@ -689,6 +693,11 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
        ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
                   dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
 
+       /* usb doesn't support enabling interrupts */
+       /* FIXME: remove check once USB support is implemented */
+       if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
+               return 0;
+
        status = ath6kl_hif_disable_intrs(dev);
 
 fail_setup:
index f3b63ca..2d72190 100644 (file)
@@ -2062,6 +2062,7 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
        enum htc_endpoint_id id;
        int n_fetched = 0;
 
+       INIT_LIST_HEAD(&comp_pktq);
        *num_pkts = 0;
 
        /*
@@ -2543,6 +2544,12 @@ int ath6kl_htc_wait_target(struct htc_target *target)
        struct htc_service_connect_resp resp;
        int status;
 
+       /* FIXME: remove once USB support is implemented */
+       if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) {
+               ath6kl_err("HTC doesn't support USB yet. Patience!\n");
+               return -EOPNOTSUPP;
+       }
+
        /* we should be getting 1 control message that the target is ready */
        packet = htc_wait_for_ctrl_msg(target);
 
@@ -2772,7 +2779,9 @@ void ath6kl_htc_cleanup(struct htc_target *target)
 {
        struct htc_packet *packet, *tmp_packet;
 
-       ath6kl_hif_cleanup_scatter(target->dev->ar);
+       /* FIXME: remove check once USB support is implemented */
+       if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB)
+               ath6kl_hif_cleanup_scatter(target->dev->ar);
 
        list_for_each_entry_safe(packet, tmp_packet,
                        &target->free_ctrl_txbuf, list) {
index 7f55be3..0d76c37 100644 (file)
 
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
+#include <linux/export.h>
 #include <linux/of.h>
 #include <linux/mmc/sdio_func.h>
+
 #include "core.h"
 #include "cfg80211.h"
 #include "target.h"
 #include "debug.h"
 #include "hif-ops.h"
 
-unsigned int debug_mask;
-static unsigned int testmode;
-static bool suspend_cutpower;
-
-module_param(debug_mask, uint, 0644);
-module_param(testmode, uint, 0644);
-module_param(suspend_cutpower, bool, 0444);
-
 static const struct ath6kl_hw hw_list[] = {
        {
                .id                             = AR6003_HW_2_0_VERSION,
@@ -47,11 +41,14 @@ static const struct ath6kl_hw hw_list[] = {
                /* hw2.0 needs override address hardcoded */
                .app_start_override_addr        = 0x944C00,
 
-               .fw_otp                 = AR6003_HW_2_0_OTP_FILE,
-               .fw                     = AR6003_HW_2_0_FIRMWARE_FILE,
-               .fw_tcmd                = AR6003_HW_2_0_TCMD_FIRMWARE_FILE,
-               .fw_patch               = AR6003_HW_2_0_PATCH_FILE,
-               .fw_api2                = AR6003_HW_2_0_FIRMWARE_2_FILE,
+               .fw = {
+                       .dir            = AR6003_HW_2_0_FW_DIR,
+                       .otp            = AR6003_HW_2_0_OTP_FILE,
+                       .fw             = AR6003_HW_2_0_FIRMWARE_FILE,
+                       .tcmd           = AR6003_HW_2_0_TCMD_FIRMWARE_FILE,
+                       .patch          = AR6003_HW_2_0_PATCH_FILE,
+               },
+
                .fw_board               = AR6003_HW_2_0_BOARD_DATA_FILE,
                .fw_default_board       = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE,
        },
@@ -64,12 +61,18 @@ static const struct ath6kl_hw hw_list[] = {
                .reserved_ram_size              = 512,
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
+               .testscript_addr                = 0x57ef74,
+
+               .fw = {
+                       .dir            = AR6003_HW_2_1_1_FW_DIR,
+                       .otp            = AR6003_HW_2_1_1_OTP_FILE,
+                       .fw             = AR6003_HW_2_1_1_FIRMWARE_FILE,
+                       .tcmd           = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,
+                       .patch          = AR6003_HW_2_1_1_PATCH_FILE,
+                       .utf            = AR6003_HW_2_1_1_UTF_FIRMWARE_FILE,
+                       .testscript     = AR6003_HW_2_1_1_TESTSCRIPT_FILE,
+               },
 
-               .fw_otp                 = AR6003_HW_2_1_1_OTP_FILE,
-               .fw                     = AR6003_HW_2_1_1_FIRMWARE_FILE,
-               .fw_tcmd                = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,
-               .fw_patch               = AR6003_HW_2_1_1_PATCH_FILE,
-               .fw_api2                = AR6003_HW_2_1_1_FIRMWARE_2_FILE,
                .fw_board               = AR6003_HW_2_1_1_BOARD_DATA_FILE,
                .fw_default_board       = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
        },
@@ -84,8 +87,11 @@ static const struct ath6kl_hw hw_list[] = {
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 11,
 
-               .fw                     = AR6004_HW_1_0_FIRMWARE_FILE,
-               .fw_api2                = AR6004_HW_1_0_FIRMWARE_2_FILE,
+               .fw = {
+                       .dir            = AR6004_HW_1_0_FW_DIR,
+                       .fw             = AR6004_HW_1_0_FIRMWARE_FILE,
+               },
+
                .fw_board               = AR6004_HW_1_0_BOARD_DATA_FILE,
                .fw_default_board       = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE,
        },
@@ -100,8 +106,11 @@ static const struct ath6kl_hw hw_list[] = {
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
 
-               .fw                     = AR6004_HW_1_1_FIRMWARE_FILE,
-               .fw_api2                = AR6004_HW_1_1_FIRMWARE_2_FILE,
+               .fw = {
+                       .dir            = AR6004_HW_1_1_FW_DIR,
+                       .fw             = AR6004_HW_1_1_FIRMWARE_FILE,
+               },
+
                .fw_board               = AR6004_HW_1_1_BOARD_DATA_FILE,
                .fw_default_board       = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
        },
@@ -452,6 +461,13 @@ int ath6kl_configure_target(struct ath6kl *ar)
        u8 fw_iftype, fw_mode = 0, fw_submode = 0;
        int i, status;
 
+       param = !!(ar->conf_flags & ATH6KL_CONF_UART_DEBUG);
+       if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar,
+                            HI_ITEM(hi_serial_enable)), (u8 *)&param, 4)) {
+               ath6kl_err("bmi_write_memory for uart debug failed\n");
+               return -EIO;
+       }
+
        /*
         * Note: Even though the firmware interface type is
         * chosen as BSS_STA for all three interfaces, can
@@ -573,36 +589,6 @@ int ath6kl_configure_target(struct ath6kl *ar)
        return 0;
 }
 
-void ath6kl_core_free(struct ath6kl *ar)
-{
-       wiphy_free(ar->wiphy);
-}
-
-void ath6kl_core_cleanup(struct ath6kl *ar)
-{
-       ath6kl_hif_power_off(ar);
-
-       destroy_workqueue(ar->ath6kl_wq);
-
-       if (ar->htc_target)
-               ath6kl_htc_cleanup(ar->htc_target);
-
-       ath6kl_cookie_cleanup(ar);
-
-       ath6kl_cleanup_amsdu_rxbufs(ar);
-
-       ath6kl_bmi_cleanup(ar);
-
-       ath6kl_debug_cleanup(ar);
-
-       kfree(ar->fw_board);
-       kfree(ar->fw_otp);
-       kfree(ar->fw);
-       kfree(ar->fw_patch);
-
-       ath6kl_deinit_ieee80211_hw(ar);
-}
-
 /* firmware upload */
 static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
                         u8 **fw, size_t *fw_len)
@@ -626,21 +612,6 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
 }
 
 #ifdef CONFIG_OF
-static const char *get_target_ver_dir(const struct ath6kl *ar)
-{
-       switch (ar->version.target_ver) {
-       case AR6003_HW_1_0_VERSION:
-               return "ath6k/AR6003/hw1.0";
-       case AR6003_HW_2_0_VERSION:
-               return "ath6k/AR6003/hw2.0";
-       case AR6003_HW_2_1_1_VERSION:
-               return "ath6k/AR6003/hw2.1.1";
-       }
-       ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__,
-                   ar->version.target_ver);
-       return NULL;
-}
-
 /*
  * Check the device tree for a board-id and use it to construct
  * the pathname to the firmware file.  Used (for now) to find a
@@ -663,7 +634,7 @@ static bool check_device_tree(struct ath6kl *ar)
                        continue;
                }
                snprintf(board_filename, sizeof(board_filename),
-                        "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id);
+                        "%s/bdata.%s.bin", ar->hw.fw.dir, board_id);
 
                ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board,
                                    &ar->fw_board_len);
@@ -730,19 +701,20 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
 
 static int ath6kl_fetch_otp_file(struct ath6kl *ar)
 {
-       const char *filename;
+       char filename[100];
        int ret;
 
        if (ar->fw_otp != NULL)
                return 0;
 
-       if (ar->hw.fw_otp == NULL) {
+       if (ar->hw.fw.otp == NULL) {
                ath6kl_dbg(ATH6KL_DBG_BOOT,
                           "no OTP file configured for this hw\n");
                return 0;
        }
 
-       filename = ar->hw.fw_otp;
+       snprintf(filename, sizeof(filename), "%s/%s",
+                ar->hw.fw.dir, ar->hw.fw.otp);
 
        ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
                            &ar->fw_otp_len);
@@ -755,33 +727,61 @@ static int ath6kl_fetch_otp_file(struct ath6kl *ar)
        return 0;
 }
 
-static int ath6kl_fetch_fw_file(struct ath6kl *ar)
+static int ath6kl_fetch_testmode_file(struct ath6kl *ar)
 {
-       const char *filename;
+       char filename[100];
        int ret;
 
-       if (ar->fw != NULL)
+       if (ar->testmode == 0)
                return 0;
 
-       if (testmode) {
-               if (ar->hw.fw_tcmd == NULL) {
-                       ath6kl_warn("testmode not supported\n");
+       ath6kl_dbg(ATH6KL_DBG_BOOT, "testmode %d\n", ar->testmode);
+
+       if (ar->testmode == 2) {
+               if (ar->hw.fw.utf == NULL) {
+                       ath6kl_warn("testmode 2 not supported\n");
+                       return -EOPNOTSUPP;
+               }
+
+               snprintf(filename, sizeof(filename), "%s/%s",
+                        ar->hw.fw.dir, ar->hw.fw.utf);
+       } else {
+               if (ar->hw.fw.tcmd == NULL) {
+                       ath6kl_warn("testmode 1 not supported\n");
                        return -EOPNOTSUPP;
                }
 
-               filename = ar->hw.fw_tcmd;
+               snprintf(filename, sizeof(filename), "%s/%s",
+                        ar->hw.fw.dir, ar->hw.fw.tcmd);
+       }
 
-               set_bit(TESTMODE, &ar->flag);
+       set_bit(TESTMODE, &ar->flag);
 
-               goto get_fw;
+       ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
+       if (ret) {
+               ath6kl_err("Failed to get testmode %d firmware file %s: %d\n",
+                          ar->testmode, filename, ret);
+               return ret;
        }
 
-       if (WARN_ON(ar->hw.fw == NULL))
+       return 0;
+}
+
+static int ath6kl_fetch_fw_file(struct ath6kl *ar)
+{
+       char filename[100];
+       int ret;
+
+       if (ar->fw != NULL)
+               return 0;
+
+       /* FIXME: remove WARN_ON() as we won't support FW API 1 for long */
+       if (WARN_ON(ar->hw.fw.fw == NULL))
                return -EINVAL;
 
-       filename = ar->hw.fw;
+       snprintf(filename, sizeof(filename), "%s/%s",
+                ar->hw.fw.dir, ar->hw.fw.fw);
 
-get_fw:
        ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
        if (ret) {
                ath6kl_err("Failed to get firmware file %s: %d\n",
@@ -794,16 +794,17 @@ get_fw:
 
 static int ath6kl_fetch_patch_file(struct ath6kl *ar)
 {
-       const char *filename;
+       char filename[100];
        int ret;
 
        if (ar->fw_patch != NULL)
                return 0;
 
-       if (ar->hw.fw_patch == NULL)
+       if (ar->hw.fw.patch == NULL)
                return 0;
 
-       filename = ar->hw.fw_patch;
+       snprintf(filename, sizeof(filename), "%s/%s",
+                ar->hw.fw.dir, ar->hw.fw.patch);
 
        ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
                            &ar->fw_patch_len);
@@ -816,6 +817,34 @@ static int ath6kl_fetch_patch_file(struct ath6kl *ar)
        return 0;
 }
 
+static int ath6kl_fetch_testscript_file(struct ath6kl *ar)
+{
+       char filename[100];
+       int ret;
+
+       if (ar->testmode != 2)
+               return 0;
+
+       if (ar->fw_testscript != NULL)
+               return 0;
+
+       if (ar->hw.fw.testscript == NULL)
+               return 0;
+
+       snprintf(filename, sizeof(filename), "%s/%s",
+               ar->hw.fw.dir, ar->hw.fw.testscript);
+
+       ret = ath6kl_get_fw(ar, filename, &ar->fw_testscript,
+                               &ar->fw_testscript_len);
+       if (ret) {
+               ath6kl_err("Failed to get testscript file %s: %d\n",
+                       filename, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int ath6kl_fetch_fw_api1(struct ath6kl *ar)
 {
        int ret;
@@ -832,23 +861,24 @@ static int ath6kl_fetch_fw_api1(struct ath6kl *ar)
        if (ret)
                return ret;
 
+       ret = ath6kl_fetch_testscript_file(ar);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
-static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
+static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
 {
        size_t magic_len, len, ie_len;
        const struct firmware *fw;
        struct ath6kl_fw_ie *hdr;
-       const char *filename;
+       char filename[100];
        const u8 *data;
        int ret, ie_id, i, index, bit;
        __le32 *val;
 
-       if (ar->hw.fw_api2 == NULL)
-               return -EOPNOTSUPP;
-
-       filename = ar->hw.fw_api2;
+       snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name);
 
        ret = request_firmware(&fw, filename, ar->dev);
        if (ret)
@@ -907,6 +937,10 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
                        ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n",
                                ie_len);
 
+                       /* in testmode we already might have a fw file */
+                       if (ar->fw != NULL)
+                               break;
+
                        ar->fw = kmemdup(data, ie_len, GFP_KERNEL);
 
                        if (ar->fw == NULL) {
@@ -1010,7 +1044,7 @@ out:
        return ret;
 }
 
-static int ath6kl_fetch_firmwares(struct ath6kl *ar)
+int ath6kl_init_fetch_firmwares(struct ath6kl *ar)
 {
        int ret;
 
@@ -1018,17 +1052,30 @@ static int ath6kl_fetch_firmwares(struct ath6kl *ar)
        if (ret)
                return ret;
 
-       ret = ath6kl_fetch_fw_api2(ar);
+       ret = ath6kl_fetch_testmode_file(ar);
+       if (ret)
+               return ret;
+
+       ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);
        if (ret == 0) {
-               ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n");
-               return 0;
+               ar->fw_api = 3;
+               goto out;
+       }
+
+       ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API2_FILE);
+       if (ret == 0) {
+               ar->fw_api = 2;
+               goto out;
        }
 
        ret = ath6kl_fetch_fw_api1(ar);
        if (ret)
                return ret;
 
-       ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n");
+       ar->fw_api = 1;
+
+out:
+       ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api %d\n", ar->fw_api);
 
        return 0;
 }
@@ -1249,6 +1296,50 @@ static int ath6kl_upload_patch(struct ath6kl *ar)
        return 0;
 }
 
+static int ath6kl_upload_testscript(struct ath6kl *ar)
+{
+       u32 address, param;
+       int ret;
+
+       if (ar->testmode != 2)
+               return 0;
+
+       if (ar->fw_testscript == NULL)
+               return 0;
+
+       address = ar->hw.testscript_addr;
+
+       ath6kl_dbg(ATH6KL_DBG_BOOT, "writing testscript to 0x%x (%zd B)\n",
+               address, ar->fw_testscript_len);
+
+       ret = ath6kl_bmi_write(ar, address, ar->fw_testscript,
+               ar->fw_testscript_len);
+       if (ret) {
+               ath6kl_err("Failed to write testscript file: %d\n", ret);
+               return ret;
+       }
+
+       param = address;
+       ath6kl_bmi_write(ar,
+                       ath6kl_get_hi_item_addr(ar,
+                       HI_ITEM(hi_ota_testscript)),
+                       (unsigned char *) &param, 4);
+
+       param = 4096;
+       ath6kl_bmi_write(ar,
+                       ath6kl_get_hi_item_addr(ar,
+                       HI_ITEM(hi_end_ram_reserve_sz)),
+                       (unsigned char *) &param, 4);
+
+       param = 1;
+       ath6kl_bmi_write(ar,
+                       ath6kl_get_hi_item_addr(ar,
+                       HI_ITEM(hi_test_apps_related)),
+                       (unsigned char *) &param, 4);
+
+       return 0;
+}
+
 static int ath6kl_init_upload(struct ath6kl *ar)
 {
        u32 param, options, sleep, address;
@@ -1357,6 +1448,11 @@ static int ath6kl_init_upload(struct ath6kl *ar)
        if (status)
                return status;
 
+       /* Download the test script */
+       status = ath6kl_upload_testscript(ar);
+       if (status)
+               return status;
+
        /* Restore system sleep */
        address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS;
        status = ath6kl_bmi_reg_write(ar, address, sleep);
@@ -1372,9 +1468,9 @@ static int ath6kl_init_upload(struct ath6kl *ar)
        return status;
 }
 
-static int ath6kl_init_hw_params(struct ath6kl *ar)
+int ath6kl_init_hw_params(struct ath6kl *ar)
 {
-       const struct ath6kl_hw *hw;
+       const struct ath6kl_hw *uninitialized_var(hw);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
@@ -1481,10 +1577,11 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
 
 
        if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
-               ath6kl_info("%s %s fw %s%s\n",
+               ath6kl_info("%s %s fw %s api %d%s\n",
                            ar->hw.name,
                            ath6kl_init_get_hif_name(ar->hif_type),
                            ar->wiphy->fw_version,
+                           ar->fw_api,
                            test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
        }
 
@@ -1549,173 +1646,7 @@ int ath6kl_init_hw_stop(struct ath6kl *ar)
        return 0;
 }
 
-int ath6kl_core_init(struct ath6kl *ar)
-{
-       struct ath6kl_bmi_target_info targ_info;
-       struct net_device *ndev;
-       int ret = 0, i;
-
-       ar->ath6kl_wq = create_singlethread_workqueue("ath6kl");
-       if (!ar->ath6kl_wq)
-               return -ENOMEM;
-
-       ret = ath6kl_bmi_init(ar);
-       if (ret)
-               goto err_wq;
-
-       /*
-        * Turn on power to get hardware (target) version and leave power
-        * on delibrately as we will boot the hardware anyway within few
-        * seconds.
-        */
-       ret = ath6kl_hif_power_on(ar);
-       if (ret)
-               goto err_bmi_cleanup;
-
-       ret = ath6kl_bmi_get_target_info(ar, &targ_info);
-       if (ret)
-               goto err_power_off;
-
-       ar->version.target_ver = le32_to_cpu(targ_info.version);
-       ar->target_type = le32_to_cpu(targ_info.type);
-       ar->wiphy->hw_version = le32_to_cpu(targ_info.version);
-
-       ret = ath6kl_init_hw_params(ar);
-       if (ret)
-               goto err_power_off;
-
-       ar->htc_target = ath6kl_htc_create(ar);
-
-       if (!ar->htc_target) {
-               ret = -ENOMEM;
-               goto err_power_off;
-       }
-
-       ret = ath6kl_fetch_firmwares(ar);
-       if (ret)
-               goto err_htc_cleanup;
-
-       /* FIXME: we should free all firmwares in the error cases below */
-
-       /* Indicate that WMI is enabled (although not ready yet) */
-       set_bit(WMI_ENABLED, &ar->flag);
-       ar->wmi = ath6kl_wmi_init(ar);
-       if (!ar->wmi) {
-               ath6kl_err("failed to initialize wmi\n");
-               ret = -EIO;
-               goto err_htc_cleanup;
-       }
-
-       ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi);
-
-       ret = ath6kl_register_ieee80211_hw(ar);
-       if (ret)
-               goto err_node_cleanup;
-
-       ret = ath6kl_debug_init(ar);
-       if (ret) {
-               wiphy_unregister(ar->wiphy);
-               goto err_node_cleanup;
-       }
-
-       for (i = 0; i < ar->vif_max; i++)
-               ar->avail_idx_map |= BIT(i);
-
-       rtnl_lock();
-
-       /* Add an initial station interface */
-       ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
-                                   INFRA_NETWORK);
-
-       rtnl_unlock();
-
-       if (!ndev) {
-               ath6kl_err("Failed to instantiate a network device\n");
-               ret = -ENOMEM;
-               wiphy_unregister(ar->wiphy);
-               goto err_debug_init;
-       }
-
-
-       ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
-                       __func__, ndev->name, ndev, ar);
-
-       /* setup access class priority mappings */
-       ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest  */
-       ar->ac_stream_pri_map[WMM_AC_BE] = 1;
-       ar->ac_stream_pri_map[WMM_AC_VI] = 2;
-       ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */
-
-       /* give our connected endpoints some buffers */
-       ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep);
-       ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]);
-
-       /* allocate some buffers that handle larger AMSDU frames */
-       ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS);
-
-       ath6kl_cookie_init(ar);
-
-       ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
-                        ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
-
-       if (suspend_cutpower)
-               ar->conf_flags |= ATH6KL_CONF_SUSPEND_CUTPOWER;
-
-       ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
-                           WIPHY_FLAG_HAVE_AP_SME |
-                           WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
-                           WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
-
-       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
-               ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
-
-       ar->wiphy->probe_resp_offload =
-               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
-               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
-               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
-               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
-
-       set_bit(FIRST_BOOT, &ar->flag);
-
-       ret = ath6kl_init_hw_start(ar);
-       if (ret) {
-               ath6kl_err("Failed to start hardware: %d\n", ret);
-               goto err_rxbuf_cleanup;
-       }
-
-       /*
-        * Set mac address which is received in ready event
-        * FIXME: Move to ath6kl_interface_add()
-        */
-       memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
-
-       return ret;
-
-err_rxbuf_cleanup:
-       ath6kl_htc_flush_rx_buf(ar->htc_target);
-       ath6kl_cleanup_amsdu_rxbufs(ar);
-       rtnl_lock();
-       ath6kl_deinit_if_data(netdev_priv(ndev));
-       rtnl_unlock();
-       wiphy_unregister(ar->wiphy);
-err_debug_init:
-       ath6kl_debug_cleanup(ar);
-err_node_cleanup:
-       ath6kl_wmi_shutdown(ar->wmi);
-       clear_bit(WMI_ENABLED, &ar->flag);
-       ar->wmi = NULL;
-err_htc_cleanup:
-       ath6kl_htc_cleanup(ar->htc_target);
-err_power_off:
-       ath6kl_hif_power_off(ar);
-err_bmi_cleanup:
-       ath6kl_bmi_cleanup(ar);
-err_wq:
-       destroy_workqueue(ar->ath6kl_wq);
-
-       return ret;
-}
-
+/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
 void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
 {
        static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
@@ -1747,6 +1678,7 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
 void ath6kl_stop_txrx(struct ath6kl *ar)
 {
        struct ath6kl_vif *vif, *tmp_vif;
+       int i;
 
        set_bit(DESTROY_IN_PROGRESS, &ar->flag);
 
@@ -1755,13 +1687,16 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
                return;
        }
 
+       for (i = 0; i < AP_MAX_NUM_STA; i++)
+               aggr_reset_state(ar->sta_list[i].aggr_conn);
+
        spin_lock_bh(&ar->list_lock);
        list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) {
                list_del(&vif->list);
                spin_unlock_bh(&ar->list_lock);
                ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
                rtnl_lock();
-               ath6kl_deinit_if_data(vif);
+               ath6kl_cfg80211_vif_cleanup(vif);
                rtnl_unlock();
                spin_lock_bh(&ar->list_lock);
        }
@@ -1796,3 +1731,4 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
 
        clear_bit(WLAN_ENABLED, &ar->flag);
 }
+EXPORT_SYMBOL(ath6kl_stop_txrx);
index eea3c74..b96d01a 100644 (file)
@@ -52,9 +52,11 @@ struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid)
        return conn;
 }
 
-static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie,
-                       u8 ielen, u8 keymgmt, u8 ucipher, u8 auth)
+static void ath6kl_add_new_sta(struct ath6kl_vif *vif, u8 *mac, u16 aid,
+                              u8 *wpaie, size_t ielen, u8 keymgmt,
+                              u8 ucipher, u8 auth, u8 apsd_info)
 {
+       struct ath6kl *ar = vif->ar;
        struct ath6kl_sta *sta;
        u8 free_slot;
 
@@ -68,9 +70,11 @@ static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie,
        sta->keymgmt = keymgmt;
        sta->ucipher = ucipher;
        sta->auth = auth;
+       sta->apsd_info = apsd_info;
 
        ar->sta_list_index = ar->sta_list_index | (1 << free_slot);
        ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid);
+       aggr_conn_init(vif, vif->aggr_cntxt, sta->aggr_conn);
 }
 
 static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
@@ -80,6 +84,7 @@ static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
        /* empty the queued pkts in the PS queue if any */
        spin_lock_bh(&sta->psq_lock);
        skb_queue_purge(&sta->psq);
+       skb_queue_purge(&sta->apsdq);
        spin_unlock_bh(&sta->psq_lock);
 
        memset(&ar->ap_stats.sta[sta->aid - 1], 0,
@@ -90,7 +95,7 @@ static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i)
        sta->sta_flags = 0;
 
        ar->sta_list_index = ar->sta_list_index & ~(1 << i);
-
+       aggr_reset_state(sta->aggr_conn);
 }
 
 static u8 ath6kl_remove_sta(struct ath6kl *ar, u8 *mac, u16 reason)
@@ -252,7 +257,7 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
        struct ath6kl_dbglog_hdr debug_hdr;
        struct ath6kl_dbglog_buf debug_buf;
        u32 address, length, dropped, firstbuf, debug_hdr_addr;
-       int ret = 0, loop;
+       int ret, loop;
        u8 *buf;
 
        buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL);
@@ -347,9 +352,6 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
        case TARGET_TYPE_AR6004:
                address = AR6004_RESET_CONTROL_ADDRESS;
                break;
-       default:
-               address = AR6003_RESET_CONTROL_ADDRESS;
-               break;
        }
 
        status = ath6kl_diag_write32(ar, address, data);
@@ -363,7 +365,7 @@ static void ath6kl_install_static_wep_keys(struct ath6kl_vif *vif)
        u8 index;
        u8 keyusage;
 
-       for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) {
+       for (index = 0; index <= WMI_MAX_KEY_INDEX; index++) {
                if (vif->wep_key_list[index].key_len) {
                        keyusage = GROUP_USAGE;
                        if (index == vif->def_txkey_index)
@@ -428,9 +430,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
 
 void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
                                u8 keymgmt, u8 ucipher, u8 auth,
-                               u8 assoc_req_len, u8 *assoc_info)
+                               u8 assoc_req_len, u8 *assoc_info, u8 apsd_info)
 {
-       struct ath6kl *ar = vif->ar;
        u8 *ies = NULL, *wpa_ie = NULL, *pos;
        size_t ies_len = 0;
        struct station_info sinfo;
@@ -484,9 +485,9 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
                pos += 2 + pos[1];
        }
 
-       ath6kl_add_new_sta(ar, mac_addr, aid, wpa_ie,
+       ath6kl_add_new_sta(vif, mac_addr, aid, wpa_ie,
                           wpa_ie ? 2 + wpa_ie[1] : 0,
-                          keymgmt, ucipher, auth);
+                          keymgmt, ucipher, auth, apsd_info);
 
        /* send event to application */
        memset(&sinfo, 0, sizeof(sinfo));
@@ -587,10 +588,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
        memcpy(vif->bssid, bssid, sizeof(vif->bssid));
        vif->bss_ch = channel;
 
-       if ((vif->nw_type == INFRA_NETWORK))
+       if ((vif->nw_type == INFRA_NETWORK)) {
+               ar->listen_intvl_b = listen_int;
                ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
-                                             ar->listen_intvl_t,
-                                             ar->listen_intvl_b);
+                                             0, ar->listen_intvl_b);
+       }
 
        netif_wake_queue(vif->ndev);
 
@@ -601,7 +603,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
        netif_carrier_on(vif->ndev);
        spin_unlock_bh(&vif->if_lock);
 
-       aggr_reset_state(vif->aggr_cntxt);
+       aggr_reset_state(vif->aggr_cntxt->aggr_conn);
        vif->reconnect_flag = 0;
 
        if ((vif->nw_type == ADHOC_NETWORK) && ar->ibss_ps_enable) {
@@ -923,7 +925,7 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
                                       assoc_resp_len, assoc_info,
                                       prot_reason_status);
 
-       aggr_reset_state(vif->aggr_cntxt);
+       aggr_reset_state(vif->aggr_cntxt->aggr_conn);
 
        del_timer(&vif->disconnect_timer);
 
@@ -1020,11 +1022,155 @@ static struct net_device_stats *ath6kl_get_stats(struct net_device *dev)
        return &vif->net_stats;
 }
 
-static struct net_device_ops ath6kl_netdev_ops = {
+static int ath6kl_set_features(struct net_device *dev,
+                              netdev_features_t features)
+{
+       struct ath6kl_vif *vif = netdev_priv(dev);
+       struct ath6kl *ar = vif->ar;
+       int err = 0;
+
+       if ((features & NETIF_F_RXCSUM) &&
+           (ar->rx_meta_ver != WMI_META_VERSION_2)) {
+               ar->rx_meta_ver = WMI_META_VERSION_2;
+               err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
+                                                        vif->fw_vif_idx,
+                                                        ar->rx_meta_ver, 0, 0);
+               if (err) {
+                       dev->features = features & ~NETIF_F_RXCSUM;
+                       return err;
+               }
+       } else if (!(features & NETIF_F_RXCSUM) &&
+                  (ar->rx_meta_ver == WMI_META_VERSION_2)) {
+               ar->rx_meta_ver = 0;
+               err = ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi,
+                                                        vif->fw_vif_idx,
+                                                        ar->rx_meta_ver, 0, 0);
+               if (err) {
+                       dev->features = features | NETIF_F_RXCSUM;
+                       return err;
+               }
+
+       }
+
+       return err;
+}
+
+static void ath6kl_set_multicast_list(struct net_device *ndev)
+{
+       struct ath6kl_vif *vif = netdev_priv(ndev);
+       bool mc_all_on = false, mc_all_off = false;
+       int mc_count = netdev_mc_count(ndev);
+       struct netdev_hw_addr *ha;
+       bool found;
+       struct ath6kl_mc_filter *mc_filter, *tmp;
+       struct list_head mc_filter_new;
+       int ret;
+
+       if (!test_bit(WMI_READY, &vif->ar->flag) ||
+           !test_bit(WLAN_ENABLED, &vif->flags))
+               return;
+
+       mc_all_on = !!(ndev->flags & IFF_PROMISC) ||
+                   !!(ndev->flags & IFF_ALLMULTI) ||
+                   !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST);
+
+       mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0;
+
+       if (mc_all_on || mc_all_off) {
+               /* Enable/disable all multicast */
+               ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n",
+                         mc_all_on ? "enabling" : "disabling");
+               ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
+                                                 mc_all_on);
+               if (ret)
+                       ath6kl_warn("Failed to %s multicast receive\n",
+                                   mc_all_on ? "enable" : "disable");
+               return;
+       }
+
+       list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
+               found = false;
+               netdev_for_each_mc_addr(ha, ndev) {
+                       if (memcmp(ha->addr, mc_filter->hw_addr,
+                           ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       /*
+                        * Delete the filter which was previously set
+                        * but not in the new request.
+                        */
+                       ath6kl_dbg(ATH6KL_DBG_TRC,
+                                  "Removing %pM from multicast filter\n",
+                                  mc_filter->hw_addr);
+                       ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi,
+                                       vif->fw_vif_idx, mc_filter->hw_addr,
+                                       false);
+                       if (ret) {
+                               ath6kl_warn("Failed to remove multicast filter:%pM\n",
+                                            mc_filter->hw_addr);
+                               return;
+                       }
+
+                       list_del(&mc_filter->list);
+                       kfree(mc_filter);
+               }
+       }
+
+       INIT_LIST_HEAD(&mc_filter_new);
+
+       netdev_for_each_mc_addr(ha, ndev) {
+               found = false;
+               list_for_each_entry(mc_filter, &vif->mc_filter, list) {
+                       if (memcmp(ha->addr, mc_filter->hw_addr,
+                           ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE) == 0) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       mc_filter = kzalloc(sizeof(struct ath6kl_mc_filter),
+                                           GFP_ATOMIC);
+                       if (!mc_filter) {
+                               WARN_ON(1);
+                               goto out;
+                       }
+
+                       memcpy(mc_filter->hw_addr, ha->addr,
+                              ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE);
+                       /* Set the multicast filter */
+                       ath6kl_dbg(ATH6KL_DBG_TRC,
+                                  "Adding %pM to multicast filter list\n",
+                                  mc_filter->hw_addr);
+                       ret = ath6kl_wmi_add_del_mcast_filter_cmd(vif->ar->wmi,
+                                       vif->fw_vif_idx, mc_filter->hw_addr,
+                                       true);
+                       if (ret) {
+                               ath6kl_warn("Failed to add multicast filter :%pM\n",
+                                            mc_filter->hw_addr);
+                               kfree(mc_filter);
+                               goto out;
+                       }
+
+                       list_add_tail(&mc_filter->list, &mc_filter_new);
+               }
+       }
+
+out:
+       list_splice_tail(&mc_filter_new, &vif->mc_filter);
+}
+
+static const struct net_device_ops ath6kl_netdev_ops = {
        .ndo_open               = ath6kl_open,
        .ndo_stop               = ath6kl_close,
        .ndo_start_xmit         = ath6kl_data_tx,
        .ndo_get_stats          = ath6kl_get_stats,
+       .ndo_set_features       = ath6kl_set_features,
+       .ndo_set_rx_mode        = ath6kl_set_multicast_list,
 };
 
 void init_netdev(struct net_device *dev)
index 9475e2d..4febee7 100644 (file)
@@ -49,11 +49,13 @@ struct ath6kl_sdio {
        /* scatter request list head */
        struct list_head scat_req;
 
+       /* Avoids disabling irq while the interrupts being handled */
+       struct mutex mtx_irq;
+
        spinlock_t scat_lock;
        bool scatter_enabled;
 
        bool is_disabled;
-       atomic_t irq_handling;
        const struct sdio_device_id *id;
        struct work_struct wr_async_work;
        struct list_head wr_asyncq;
@@ -460,8 +462,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
        ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");
 
        ar_sdio = sdio_get_drvdata(func);
-       atomic_set(&ar_sdio->irq_handling, 1);
-
+       mutex_lock(&ar_sdio->mtx_irq);
        /*
         * Release the host during interrups so we can pick it back up when
         * we process commands.
@@ -470,7 +471,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
 
        status = ath6kl_hif_intr_bh_handler(ar_sdio->ar);
        sdio_claim_host(ar_sdio->func);
-       atomic_set(&ar_sdio->irq_handling, 0);
+       mutex_unlock(&ar_sdio->mtx_irq);
        WARN_ON(status && status != -ECANCELED);
 }
 
@@ -578,17 +579,14 @@ static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
 
        sdio_claim_host(ar_sdio->func);
 
-       /* Mask our function IRQ */
-       while (atomic_read(&ar_sdio->irq_handling)) {
-               sdio_release_host(ar_sdio->func);
-               schedule_timeout(HZ / 10);
-               sdio_claim_host(ar_sdio->func);
-       }
+       mutex_lock(&ar_sdio->mtx_irq);
 
        ret = sdio_release_irq(ar_sdio->func);
        if (ret)
                ath6kl_err("Failed to release sdio irq: %d\n", ret);
 
+       mutex_unlock(&ar_sdio->mtx_irq);
+
        sdio_release_host(ar_sdio->func);
 }
 
@@ -772,7 +770,6 @@ static int ath6kl_sdio_config(struct ath6kl *ar)
        if (ret) {
                ath6kl_err("Set sdio block size %d failed: %d)\n",
                           HIF_MBOX_BLOCK_SIZE, ret);
-               sdio_release_host(func);
                goto out;
        }
 
@@ -782,7 +779,7 @@ out:
        return ret;
 }
 
-static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+static int ath6kl_set_sdio_pm_caps(struct ath6kl *ar)
 {
        struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
        struct sdio_func *func = ar_sdio->func;
@@ -793,60 +790,95 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
 
        ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags);
 
-       if (!(flags & MMC_PM_KEEP_POWER) ||
-           (ar->conf_flags & ATH6KL_CONF_SUSPEND_CUTPOWER)) {
-               /* as host doesn't support keep power we need to cut power */
-               return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
-                                              NULL);
-       }
+       if (!(flags & MMC_PM_WAKE_SDIO_IRQ) ||
+           !(flags & MMC_PM_KEEP_POWER))
+               return -EINVAL;
 
        ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
        if (ret) {
-               printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n",
-                      ret);
+               ath6kl_err("set sdio keep pwr flag failed: %d\n", ret);
                return ret;
        }
 
-       if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
-               goto deepsleep;
-
        /* sdio irq wakes up host */
+       ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+       if (ret)
+               ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
+
+       return ret;
+}
+
+static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+{
+       struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
+       struct sdio_func *func = ar_sdio->func;
+       mmc_pm_flag_t flags;
+       int ret;
 
        if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
+               ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n");
+
+               ret = ath6kl_set_sdio_pm_caps(ar);
+               if (ret)
+                       goto cut_pwr;
+
                ret =  ath6kl_cfg80211_suspend(ar,
                                               ATH6KL_CFG_SUSPEND_SCHED_SCAN,
                                               NULL);
-               if (ret) {
-                       ath6kl_warn("Schedule scan suspend failed: %d", ret);
-                       return ret;
-               }
+               if (ret)
+                       goto cut_pwr;
+
+               return 0;
+       }
+
+       if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
+           (!ar->suspend_mode && wow)) {
 
-               ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+               ret = ath6kl_set_sdio_pm_caps(ar);
                if (ret)
-                       ath6kl_warn("set sdio wake irq flag failed: %d\n", ret);
+                       goto cut_pwr;
 
-               return ret;
+               ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
+               if (ret)
+                       goto cut_pwr;
+
+               return 0;
        }
 
-       if (wow) {
+       if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP ||
+           !ar->suspend_mode) {
+
+               flags = sdio_get_host_pm_caps(func);
+               if (!(flags & MMC_PM_KEEP_POWER))
+                       goto cut_pwr;
+
+               ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+               if (ret)
+                       goto cut_pwr;
+
                /*
-                * The host sdio controller is capable of keep power and
-                * sdio irq wake up at this point. It's fine to continue
-                * wow suspend operation.
+                * Workaround to support Deep Sleep with MSM, set the host pm
+                * flag as MMC_PM_WAKE_SDIO_IRQ to allow SDCC deiver to disable
+                * the sdc2_clock and internally allows MSM to enter
+                * TCXO shutdown properly.
                 */
-               ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
-               if (ret)
-                       return ret;
+               if ((flags & MMC_PM_WAKE_SDIO_IRQ)) {
+                       ret = sdio_set_host_pm_flags(func,
+                                               MMC_PM_WAKE_SDIO_IRQ);
+                       if (ret)
+                               goto cut_pwr;
+               }
 
-               ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+               ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP,
+                                             NULL);
                if (ret)
-                       ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
+                       goto cut_pwr;
 
-               return ret;
+               return 0;
        }
 
-deepsleep:
-       return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
+cut_pwr:
+       return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL);
 }
 
 static int ath6kl_sdio_resume(struct ath6kl *ar)
@@ -1253,6 +1285,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
        spin_lock_init(&ar_sdio->scat_lock);
        spin_lock_init(&ar_sdio->wr_async_lock);
        mutex_init(&ar_sdio->dma_buffer_mutex);
+       mutex_init(&ar_sdio->mtx_irq);
 
        INIT_LIST_HEAD(&ar_sdio->scat_req);
        INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
@@ -1263,7 +1296,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
        for (count = 0; count < BUS_REQUEST_MAX_NUM; count++)
                ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]);
 
-       ar = ath6kl_core_alloc(&ar_sdio->func->dev);
+       ar = ath6kl_core_create(&ar_sdio->func->dev);
        if (!ar) {
                ath6kl_err("Failed to alloc ath6kl core\n");
                ret = -ENOMEM;
@@ -1293,7 +1326,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
        return ret;
 
 err_core_alloc:
-       ath6kl_core_free(ar_sdio->ar);
+       ath6kl_core_destroy(ar_sdio->ar);
 err_dma:
        kfree(ar_sdio->dma_buffer);
 err_hif:
@@ -1316,6 +1349,7 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
        cancel_work_sync(&ar_sdio->wr_async_work);
 
        ath6kl_core_cleanup(ar_sdio->ar);
+       ath6kl_core_destroy(ar_sdio->ar);
 
        kfree(ar_sdio->dma_buffer);
        kfree(ar_sdio);
@@ -1332,7 +1366,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = {
 MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
 
 static struct sdio_driver ath6kl_sdio_driver = {
-       .name = "ath6kl",
+       .name = "ath6kl_sdio",
        .id_table = ath6kl_sdio_devices,
        .probe = ath6kl_sdio_probe,
        .remove = ath6kl_sdio_remove,
@@ -1362,19 +1396,19 @@ MODULE_AUTHOR("Atheros Communications, Inc.");
 MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");
 MODULE_LICENSE("Dual BSD/GPL");
 
-MODULE_FIRMWARE(AR6003_HW_2_0_OTP_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_0_FIRMWARE_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_0_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_OTP_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_0_FW_DIR "/" AR6003_HW_2_0_PATCH_FILE);
 MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_1_1_OTP_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_1_1_FIRMWARE_FILE);
-MODULE_FIRMWARE(AR6003_HW_2_1_1_PATCH_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_OTP_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6003_HW_2_1_1_FW_DIR "/" AR6003_HW_2_1_1_PATCH_FILE);
 MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE);
-MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_0_FW_DIR "/" AR6004_HW_1_0_FIRMWARE_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
-MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
index 381eb66..f0cd61d 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "testmode.h"
+#include "debug.h"
 
 #include <net/netlink.h>
 
@@ -30,7 +31,7 @@ enum ath6kl_tm_attr {
 
 enum ath6kl_tm_cmd {
        ATH6KL_TM_CMD_TCMD              = 0,
-       ATH6KL_TM_CMD_RX_REPORT         = 1,
+       ATH6KL_TM_CMD_RX_REPORT         = 1,    /* not used anymore */
 };
 
 #define ATH6KL_TM_DATA_MAX_LEN         5000
@@ -41,84 +42,33 @@ static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = {
                                            .len = ATH6KL_TM_DATA_MAX_LEN },
 };
 
-void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len)
+void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len)
 {
-       if (down_interruptible(&ar->sem))
-               return;
-
-       kfree(ar->tm.rx_report);
-
-       ar->tm.rx_report = kmemdup(buf, buf_len, GFP_KERNEL);
-       ar->tm.rx_report_len = buf_len;
-
-       up(&ar->sem);
-
-       wake_up(&ar->event_wq);
-}
-
-static int ath6kl_tm_rx_report(struct ath6kl *ar, void *buf, size_t buf_len,
-                              struct sk_buff *skb)
-{
-       int ret = 0;
-       long left;
-
-       if (down_interruptible(&ar->sem))
-               return -ERESTARTSYS;
-
-       if (!test_bit(WMI_READY, &ar->flag)) {
-               ret = -EIO;
-               goto out;
-       }
-
-       if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len) < 0) {
-               up(&ar->sem);
-               return -EIO;
-       }
-
-       left = wait_event_interruptible_timeout(ar->event_wq,
-                                               ar->tm.rx_report != NULL,
-                                               WMI_TIMEOUT);
+       struct sk_buff *skb;
 
-       if (left == 0) {
-               ret = -ETIMEDOUT;
-               goto out;
-       } else if (left < 0) {
-               ret = left;
-               goto out;
-       }
+       if (!buf || buf_len == 0)
+               return;
 
-       if (ar->tm.rx_report == NULL || ar->tm.rx_report_len == 0) {
-               ret = -EINVAL;
-               goto out;
+       skb = cfg80211_testmode_alloc_event_skb(ar->wiphy, buf_len, GFP_KERNEL);
+       if (!skb) {
+               ath6kl_warn("failed to allocate testmode rx skb!\n");
+               return;
        }
-
-       NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, ar->tm.rx_report_len,
-               ar->tm.rx_report);
-
-       kfree(ar->tm.rx_report);
-       ar->tm.rx_report = NULL;
-
-out:
-       up(&ar->sem);
-
-       return ret;
+       NLA_PUT_U32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_TCMD);
+       NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf);
+       cfg80211_testmode_event(skb, GFP_KERNEL);
+       return;
 
 nla_put_failure:
-       ret = -ENOBUFS;
-       goto out;
+       kfree_skb(skb);
+       ath6kl_warn("nla_put failed on testmode rx skb!\n");
 }
 
 int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
 {
        struct ath6kl *ar = wiphy_priv(wiphy);
        struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1];
-       int err, buf_len, reply_len;
-       struct sk_buff *skb;
+       int err, buf_len;
        void *buf;
 
        err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len,
@@ -143,24 +93,6 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len)
 
                break;
        case ATH6KL_TM_CMD_RX_REPORT:
-               if (!tb[ATH6KL_TM_ATTR_DATA])
-                       return -EINVAL;
-
-               buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]);
-               buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]);
-
-               reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN);
-               skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len);
-               if (!skb)
-                       return -ENOMEM;
-
-               err = ath6kl_tm_rx_report(ar, buf, buf_len, skb);
-               if (err < 0) {
-                       kfree_skb(skb);
-                       return err;
-               }
-
-               return cfg80211_testmode_reply(skb);
        default:
                return -EOPNOTSUPP;
        }
index 43dffcc..7fd47a6 100644 (file)
 
 #ifdef CONFIG_NL80211_TESTMODE
 
-void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len);
+void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len);
 int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len);
 
 #else
 
-static inline void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf,
-                                            size_t buf_len)
+static inline void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf,
+                                     size_t buf_len)
 {
 }
 
index 506a303..a3dc694 100644 (file)
 #include "core.h"
 #include "debug.h"
 
+/*
+ * tid - tid_mux0..tid_mux3
+ * aid - tid_mux4..tid_mux7
+ */
+#define ATH6KL_TID_MASK 0xf
+#define ATH6KL_AID_SHIFT 4
+
+static inline u8 ath6kl_get_tid(u8 tid_mux)
+{
+       return tid_mux & ATH6KL_TID_MASK;
+}
+
+static inline u8 ath6kl_get_aid(u8 tid_mux)
+{
+       return tid_mux >> ATH6KL_AID_SHIFT;
+}
+
 static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev,
                               u32 *map_no)
 {
@@ -77,12 +94,118 @@ static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev,
        return ar->node_map[ep_map].ep_id;
 }
 
+static bool ath6kl_process_uapsdq(struct ath6kl_sta *conn,
+                               struct ath6kl_vif *vif,
+                               struct sk_buff *skb,
+                               u32 *flags)
+{
+       struct ath6kl *ar = vif->ar;
+       bool is_apsdq_empty = false;
+       struct ethhdr *datap = (struct ethhdr *) skb->data;
+       u8 up = 0, traffic_class, *ip_hdr;
+       u16 ether_type;
+       struct ath6kl_llc_snap_hdr *llc_hdr;
+
+       if (conn->sta_flags & STA_PS_APSD_TRIGGER) {
+               /*
+                * This tx is because of a uAPSD trigger, determine
+                * more and EOSP bit. Set EOSP if queue is empty
+                * or sufficient frames are delivered for this trigger.
+                */
+               spin_lock_bh(&conn->psq_lock);
+               if (!skb_queue_empty(&conn->apsdq))
+                       *flags |= WMI_DATA_HDR_FLAGS_MORE;
+               else if (conn->sta_flags & STA_PS_APSD_EOSP)
+                       *flags |= WMI_DATA_HDR_FLAGS_EOSP;
+               *flags |= WMI_DATA_HDR_FLAGS_UAPSD;
+               spin_unlock_bh(&conn->psq_lock);
+               return false;
+       } else if (!conn->apsd_info)
+               return false;
+
+       if (test_bit(WMM_ENABLED, &vif->flags)) {
+               ether_type = be16_to_cpu(datap->h_proto);
+               if (is_ethertype(ether_type)) {
+                       /* packet is in DIX format  */
+                       ip_hdr = (u8 *)(datap + 1);
+               } else {
+                       /* packet is in 802.3 format */
+                       llc_hdr = (struct ath6kl_llc_snap_hdr *)
+                                                       (datap + 1);
+                       ether_type = be16_to_cpu(llc_hdr->eth_type);
+                       ip_hdr = (u8 *)(llc_hdr + 1);
+               }
+
+               if (ether_type == IP_ETHERTYPE)
+                       up = ath6kl_wmi_determine_user_priority(
+                                                       ip_hdr, 0);
+       }
+
+       traffic_class = ath6kl_wmi_get_traffic_class(up);
+
+       if ((conn->apsd_info & (1 << traffic_class)) == 0)
+               return false;
+
+       /* Queue the frames if the STA is sleeping */
+       spin_lock_bh(&conn->psq_lock);
+       is_apsdq_empty = skb_queue_empty(&conn->apsdq);
+       skb_queue_tail(&conn->apsdq, skb);
+       spin_unlock_bh(&conn->psq_lock);
+
+       /*
+        * If this is the first pkt getting queued
+        * for this STA, update the PVB for this STA
+        */
+       if (is_apsdq_empty) {
+               ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi,
+                               vif->fw_vif_idx,
+                               conn->aid, 1, 0);
+       }
+       *flags |= WMI_DATA_HDR_FLAGS_UAPSD;
+
+       return true;
+}
+
+static bool ath6kl_process_psq(struct ath6kl_sta *conn,
+                               struct ath6kl_vif *vif,
+                               struct sk_buff *skb,
+                               u32 *flags)
+{
+       bool is_psq_empty = false;
+       struct ath6kl *ar = vif->ar;
+
+       if (conn->sta_flags & STA_PS_POLLED) {
+               spin_lock_bh(&conn->psq_lock);
+               if (!skb_queue_empty(&conn->psq))
+                       *flags |= WMI_DATA_HDR_FLAGS_MORE;
+               spin_unlock_bh(&conn->psq_lock);
+               return false;
+       }
+
+       /* Queue the frames if the STA is sleeping */
+       spin_lock_bh(&conn->psq_lock);
+       is_psq_empty = skb_queue_empty(&conn->psq);
+       skb_queue_tail(&conn->psq, skb);
+       spin_unlock_bh(&conn->psq_lock);
+
+       /*
+        * If this is the first pkt getting queued
+        * for this STA, update the PVB for this
+        * STA.
+        */
+       if (is_psq_empty)
+               ath6kl_wmi_set_pvb_cmd(ar->wmi,
+                                      vif->fw_vif_idx,
+                                      conn->aid, 1);
+       return true;
+}
+
 static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb,
-                               bool *more_data)
+                               u32 *flags)
 {
        struct ethhdr *datap = (struct ethhdr *) skb->data;
        struct ath6kl_sta *conn = NULL;
-       bool ps_queued = false, is_psq_empty = false;
+       bool ps_queued = false;
        struct ath6kl *ar = vif->ar;
 
        if (is_multicast_ether_addr(datap->h_dest)) {
@@ -128,7 +251,7 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb,
                                 */
                                spin_lock_bh(&ar->mcastpsq_lock);
                                if (!skb_queue_empty(&ar->mcastpsq))
-                                       *more_data = true;
+                                       *flags |= WMI_DATA_HDR_FLAGS_MORE;
                                spin_unlock_bh(&ar->mcastpsq_lock);
                        }
                }
@@ -142,37 +265,13 @@ static bool ath6kl_powersave_ap(struct ath6kl_vif *vif, struct sk_buff *skb,
                }
 
                if (conn->sta_flags & STA_PS_SLEEP) {
-                       if (!(conn->sta_flags & STA_PS_POLLED)) {
-                               /* Queue the frames if the STA is sleeping */
-                               spin_lock_bh(&conn->psq_lock);
-                               is_psq_empty = skb_queue_empty(&conn->psq);
-                               skb_queue_tail(&conn->psq, skb);
-                               spin_unlock_bh(&conn->psq_lock);
-
-                               /*
-                                * If this is the first pkt getting queued
-                                * for this STA, update the PVB for this
-                                * STA.
-                                */
-                               if (is_psq_empty)
-                                       ath6kl_wmi_set_pvb_cmd(ar->wmi,
-                                                              vif->fw_vif_idx,
-                                                              conn->aid, 1);
-
-                               ps_queued = true;
-                       } else {
-                               /*
-                                * This tx is because of a PsPoll.
-                                * Determine if MoreData bit has to be set.
-                                */
-                               spin_lock_bh(&conn->psq_lock);
-                               if (!skb_queue_empty(&conn->psq))
-                                       *more_data = true;
-                               spin_unlock_bh(&conn->psq_lock);
-                       }
+                       ps_queued = ath6kl_process_uapsdq(conn,
+                                               vif, skb, flags);
+                       if (!(*flags & WMI_DATA_HDR_FLAGS_UAPSD))
+                               ps_queued = ath6kl_process_psq(conn,
+                                               vif, skb, flags);
                }
        }
-
        return ps_queued;
 }
 
@@ -242,8 +341,13 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
        u32 map_no = 0;
        u16 htc_tag = ATH6KL_DATA_PKT_TAG;
        u8 ac = 99 ; /* initialize to unmapped ac */
-       bool chk_adhoc_ps_mapping = false, more_data = false;
+       bool chk_adhoc_ps_mapping = false;
        int ret;
+       struct wmi_tx_meta_v2 meta_v2;
+       void *meta;
+       u8 csum_start = 0, csum_dest = 0, csum = skb->ip_summed;
+       u8 meta_ver = 0;
+       u32 flags = 0;
 
        ath6kl_dbg(ATH6KL_DBG_WLAN_TX,
                   "%s: skb=0x%p, data=0x%p, len=0x%x\n", __func__,
@@ -260,11 +364,19 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
 
        /* AP mode Power saving processing */
        if (vif->nw_type == AP_NETWORK) {
-               if (ath6kl_powersave_ap(vif, skb, &more_data))
+               if (ath6kl_powersave_ap(vif, skb, &flags))
                        return 0;
        }
 
        if (test_bit(WMI_ENABLED, &ar->flag)) {
+               if ((dev->features & NETIF_F_IP_CSUM) &&
+                               (csum == CHECKSUM_PARTIAL)) {
+                       csum_start = skb->csum_start -
+                                       (skb_network_header(skb) - skb->head) +
+                                       sizeof(struct ath6kl_llc_snap_hdr);
+                       csum_dest = skb->csum_offset + csum_start;
+               }
+
                if (skb_headroom(skb) < dev->needed_headroom) {
                        struct sk_buff *tmp_skb = skb;
 
@@ -281,10 +393,28 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
                        goto fail_tx;
                }
 
-               if (ath6kl_wmi_data_hdr_add(ar->wmi, skb, DATA_MSGTYPE,
-                                           more_data, 0, 0, NULL,
-                                           vif->fw_vif_idx)) {
-                       ath6kl_err("wmi_data_hdr_add failed\n");
+               if ((dev->features & NETIF_F_IP_CSUM) &&
+                               (csum == CHECKSUM_PARTIAL)) {
+                       meta_v2.csum_start = csum_start;
+                       meta_v2.csum_dest = csum_dest;
+
+                       /* instruct target to calculate checksum */
+                       meta_v2.csum_flags = WMI_META_V2_FLAG_CSUM_OFFLOAD;
+                       meta_ver = WMI_META_VERSION_2;
+                       meta = &meta_v2;
+               } else {
+                       meta_ver = 0;
+                       meta = NULL;
+               }
+
+               ret = ath6kl_wmi_data_hdr_add(ar->wmi, skb,
+                               DATA_MSGTYPE, flags, 0,
+                               meta_ver,
+                               meta, vif->fw_vif_idx);
+
+               if (ret) {
+                       ath6kl_warn("failed to add wmi data header:%d\n"
+                               , ret);
                        goto fail_tx;
                }
 
@@ -449,9 +579,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
                 * WMI queue with too many commands the only exception to
                 * this is during testing using endpointping.
                 */
-               spin_lock_bh(&ar->lock);
                set_bit(WMI_CTRL_EP_FULL, &ar->flag);
-               spin_unlock_bh(&ar->lock);
                ath6kl_err("wmi ctrl ep is full\n");
                return action;
        }
@@ -479,9 +607,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
                    action != HTC_SEND_FULL_DROP) {
                        spin_unlock_bh(&ar->list_lock);
 
-                       spin_lock_bh(&vif->if_lock);
                        set_bit(NETQ_STOPPED, &vif->flags);
-                       spin_unlock_bh(&vif->if_lock);
                        netif_stop_queue(vif->ndev);
 
                        return action;
@@ -710,10 +836,12 @@ static struct sk_buff *aggr_get_free_skb(struct aggr_info *p_aggr)
 {
        struct sk_buff *skb = NULL;
 
-       if (skb_queue_len(&p_aggr->free_q) < (AGGR_NUM_OF_FREE_NETBUFS >> 2))
-               ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS);
+       if (skb_queue_len(&p_aggr->rx_amsdu_freeq) <
+           (AGGR_NUM_OF_FREE_NETBUFS >> 2))
+               ath6kl_alloc_netbufs(&p_aggr->rx_amsdu_freeq,
+                                    AGGR_NUM_OF_FREE_NETBUFS);
 
-       skb = skb_dequeue(&p_aggr->free_q);
+       skb = skb_dequeue(&p_aggr->rx_amsdu_freeq);
 
        return skb;
 }
@@ -881,7 +1009,7 @@ static void aggr_slice_amsdu(struct aggr_info *p_aggr,
        dev_kfree_skb(skb);
 }
 
-static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid,
+static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
                            u16 seq_no, u8 order)
 {
        struct sk_buff *skb;
@@ -890,11 +1018,8 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid,
        u16 idx, idx_end, seq_end;
        struct rxtid_stats *stats;
 
-       if (!p_aggr)
-               return;
-
-       rxtid = &p_aggr->rx_tid[tid];
-       stats = &p_aggr->stat[tid];
+       rxtid = &agg_conn->rx_tid[tid];
+       stats = &agg_conn->stat[tid];
 
        idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
 
@@ -923,7 +1048,8 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid,
 
                if (node->skb) {
                        if (node->is_amsdu)
-                               aggr_slice_amsdu(p_aggr, rxtid, node->skb);
+                               aggr_slice_amsdu(agg_conn->aggr_info, rxtid,
+                                                node->skb);
                        else
                                skb_queue_tail(&rxtid->q, node->skb);
                        node->skb = NULL;
@@ -939,10 +1065,10 @@ static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid,
        stats->num_delivered += skb_queue_len(&rxtid->q);
 
        while ((skb = skb_dequeue(&rxtid->q)))
-               ath6kl_deliver_frames_to_nw_stack(p_aggr->dev, skb);
+               ath6kl_deliver_frames_to_nw_stack(agg_conn->dev, skb);
 }
 
-static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
+static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
                                  u16 seq_no,
                                  bool is_amsdu, struct sk_buff *frame)
 {
@@ -954,18 +1080,18 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
        bool is_queued = false;
        u16 extended_end;
 
-       rxtid = &agg_info->rx_tid[tid];
-       stats = &agg_info->stat[tid];
+       rxtid = &agg_conn->rx_tid[tid];
+       stats = &agg_conn->stat[tid];
 
        stats->num_into_aggr++;
 
        if (!rxtid->aggr) {
                if (is_amsdu) {
-                       aggr_slice_amsdu(agg_info, rxtid, frame);
+                       aggr_slice_amsdu(agg_conn->aggr_info, rxtid, frame);
                        is_queued = true;
                        stats->num_amsdu++;
                        while ((skb = skb_dequeue(&rxtid->q)))
-                               ath6kl_deliver_frames_to_nw_stack(agg_info->dev,
+                               ath6kl_deliver_frames_to_nw_stack(agg_conn->dev,
                                                                  skb);
                }
                return is_queued;
@@ -985,7 +1111,7 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
                     (cur < end || cur > extended_end)) ||
                    ((end > extended_end) && (cur > extended_end) &&
                     (cur < end))) {
-                       aggr_deque_frms(agg_info, tid, 0, 0);
+                       aggr_deque_frms(agg_conn, tid, 0, 0);
                        if (cur >= rxtid->hold_q_sz - 1)
                                rxtid->seq_next = cur - (rxtid->hold_q_sz - 1);
                        else
@@ -1002,7 +1128,7 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
                                st = ATH6KL_MAX_SEQ_NO -
                                        (rxtid->hold_q_sz - 2 - cur);
 
-                       aggr_deque_frms(agg_info, tid, st, 0);
+                       aggr_deque_frms(agg_conn, tid, st, 0);
                }
 
                stats->num_oow++;
@@ -1041,9 +1167,9 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
 
        spin_unlock_bh(&rxtid->lock);
 
-       aggr_deque_frms(agg_info, tid, 0, 1);
+       aggr_deque_frms(agg_conn, tid, 0, 1);
 
-       if (agg_info->timer_scheduled)
+       if (agg_conn->timer_scheduled)
                rxtid->progress = true;
        else
                for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
@@ -1054,8 +1180,8 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
                                 * the frame doesn't remain stuck
                                 * forever.
                                 */
-                               agg_info->timer_scheduled = true;
-                               mod_timer(&agg_info->timer,
+                               agg_conn->timer_scheduled = true;
+                               mod_timer(&agg_conn->timer,
                                          (jiffies +
                                           HZ * (AGGR_RX_TIMEOUT) / 1000));
                                rxtid->progress = false;
@@ -1067,6 +1193,76 @@ static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid,
        return is_queued;
 }
 
+static void ath6kl_uapsd_trigger_frame_rx(struct ath6kl_vif *vif,
+                                                struct ath6kl_sta *conn)
+{
+       struct ath6kl *ar = vif->ar;
+       bool is_apsdq_empty, is_apsdq_empty_at_start;
+       u32 num_frames_to_deliver, flags;
+       struct sk_buff *skb = NULL;
+
+       /*
+        * If the APSD q for this STA is not empty, dequeue and
+        * send a pkt from the head of the q. Also update the
+        * More data bit in the WMI_DATA_HDR if there are
+        * more pkts for this STA in the APSD q.
+        * If there are no more pkts for this STA,
+        * update the APSD bitmap for this STA.
+        */
+
+       num_frames_to_deliver = (conn->apsd_info >> ATH6KL_APSD_NUM_OF_AC) &
+                                                   ATH6KL_APSD_FRAME_MASK;
+       /*
+        * Number of frames to send in a service period is
+        * indicated by the station
+        * in the QOS_INFO of the association request
+        * If it is zero, send all frames
+        */
+       if (!num_frames_to_deliver)
+               num_frames_to_deliver = ATH6KL_APSD_ALL_FRAME;
+
+       spin_lock_bh(&conn->psq_lock);
+       is_apsdq_empty = skb_queue_empty(&conn->apsdq);
+       spin_unlock_bh(&conn->psq_lock);
+       is_apsdq_empty_at_start = is_apsdq_empty;
+
+       while ((!is_apsdq_empty) && (num_frames_to_deliver)) {
+
+               spin_lock_bh(&conn->psq_lock);
+               skb = skb_dequeue(&conn->apsdq);
+               is_apsdq_empty = skb_queue_empty(&conn->apsdq);
+               spin_unlock_bh(&conn->psq_lock);
+
+               /*
+                * Set the STA flag to Trigger delivery,
+                * so that the frame will go out
+                */
+               conn->sta_flags |= STA_PS_APSD_TRIGGER;
+               num_frames_to_deliver--;
+
+               /* Last frame in the service period, set EOSP or queue empty */
+               if ((is_apsdq_empty) || (!num_frames_to_deliver))
+                       conn->sta_flags |= STA_PS_APSD_EOSP;
+
+               ath6kl_data_tx(skb, vif->ndev);
+               conn->sta_flags &= ~(STA_PS_APSD_TRIGGER);
+               conn->sta_flags &= ~(STA_PS_APSD_EOSP);
+       }
+
+       if (is_apsdq_empty) {
+               if (is_apsdq_empty_at_start)
+                       flags = WMI_AP_APSD_NO_DELIVERY_FRAMES;
+               else
+                       flags = 0;
+
+               ath6kl_wmi_set_apsd_bfrd_traf(ar->wmi,
+                               vif->fw_vif_idx,
+                               conn->aid, 0, flags);
+       }
+
+       return;
+}
+
 void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
 {
        struct ath6kl *ar = target->dev->ar;
@@ -1078,10 +1274,12 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
        int status = packet->status;
        enum htc_endpoint_id ept = packet->endpoint;
        bool is_amsdu, prev_ps, ps_state = false;
+       bool trig_state = false;
        struct ath6kl_sta *conn = NULL;
        struct sk_buff *skb1 = NULL;
        struct ethhdr *datap = NULL;
        struct ath6kl_vif *vif;
+       struct aggr_info_conn *aggr_conn;
        u16 seq_no, offset;
        u8 tid, if_idx;
 
@@ -1171,6 +1369,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
                              WMI_DATA_HDR_PS_MASK);
 
                offset = sizeof(struct wmi_data_hdr);
+               trig_state = !!(le16_to_cpu(dhdr->info3) & WMI_DATA_HDR_TRIG);
 
                switch (meta_type) {
                case 0:
@@ -1209,18 +1408,36 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
                else
                        conn->sta_flags &= ~STA_PS_SLEEP;
 
+               /* Accept trigger only when the station is in sleep */
+               if ((conn->sta_flags & STA_PS_SLEEP) && trig_state)
+                       ath6kl_uapsd_trigger_frame_rx(vif, conn);
+
                if (prev_ps ^ !!(conn->sta_flags & STA_PS_SLEEP)) {
                        if (!(conn->sta_flags & STA_PS_SLEEP)) {
                                struct sk_buff *skbuff = NULL;
+                               bool is_apsdq_empty;
 
                                spin_lock_bh(&conn->psq_lock);
-                               while ((skbuff = skb_dequeue(&conn->psq))
-                                      != NULL) {
+                               while ((skbuff = skb_dequeue(&conn->psq))) {
+                                       spin_unlock_bh(&conn->psq_lock);
+                                       ath6kl_data_tx(skbuff, vif->ndev);
+                                       spin_lock_bh(&conn->psq_lock);
+                               }
+
+                               is_apsdq_empty = skb_queue_empty(&conn->apsdq);
+                               while ((skbuff = skb_dequeue(&conn->apsdq))) {
                                        spin_unlock_bh(&conn->psq_lock);
                                        ath6kl_data_tx(skbuff, vif->ndev);
                                        spin_lock_bh(&conn->psq_lock);
                                }
                                spin_unlock_bh(&conn->psq_lock);
+
+                               if (!is_apsdq_empty)
+                                       ath6kl_wmi_set_apsd_bfrd_traf(
+                                                       ar->wmi,
+                                                       vif->fw_vif_idx,
+                                                       conn->aid, 0, 0);
+
                                /* Clear the PVB for this STA */
                                ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx,
                                                       conn->aid, 0);
@@ -1314,11 +1531,21 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
 
        datap = (struct ethhdr *) skb->data;
 
-       if (is_unicast_ether_addr(datap->h_dest) &&
-           aggr_process_recv_frm(vif->aggr_cntxt, tid, seq_no,
-                                 is_amsdu, skb))
-               /* aggregation code will handle the skb */
-               return;
+       if (is_unicast_ether_addr(datap->h_dest)) {
+               if (vif->nw_type == AP_NETWORK) {
+                       conn = ath6kl_find_sta(vif, datap->h_source);
+                       if (!conn)
+                               return;
+                       aggr_conn = conn->aggr_conn;
+               } else
+                       aggr_conn = vif->aggr_cntxt->aggr_conn;
+
+               if (aggr_process_recv_frm(aggr_conn, tid, seq_no,
+                   is_amsdu, skb)) {
+                       /* aggregation code will handle the skb */
+                       return;
+               }
+       }
 
        ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb);
 }
@@ -1326,13 +1553,13 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
 static void aggr_timeout(unsigned long arg)
 {
        u8 i, j;
-       struct aggr_info *p_aggr = (struct aggr_info *) arg;
+       struct aggr_info_conn *aggr_conn = (struct aggr_info_conn *) arg;
        struct rxtid *rxtid;
        struct rxtid_stats *stats;
 
        for (i = 0; i < NUM_OF_TIDS; i++) {
-               rxtid = &p_aggr->rx_tid[i];
-               stats = &p_aggr->stat[i];
+               rxtid = &aggr_conn->rx_tid[i];
+               stats = &aggr_conn->stat[i];
 
                if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress)
                        continue;
@@ -1343,18 +1570,18 @@ static void aggr_timeout(unsigned long arg)
                           rxtid->seq_next,
                           ((rxtid->seq_next + rxtid->hold_q_sz-1) &
                            ATH6KL_MAX_SEQ_NO));
-               aggr_deque_frms(p_aggr, i, 0, 0);
+               aggr_deque_frms(aggr_conn, i, 0, 0);
        }
 
-       p_aggr->timer_scheduled = false;
+       aggr_conn->timer_scheduled = false;
 
        for (i = 0; i < NUM_OF_TIDS; i++) {
-               rxtid = &p_aggr->rx_tid[i];
+               rxtid = &aggr_conn->rx_tid[i];
 
                if (rxtid->aggr && rxtid->hold_q) {
                        for (j = 0; j < rxtid->hold_q_sz; j++) {
                                if (rxtid->hold_q[j].skb) {
-                                       p_aggr->timer_scheduled = true;
+                                       aggr_conn->timer_scheduled = true;
                                        rxtid->timer_mon = true;
                                        rxtid->progress = false;
                                        break;
@@ -1366,24 +1593,24 @@ static void aggr_timeout(unsigned long arg)
                }
        }
 
-       if (p_aggr->timer_scheduled)
-               mod_timer(&p_aggr->timer,
+       if (aggr_conn->timer_scheduled)
+               mod_timer(&aggr_conn->timer,
                          jiffies + msecs_to_jiffies(AGGR_RX_TIMEOUT));
 }
 
-static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid)
+static void aggr_delete_tid_state(struct aggr_info_conn *aggr_conn, u8 tid)
 {
        struct rxtid *rxtid;
        struct rxtid_stats *stats;
 
-       if (!p_aggr || tid >= NUM_OF_TIDS)
+       if (!aggr_conn || tid >= NUM_OF_TIDS)
                return;
 
-       rxtid = &p_aggr->rx_tid[tid];
-       stats = &p_aggr->stat[tid];
+       rxtid = &aggr_conn->rx_tid[tid];
+       stats = &aggr_conn->stat[tid];
 
        if (rxtid->aggr)
-               aggr_deque_frms(p_aggr, tid, 0, 0);
+               aggr_deque_frms(aggr_conn, tid, 0, 0);
 
        rxtid->aggr = false;
        rxtid->progress = false;
@@ -1398,26 +1625,40 @@ static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid)
        memset(stats, 0, sizeof(struct rxtid_stats));
 }
 
-void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid, u16 seq_no,
+void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no,
                             u8 win_sz)
 {
-       struct aggr_info *p_aggr = vif->aggr_cntxt;
+       struct ath6kl_sta *sta;
+       struct aggr_info_conn *aggr_conn = NULL;
        struct rxtid *rxtid;
        struct rxtid_stats *stats;
        u16 hold_q_size;
+       u8 tid, aid;
 
-       if (!p_aggr)
+       if (vif->nw_type == AP_NETWORK) {
+               aid = ath6kl_get_aid(tid_mux);
+               sta = ath6kl_find_sta_by_aid(vif->ar, aid);
+               if (sta)
+                       aggr_conn = sta->aggr_conn;
+       } else
+               aggr_conn = vif->aggr_cntxt->aggr_conn;
+
+       if (!aggr_conn)
+               return;
+
+       tid = ath6kl_get_tid(tid_mux);
+       if (tid >= NUM_OF_TIDS)
                return;
 
-       rxtid = &p_aggr->rx_tid[tid];
-       stats = &p_aggr->stat[tid];
+       rxtid = &aggr_conn->rx_tid[tid];
+       stats = &aggr_conn->stat[tid];
 
        if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX)
                ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",
                           __func__, win_sz, tid);
 
        if (rxtid->aggr)
-               aggr_delete_tid_state(p_aggr, tid);
+               aggr_delete_tid_state(aggr_conn, tid);
 
        rxtid->seq_next = seq_no;
        hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q);
@@ -1433,31 +1674,23 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid, u16 seq_no,
        rxtid->aggr = true;
 }
 
-struct aggr_info *aggr_init(struct net_device *dev)
+void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info,
+                   struct aggr_info_conn *aggr_conn)
 {
-       struct aggr_info *p_aggr = NULL;
        struct rxtid *rxtid;
        u8 i;
 
-       p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL);
-       if (!p_aggr) {
-               ath6kl_err("failed to alloc memory for aggr_node\n");
-               return NULL;
-       }
-
-       p_aggr->aggr_sz = AGGR_SZ_DEFAULT;
-       p_aggr->dev = dev;
-       init_timer(&p_aggr->timer);
-       p_aggr->timer.function = aggr_timeout;
-       p_aggr->timer.data = (unsigned long) p_aggr;
+       aggr_conn->aggr_sz = AGGR_SZ_DEFAULT;
+       aggr_conn->dev = vif->ndev;
+       init_timer(&aggr_conn->timer);
+       aggr_conn->timer.function = aggr_timeout;
+       aggr_conn->timer.data = (unsigned long) aggr_conn;
+       aggr_conn->aggr_info = aggr_info;
 
-       p_aggr->timer_scheduled = false;
-       skb_queue_head_init(&p_aggr->free_q);
-
-       ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS);
+       aggr_conn->timer_scheduled = false;
 
        for (i = 0; i < NUM_OF_TIDS; i++) {
-               rxtid = &p_aggr->rx_tid[i];
+               rxtid = &aggr_conn->rx_tid[i];
                rxtid->aggr = false;
                rxtid->progress = false;
                rxtid->timer_mon = false;
@@ -1465,29 +1698,75 @@ struct aggr_info *aggr_init(struct net_device *dev)
                spin_lock_init(&rxtid->lock);
        }
 
+}
+
+struct aggr_info *aggr_init(struct ath6kl_vif *vif)
+{
+       struct aggr_info *p_aggr = NULL;
+
+       p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL);
+       if (!p_aggr) {
+               ath6kl_err("failed to alloc memory for aggr_node\n");
+               return NULL;
+       }
+
+       p_aggr->aggr_conn = kzalloc(sizeof(struct aggr_info_conn), GFP_KERNEL);
+       if (!p_aggr->aggr_conn) {
+               ath6kl_err("failed to alloc memory for connection specific aggr info\n");
+               kfree(p_aggr);
+               return NULL;
+       }
+
+       aggr_conn_init(vif, p_aggr, p_aggr->aggr_conn);
+
+       skb_queue_head_init(&p_aggr->rx_amsdu_freeq);
+       ath6kl_alloc_netbufs(&p_aggr->rx_amsdu_freeq, AGGR_NUM_OF_FREE_NETBUFS);
+
        return p_aggr;
 }
 
-void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid)
+void aggr_recv_delba_req_evt(struct ath6kl_vif *vif, u8 tid_mux)
 {
-       struct aggr_info *p_aggr = vif->aggr_cntxt;
+       struct ath6kl_sta *sta;
        struct rxtid *rxtid;
+       struct aggr_info_conn *aggr_conn = NULL;
+       u8 tid, aid;
+
+       if (vif->nw_type == AP_NETWORK) {
+               aid = ath6kl_get_aid(tid_mux);
+               sta = ath6kl_find_sta_by_aid(vif->ar, aid);
+               if (sta)
+                       aggr_conn = sta->aggr_conn;
+       } else
+               aggr_conn = vif->aggr_cntxt->aggr_conn;
+
+       if (!aggr_conn)
+               return;
 
-       if (!p_aggr)
+       tid = ath6kl_get_tid(tid_mux);
+       if (tid >= NUM_OF_TIDS)
                return;
 
-       rxtid = &p_aggr->rx_tid[tid];
+       rxtid = &aggr_conn->rx_tid[tid];
 
        if (rxtid->aggr)
-               aggr_delete_tid_state(p_aggr, tid);
+               aggr_delete_tid_state(aggr_conn, tid);
 }
 
-void aggr_reset_state(struct aggr_info *aggr_info)
+void aggr_reset_state(struct aggr_info_conn *aggr_conn)
 {
        u8 tid;
 
+       if (!aggr_conn)
+               return;
+
+       if (aggr_conn->timer_scheduled) {
+               del_timer(&aggr_conn->timer);
+               aggr_conn->timer_scheduled = false;
+       }
+
        for (tid = 0; tid < NUM_OF_TIDS; tid++)
-               aggr_delete_tid_state(aggr_info, tid);
+               aggr_delete_tid_state(aggr_conn, tid);
 }
 
 /* clean up our amsdu buffer list */
@@ -1514,28 +1793,11 @@ void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar)
 
 void aggr_module_destroy(struct aggr_info *aggr_info)
 {
-       struct rxtid *rxtid;
-       u8 i, k;
-
        if (!aggr_info)
                return;
 
-       if (aggr_info->timer_scheduled) {
-               del_timer(&aggr_info->timer);
-               aggr_info->timer_scheduled = false;
-       }
-
-       for (i = 0; i < NUM_OF_TIDS; i++) {
-               rxtid = &aggr_info->rx_tid[i];
-               if (rxtid->hold_q) {
-                       for (k = 0; k < rxtid->hold_q_sz; k++)
-                               dev_kfree_skb(rxtid->hold_q[k].skb);
-                       kfree(rxtid->hold_q);
-               }
-
-               skb_queue_purge(&rxtid->q);
-       }
-
-       skb_queue_purge(&aggr_info->free_q);
+       aggr_reset_state(aggr_info->aggr_conn);
+       skb_queue_purge(&aggr_info->rx_amsdu_freeq);
+       kfree(aggr_info->aggr_conn);
        kfree(aggr_info);
 }
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
new file mode 100644 (file)
index 0000000..c72567c
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2007-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "debug.h"
+#include "core.h"
+
+/* usb device object */
+struct ath6kl_usb {
+       struct usb_device *udev;
+       struct usb_interface *interface;
+       u8 *diag_cmd_buffer;
+       u8 *diag_resp_buffer;
+       struct ath6kl *ar;
+};
+
+/* diagnostic command defnitions */
+#define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD        1
+#define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP       2
+#define ATH6KL_USB_CONTROL_REQ_DIAG_CMD            3
+#define ATH6KL_USB_CONTROL_REQ_DIAG_RESP           4
+
+#define ATH6KL_USB_CTRL_DIAG_CC_READ               0
+#define ATH6KL_USB_CTRL_DIAG_CC_WRITE              1
+
+struct ath6kl_usb_ctrl_diag_cmd_write {
+       __le32 cmd;
+       __le32 address;
+       __le32 value;
+       __le32 _pad[1];
+} __packed;
+
+struct ath6kl_usb_ctrl_diag_cmd_read {
+       __le32 cmd;
+       __le32 address;
+} __packed;
+
+struct ath6kl_usb_ctrl_diag_resp_read {
+       __le32 value;
+} __packed;
+
+#define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write))
+#define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read))
+
+static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb)
+{
+       usb_set_intfdata(ar_usb->interface, NULL);
+
+       kfree(ar_usb->diag_cmd_buffer);
+       kfree(ar_usb->diag_resp_buffer);
+
+       kfree(ar_usb);
+}
+
+static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
+{
+       struct ath6kl_usb *ar_usb = NULL;
+       struct usb_device *dev = interface_to_usbdev(interface);
+       int status = 0;
+
+       ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL);
+       if (ar_usb == NULL)
+               goto fail_ath6kl_usb_create;
+
+       memset(ar_usb, 0, sizeof(struct ath6kl_usb));
+       usb_set_intfdata(interface, ar_usb);
+       ar_usb->udev = dev;
+       ar_usb->interface = interface;
+
+       ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL);
+       if (ar_usb->diag_cmd_buffer == NULL) {
+               status = -ENOMEM;
+               goto fail_ath6kl_usb_create;
+       }
+
+       ar_usb->diag_resp_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_RESP,
+                                          GFP_KERNEL);
+       if (ar_usb->diag_resp_buffer == NULL) {
+               status = -ENOMEM;
+               goto fail_ath6kl_usb_create;
+       }
+
+fail_ath6kl_usb_create:
+       if (status != 0) {
+               ath6kl_usb_destroy(ar_usb);
+               ar_usb = NULL;
+       }
+