Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorWey-Yi Guy <wey-yi.w.guy@intel.com>
Fri, 2 Dec 2011 16:20:01 +0000 (08:20 -0800)
committerWey-Yi Guy <wey-yi.w.guy@intel.com>
Fri, 2 Dec 2011 16:20:01 +0000 (08:20 -0800)
112 files changed:
drivers/net/wireless/ath/ath5k/ahb.c
drivers/net/wireless/ath/ath5k/ani.c
drivers/net/wireless/ath/ath5k/ani.h
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/attach.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/caps.c
drivers/net/wireless/ath/ath5k/desc.c
drivers/net/wireless/ath/ath5k/desc.h
drivers/net/wireless/ath/ath5k/dma.c
drivers/net/wireless/ath/ath5k/gpio.c
drivers/net/wireless/ath/ath5k/initvals.c
drivers/net/wireless/ath/ath5k/pci.c
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/qcu.c
drivers/net/wireless/ath/ath5k/reg.h
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath5k/rfbuffer.h
drivers/net/wireless/ath/ath5k/rfgain.h
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_mci.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_mci.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/btcoex.h
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/mci.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h [deleted file]
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_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/dma.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/main.h
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/prism54/isl_ioctl.h
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/wl1251/spi.c
drivers/net/wireless/wl12xx/spi.c
drivers/nfc/pn533.c
include/linux/nl80211.h
include/net/cfg80211.h
net/mac80211/Kconfig
net/mac80211/Makefile
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/debugfs_netdev.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ht.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/offchannel.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mac80211/wme.h
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/nfc.h
net/nfc/rawsock.c
net/rfkill/rfkill-gpio.c
net/rfkill/rfkill-regulator.c
net/wireless/mesh.c
net/wireless/nl80211.c

index e5be7e7..ee7ea57 100644 (file)
@@ -166,7 +166,9 @@ static int ath_ahb_probe(struct platform_device *pdev)
                if (to_platform_device(ah->dev)->id == 0 &&
                    (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) ==
                     (BD_WLAN1 | BD_WLAN0))
-                       __set_bit(ATH_STAT_2G_DISABLED, ah->status);
+                       ah->ah_capabilities.cap_needs_2GHz_ovr = true;
+               else
+                       ah->ah_capabilities.cap_needs_2GHz_ovr = false;
        }
 
        ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
index bea90e6..bf67416 100644 (file)
  * or reducing sensitivity as necessary.
  *
  * The parameters are:
+ *
  *   - "noise immunity"
+ *
  *   - "spur immunity"
+ *
  *   - "firstep level"
+ *
  *   - "OFDM weak signal detection"
+ *
  *   - "CCK weak signal detection"
  *
  * Basically we look at the amount of ODFM and CCK timing errors we get and then
  * raise or lower immunity accordingly by setting one or more of these
  * parameters.
+ *
  * Newer chipsets have PHY error counters in hardware which will generate a MIB
  * interrupt when they overflow. Older hardware has too enable PHY error frames
  * by setting a RX flag and then count every single PHY error. When a specified
  */
 
 
-/*** ANI parameter control ***/
+/***********************\
+* ANI parameter control *
+\***********************/
 
 /**
  * ath5k_ani_set_noise_immunity_level() - Set noise immunity level
- *
+ * @ah: The &struct ath5k_hw
  * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL
  */
 void
@@ -91,12 +99,11 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
        ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level);
 }
 
-
 /**
  * ath5k_ani_set_spur_immunity_level() - Set spur immunity level
- *
+ * @ah: The &struct ath5k_hw
  * @level: level between 0 and @max_spur_level (the maximum level is dependent
- *     on the chip revision).
+ * on the chip revision).
  */
 void
 ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
@@ -117,10 +124,9 @@ ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
        ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level);
 }
 
-
 /**
  * ath5k_ani_set_firstep_level() - Set "firstep" level
- *
+ * @ah: The &struct ath5k_hw
  * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL
  */
 void
@@ -140,11 +146,9 @@ ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level)
        ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level);
 }
 
-
 /**
- * ath5k_ani_set_ofdm_weak_signal_detection() - Control OFDM weak signal
- *                                             detection
- *
+ * ath5k_ani_set_ofdm_weak_signal_detection() - Set OFDM weak signal detection
+ * @ah: The &struct ath5k_hw
  * @on: turn on or off
  */
 void
@@ -182,10 +186,9 @@ ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on)
                          on ? "on" : "off");
 }
 
-
 /**
- * ath5k_ani_set_cck_weak_signal_detection() - control CCK weak signal detection
- *
+ * ath5k_ani_set_cck_weak_signal_detection() - Set CCK weak signal detection
+ * @ah: The &struct ath5k_hw
  * @on: turn on or off
  */
 void
@@ -200,13 +203,16 @@ ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on)
 }
 
 
-/*** ANI algorithm ***/
+/***************\
+* ANI algorithm *
+\***************/
 
 /**
  * ath5k_ani_raise_immunity() - Increase noise immunity
- *
+ * @ah: The &struct ath5k_hw
+ * @as: The &struct ath5k_ani_state
  * @ofdm_trigger: If this is true we are called because of too many OFDM errors,
- *     the algorithm will tune more parameters then.
+ * the algorithm will tune more parameters then.
  *
  * Try to raise noise immunity (=decrease sensitivity) in several steps
  * depending on the average RSSI of the beacons we received.
@@ -290,9 +296,10 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,
        */
 }
 
-
 /**
  * ath5k_ani_lower_immunity() - Decrease noise immunity
+ * @ah: The &struct ath5k_hw
+ * @as: The &struct ath5k_ani_state
  *
  * Try to lower noise immunity (=increase sensitivity) in several steps
  * depending on the average RSSI of the beacons we received.
@@ -352,9 +359,10 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as)
        }
 }
 
-
 /**
  * ath5k_hw_ani_get_listen_time() - Update counters and return listening time
+ * @ah: The &struct ath5k_hw
+ * @as: The &struct ath5k_ani_state
  *
  * Return an approximation of the time spent "listening" in milliseconds (ms)
  * since the last call of this function.
@@ -379,9 +387,10 @@ ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as)
        return listen;
 }
 
-
 /**
  * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters
+ * @ah: The &struct ath5k_hw
+ * @as: The &struct ath5k_ani_state
  *
  * Clear the PHY error counters as soon as possible, since this might be called
  * from a MIB interrupt and we want to make sure we don't get interrupted again.
@@ -429,14 +438,14 @@ ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah,
        return 1;
 }
 
-
 /**
  * ath5k_ani_period_restart() - Restart ANI period
+ * @as: The &struct ath5k_ani_state
  *
  * Just reset counters, so they are clear for the next "ani period".
  */
 static void
-ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as)
+ath5k_ani_period_restart(struct ath5k_ani_state *as)
 {
        /* keep last values for debugging */
        as->last_ofdm_errors = as->ofdm_errors;
@@ -448,9 +457,9 @@ ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as)
        as->listen_time = 0;
 }
 
-
 /**
  * ath5k_ani_calibration() - The main ANI calibration function
+ * @ah: The &struct ath5k_hw
  *
  * We count OFDM and CCK errors relative to the time where we did not send or
  * receive ("listen" time) and raise or lower immunity accordingly.
@@ -492,7 +501,7 @@ ath5k_ani_calibration(struct ath5k_hw *ah)
                /* too many PHY errors - we have to raise immunity */
                bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false;
                ath5k_ani_raise_immunity(ah, as, ofdm_flag);
-               ath5k_ani_period_restart(ah, as);
+               ath5k_ani_period_restart(as);
 
        } else if (as->listen_time > 5 * ATH5K_ANI_LISTEN_PERIOD) {
                /* If more than 5 (TODO: why 5?) periods have passed and we got
@@ -504,15 +513,18 @@ ath5k_ani_calibration(struct ath5k_hw *ah)
                if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low)
                        ath5k_ani_lower_immunity(ah, as);
 
-               ath5k_ani_period_restart(ah, as);
+               ath5k_ani_period_restart(as);
        }
 }
 
 
-/*** INTERRUPT HANDLER ***/
+/*******************\
+* Interrupt handler *
+\*******************/
 
 /**
  * ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters
+ * @ah: The &struct ath5k_hw
  *
  * Just read & reset the registers quickly, so they don't generate more
  * interrupts, save the counters and schedule the tasklet to decide whether
@@ -549,9 +561,11 @@ ath5k_ani_mib_intr(struct ath5k_hw *ah)
                tasklet_schedule(&ah->ani_tasklet);
 }
 
-
 /**
- * ath5k_ani_phy_error_report() - Used by older HW to report PHY errors
+ * ath5k_ani_phy_error_report - Used by older HW to report PHY errors
+ *
+ * @ah: The &struct ath5k_hw
+ * @phyerr: One of enum ath5k_phy_error_code
  *
  * This is used by hardware without PHY error counters to report PHY errors
  * on a frame-by-frame basis, instead of the interrupt.
@@ -574,10 +588,13 @@ ath5k_ani_phy_error_report(struct ath5k_hw *ah,
 }
 
 
-/*** INIT ***/
+/****************\
+* Initialization *
+\****************/
 
 /**
  * ath5k_enable_phy_err_counters() - Enable PHY error counters
+ * @ah: The &struct ath5k_hw
  *
  * Enable PHY error counters for OFDM and CCK timing errors.
  */
@@ -596,9 +613,9 @@ ath5k_enable_phy_err_counters(struct ath5k_hw *ah)
        ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
 }
 
-
 /**
  * ath5k_disable_phy_err_counters() - Disable PHY error counters
+ * @ah: The &struct ath5k_hw
  *
  * Disable PHY error counters for OFDM and CCK timing errors.
  */
@@ -615,10 +632,10 @@ ath5k_disable_phy_err_counters(struct ath5k_hw *ah)
        ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
 }
 
-
 /**
  * ath5k_ani_init() - Initialize ANI
- * @mode: Which mode to use (auto, manual high, manual low, off)
+ * @ah: The &struct ath5k_hw
+ * @mode: One of enum ath5k_ani_mode
  *
  * Initialize ANI according to mode.
  */
@@ -695,10 +712,18 @@ ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode)
 }
 
 
-/*** DEBUG ***/
+/**************\
+* Debug output *
+\**************/
 
 #ifdef CONFIG_ATH5K_DEBUG
 
+/**
+ * ath5k_ani_print_counters() - Print ANI counters
+ * @ah: The &struct ath5k_hw
+ *
+ * Used for debugging ANI
+ */
 void
 ath5k_ani_print_counters(struct ath5k_hw *ah)
 {
index 7358b6c..21aa355 100644 (file)
@@ -40,13 +40,13 @@ enum ath5k_phy_error_code;
  * enum ath5k_ani_mode - mode for ANI / noise sensitivity
  *
  * @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI
- *     algorithm after it has been on auto mode.
- * ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low,
- *     maximizing sensitivity. ANI will not run.
- * ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high,
- *     minimizing sensitivity. ANI will not run.
- * ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the
- *     amount of OFDM and CCK frame errors (default).
+ *                     algorithm after it has been on auto mode.
+ * @ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low,
+ *                     maximizing sensitivity. ANI will not run.
+ * @ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high,
+ *                     minimizing sensitivity. ANI will not run.
+ * @ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the
+ *                     amount of OFDM and CCK frame errors (default).
  */
 enum ath5k_ani_mode {
        ATH5K_ANI_MODE_OFF              = 0,
@@ -58,8 +58,22 @@ enum ath5k_ani_mode {
 
 /**
  * struct ath5k_ani_state - ANI state and associated counters
- *
- * @max_spur_level: the maximum spur level is chip dependent
+ * @ani_mode: One of enum ath5k_ani_mode
+ * @noise_imm_level: Noise immunity level
+ * @spur_level: Spur immunity level
+ * @firstep_level: FIRstep level
+ * @ofdm_weak_sig: OFDM weak signal detection state (on/off)
+ * @cck_weak_sig: CCK weak signal detection state (on/off)
+ * @max_spur_level: Max spur immunity level (chip specific)
+ * @listen_time: Listen time
+ * @ofdm_errors: OFDM timing error count
+ * @cck_errors: CCK timing error count
+ * @last_cc: The &struct ath_cycle_counters (for stats)
+ * @last_listen: Listen time from previous run (for stats)
+ * @last_ofdm_errors: OFDM timing error count from previous run (for tats)
+ * @last_cck_errors: CCK timing error count from previous run (for stats)
+ * @sum_ofdm_errors: Sum of OFDM timing errors (for stats)
+ * @sum_cck_errors: Sum of all CCK timing errors (for stats)
  */
 struct ath5k_ani_state {
        enum ath5k_ani_mode     ani_mode;
index fecbcd9..e564e58 100644 (file)
 #define AR5K_TUNE_MAX_TXPOWER                  63
 #define AR5K_TUNE_DEFAULT_TXPOWER              25
 #define AR5K_TUNE_TPC_TXPOWER                  false
-#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL    10000   /* 10 sec */
+#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL    60000   /* 60 sec */
+#define        ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT   10000   /* 10 sec */
 #define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI    1000    /* 1 sec */
-#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF     60000   /* 60 sec */
-
 #define ATH5K_TX_COMPLETE_POLL_INT             3000    /* 3 sec */
 
 #define AR5K_INIT_CARR_SENSE_EN                        1
 #define        AR5K_AGC_SETTLING_TURBO                 37
 
 
-/* GENERIC CHIPSET DEFINITIONS */
 
-/* MAC Chips */
+/*****************************\
+* GENERIC CHIPSET DEFINITIONS *
+\*****************************/
+
+/**
+ * enum ath5k_version - MAC Chips
+ * @AR5K_AR5210: AR5210 (Crete)
+ * @AR5K_AR5211: AR5211 (Oahu/Maui)
+ * @AR5K_AR5212: AR5212 (Venice) and newer
+ */
 enum ath5k_version {
        AR5K_AR5210     = 0,
        AR5K_AR5211     = 1,
        AR5K_AR5212     = 2,
 };
 
-/* PHY Chips */
+/**
+ * enum ath5k_radio - PHY Chips
+ * @AR5K_RF5110: RF5110 (Fez)
+ * @AR5K_RF5111: RF5111 (Sombrero)
+ * @AR5K_RF5112: RF2112/5112(A) (Derby/Derby2)
+ * @AR5K_RF2413: RF2413/2414 (Griffin/Griffin-Lite)
+ * @AR5K_RF5413: RF5413/5414/5424 (Eagle/Condor)
+ * @AR5K_RF2316: RF2315/2316 (Cobra SoC)
+ * @AR5K_RF2317: RF2317 (Spider SoC)
+ * @AR5K_RF2425: RF2425/2417 (Swan/Nalla)
+ */
 enum ath5k_radio {
        AR5K_RF5110     = 0,
        AR5K_RF5111     = 1,
@@ -303,11 +320,11 @@ enum ath5k_radio {
 #define AR5K_SREV_AR5213A      0x59 /* Hainan */
 #define AR5K_SREV_AR2413       0x78 /* Griffin lite */
 #define AR5K_SREV_AR2414       0x70 /* Griffin */
-#define AR5K_SREV_AR2315_R6 0x86 /* AP51-Light */
-#define AR5K_SREV_AR2315_R7 0x87 /* AP51-Full */
+#define AR5K_SREV_AR2315_R6    0x86 /* AP51-Light */
+#define AR5K_SREV_AR2315_R7    0x87 /* AP51-Full */
 #define AR5K_SREV_AR5424       0x90 /* Condor */
-#define AR5K_SREV_AR2317_R1 0x90 /* AP61-Light */
-#define AR5K_SREV_AR2317_R2 0x91 /* AP61-Full */
+#define AR5K_SREV_AR2317_R1    0x90 /* AP61-Light */
+#define AR5K_SREV_AR2317_R2    0x91 /* AP61-Full */
 #define AR5K_SREV_AR5413       0xa4 /* Eagle lite */
 #define AR5K_SREV_AR5414       0xa0 /* Eagle */
 #define AR5K_SREV_AR2415       0xb0 /* Talon */
@@ -344,32 +361,40 @@ enum ath5k_radio {
 
 /* TODO add support to mac80211 for vendor-specific rates and modes */
 
-/*
+/**
+ * DOC: Atheros XR
+ *
  * Some of this information is based on Documentation from:
  *
  * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG
  *
- * Modulation for Atheros' eXtended Range - range enhancing extension that is
- * supposed to double the distance an Atheros client device can keep a
- * connection with an Atheros access point. This is achieved by increasing
- * the receiver sensitivity up to, -105dBm, which is about 20dB above what
- * the 802.11 specifications demand. In addition, new (proprietary) data rates
- * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s.
+ * Atheros' eXtended Range - range enhancing extension is a modulation scheme
+ * that is supposed to double the link distance between an Atheros XR-enabled
+ * client device with an Atheros XR-enabled access point. This is achieved
+ * by increasing the receiver sensitivity up to, -105dBm, which is about 20dB
+ * above what the 802.11 specifications demand. In addition, new (proprietary)
+ * data rates are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s.
  *
  * Please note that can you either use XR or TURBO but you cannot use both,
  * they are exclusive.
  *
+ * Also note that we do not plan to support XR mode at least for now. You can
+ * get a mode similar to XR by using 5MHz bwmode.
  */
-#define MODULATION_XR          0x00000200
-/*
- * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a
- * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s
- * signaling rate achieved through the bonding of two 54Mbit/s 802.11g
- * channels. To use this feature your Access Point must also support it.
+
+
+/**
+ * DOC: Atheros SuperAG
+ *
+ * In addition to XR we have another modulation scheme called TURBO mode
+ * that is supposed to provide a throughput transmission speed up to 40Mbit/s
+ * -60Mbit/s at a 108Mbit/s signaling rate achieved through the bonding of two
+ * 54Mbit/s 802.11g channels. To use this feature both ends must support it.
  * There is also a distinction between "static" and "dynamic" turbo modes:
  *
  * - Static: is the dumb version: devices set to this mode stick to it until
  *     the mode is turned off.
+ *
  * - Dynamic: is the intelligent version, the network decides itself if it
  *     is ok to use turbo. As soon as traffic is detected on adjacent channels
  *     (which would get used in turbo mode), or when a non-turbo station joins
@@ -383,24 +408,39 @@ enum ath5k_radio {
  *
  * http://www.pcworld.com/article/id,113428-page,1/article.html
  *
- * The channel bonding seems to be driver specific though. In addition to
- * deciding what channels will be used, these "Turbo" modes are accomplished
- * by also enabling the following features:
+ * The channel bonding seems to be driver specific though.
+ *
+ * In addition to TURBO modes we also have the following features for even
+ * greater speed-up:
  *
  * - Bursting: allows multiple frames to be sent at once, rather than pausing
  *     after each frame. Bursting is a standards-compliant feature that can be
  *     used with any Access Point.
+ *
  * - Fast frames: increases the amount of information that can be sent per
  *     frame, also resulting in a reduction of transmission overhead. It is a
  *     proprietary feature that needs to be supported by the Access Point.
+ *
  * - Compression: data frames are compressed in real time using a Lempel Ziv
  *     algorithm. This is done transparently. Once this feature is enabled,
  *     compression and decompression takes place inside the chipset, without
  *     putting additional load on the host CPU.
  *
+ * As with XR we also don't plan to support SuperAG features for now. You can
+ * get a mode similar to TURBO by using 40MHz bwmode.
  */
-#define MODULATION_TURBO       0x00000080
 
+
+/**
+ * enum ath5k_driver_mode - PHY operation mode
+ * @AR5K_MODE_11A: 802.11a
+ * @AR5K_MODE_11B: 802.11b
+ * @AR5K_MODE_11G: 801.11g
+ * @AR5K_MODE_MAX: Used for boundary checks
+ *
+ * Do not change the order here, we use these as
+ * array indices and it also maps EEPROM structures.
+ */
 enum ath5k_driver_mode {
        AR5K_MODE_11A           =       0,
        AR5K_MODE_11B           =       1,
@@ -408,30 +448,64 @@ enum ath5k_driver_mode {
        AR5K_MODE_MAX           =       3
 };
 
+/**
+ * enum ath5k_ant_mode - Antenna operation mode
+ * @AR5K_ANTMODE_DEFAULT: Default antenna setup
+ * @AR5K_ANTMODE_FIXED_A: Only antenna A is present
+ * @AR5K_ANTMODE_FIXED_B: Only antenna B is present
+ * @AR5K_ANTMODE_SINGLE_AP: STA locked on a single ap
+ * @AR5K_ANTMODE_SECTOR_AP: AP with tx antenna set on tx desc
+ * @AR5K_ANTMODE_SECTOR_STA: STA with tx antenna set on tx desc
+ * @AR5K_ANTMODE_DEBUG: Debug mode -A -> Rx, B-> Tx-
+ * @AR5K_ANTMODE_MAX: Used for boundary checks
+ *
+ * For more infos on antenna control check out phy.c
+ */
 enum ath5k_ant_mode {
-       AR5K_ANTMODE_DEFAULT    = 0,    /* default antenna setup */
-       AR5K_ANTMODE_FIXED_A    = 1,    /* only antenna A is present */
-       AR5K_ANTMODE_FIXED_B    = 2,    /* only antenna B is present */
-       AR5K_ANTMODE_SINGLE_AP  = 3,    /* sta locked on a single ap */
-       AR5K_ANTMODE_SECTOR_AP  = 4,    /* AP with tx antenna set on tx desc */
-       AR5K_ANTMODE_SECTOR_STA = 5,    /* STA with tx antenna set on tx desc */
-       AR5K_ANTMODE_DEBUG      = 6,    /* Debug mode -A -> Rx, B-> Tx- */
+       AR5K_ANTMODE_DEFAULT    = 0,
+       AR5K_ANTMODE_FIXED_A    = 1,
+       AR5K_ANTMODE_FIXED_B    = 2,
+       AR5K_ANTMODE_SINGLE_AP  = 3,
+       AR5K_ANTMODE_SECTOR_AP  = 4,
+       AR5K_ANTMODE_SECTOR_STA = 5,
+       AR5K_ANTMODE_DEBUG      = 6,
        AR5K_ANTMODE_MAX,
 };
 
+/**
+ * enum ath5k_bw_mode - Bandwidth operation mode
+ * @AR5K_BWMODE_DEFAULT: 20MHz, default operation
+ * @AR5K_BWMODE_5MHZ: Quarter rate
+ * @AR5K_BWMODE_10MHZ: Half rate
+ * @AR5K_BWMODE_40MHZ: Turbo
+ */
 enum ath5k_bw_mode {
-       AR5K_BWMODE_DEFAULT     = 0,    /* 20MHz, default operation */
-       AR5K_BWMODE_5MHZ        = 1,    /* Quarter rate */
-       AR5K_BWMODE_10MHZ       = 2,    /* Half rate */
-       AR5K_BWMODE_40MHZ       = 3     /* Turbo */
+       AR5K_BWMODE_DEFAULT     = 0,
+       AR5K_BWMODE_5MHZ        = 1,
+       AR5K_BWMODE_10MHZ       = 2,
+       AR5K_BWMODE_40MHZ       = 3
 };
 
+
+
 /****************\
   TX DEFINITIONS
 \****************/
 
-/*
- * TX Status descriptor
+/**
+ * struct ath5k_tx_status - TX Status descriptor
+ * @ts_seqnum: Sequence number
+ * @ts_tstamp: Timestamp
+ * @ts_status: Status code
+ * @ts_final_idx: Final transmission series index
+ * @ts_final_retry: Final retry count
+ * @ts_rssi: RSSI for received ACK
+ * @ts_shortretry: Short retry count
+ * @ts_virtcol: Virtual collision count
+ * @ts_antenna: Antenna used
+ *
+ * TX status descriptor gets filled by the hw
+ * on each transmission attempt.
  */
 struct ath5k_tx_status {
        u16     ts_seqnum;
@@ -454,7 +528,6 @@ struct ath5k_tx_status {
  * enum ath5k_tx_queue - Queue types used to classify tx queues.
  * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue
  * @AR5K_TX_QUEUE_DATA: A normal data queue
- * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue
  * @AR5K_TX_QUEUE_BEACON: The beacon queue
  * @AR5K_TX_QUEUE_CAB: The after-beacon queue
  * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue
@@ -462,7 +535,6 @@ struct ath5k_tx_status {
 enum ath5k_tx_queue {
        AR5K_TX_QUEUE_INACTIVE = 0,
        AR5K_TX_QUEUE_DATA,
-       AR5K_TX_QUEUE_XR_DATA,
        AR5K_TX_QUEUE_BEACON,
        AR5K_TX_QUEUE_CAB,
        AR5K_TX_QUEUE_UAPSD,
@@ -471,36 +543,46 @@ enum ath5k_tx_queue {
 #define        AR5K_NUM_TX_QUEUES              10
 #define        AR5K_NUM_TX_QUEUES_NOQCU        2
 
-/*
- * Queue syb-types to classify normal data queues.
+/**
+ * enum ath5k_tx_queue_subtype - Queue sub-types to classify normal data queues
+ * @AR5K_WME_AC_BK: Background traffic
+ * @AR5K_WME_AC_BE: Best-effort (normal) traffic
+ * @AR5K_WME_AC_VI: Video traffic
+ * @AR5K_WME_AC_VO: Voice traffic
+ *
  * These are the 4 Access Categories as defined in
  * WME spec. 0 is the lowest priority and 4 is the
  * highest. Normal data that hasn't been classified
  * goes to the Best Effort AC.
  */
 enum ath5k_tx_queue_subtype {
-       AR5K_WME_AC_BK = 0,     /*Background traffic*/
-       AR5K_WME_AC_BE,         /*Best-effort (normal) traffic*/
-       AR5K_WME_AC_VI,         /*Video traffic*/
-       AR5K_WME_AC_VO,         /*Voice traffic*/
+       AR5K_WME_AC_BK = 0,
+       AR5K_WME_AC_BE,
+       AR5K_WME_AC_VI,
+       AR5K_WME_AC_VO,
 };
 
-/*
- * Queue ID numbers as returned by the hw functions, each number
- * represents a hw queue. If hw does not support hw queues
- * (eg 5210) all data goes in one queue. These match
- * d80211 definitions (net80211/MadWiFi don't use them).
+/**
+ * enum ath5k_tx_queue_id - Queue ID numbers as returned by the hw functions
+ * @AR5K_TX_QUEUE_ID_NOQCU_DATA: Data queue on AR5210 (no QCU available)
+ * @AR5K_TX_QUEUE_ID_NOQCU_BEACON: Beacon queue on AR5210 (no QCU available)
+ * @AR5K_TX_QUEUE_ID_DATA_MIN: Data queue min index
+ * @AR5K_TX_QUEUE_ID_DATA_MAX: Data queue max index
+ * @AR5K_TX_QUEUE_ID_CAB: Content after beacon queue
+ * @AR5K_TX_QUEUE_ID_BEACON: Beacon queue
+ * @AR5K_TX_QUEUE_ID_UAPSD: Urgent Automatic Power Save Delivery,
+ *
+ * Each number represents a hw queue. If hw does not support hw queues
+ * (eg 5210) all data goes in one queue.
  */
 enum ath5k_tx_queue_id {
        AR5K_TX_QUEUE_ID_NOQCU_DATA     = 0,
        AR5K_TX_QUEUE_ID_NOQCU_BEACON   = 1,
-       AR5K_TX_QUEUE_ID_DATA_MIN       = 0, /*IEEE80211_TX_QUEUE_DATA0*/
-       AR5K_TX_QUEUE_ID_DATA_MAX       = 3, /*IEEE80211_TX_QUEUE_DATA3*/
-       AR5K_TX_QUEUE_ID_DATA_SVP       = 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/
-       AR5K_TX_QUEUE_ID_CAB            = 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/
-       AR5K_TX_QUEUE_ID_BEACON         = 7, /*IEEE80211_TX_QUEUE_BEACON*/
-       AR5K_TX_QUEUE_ID_UAPSD          = 8,
-       AR5K_TX_QUEUE_ID_XR_DATA        = 9,
+       AR5K_TX_QUEUE_ID_DATA_MIN       = 0,
+       AR5K_TX_QUEUE_ID_DATA_MAX       = 3,
+       AR5K_TX_QUEUE_ID_UAPSD          = 7,
+       AR5K_TX_QUEUE_ID_CAB            = 8,
+       AR5K_TX_QUEUE_ID_BEACON         = 9,
 };
 
 /*
@@ -521,46 +603,70 @@ enum ath5k_tx_queue_id {
 #define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS                0x1000  /* Disable backoff while bursting */
 #define AR5K_TXQ_FLAG_COMPRESSION_ENABLE       0x2000  /* Enable hw compression -not implemented-*/
 
-/*
- * Data transmit queue state.  One of these exists for each
- * hardware transmit queue.  Packets sent to us from above
- * are assigned to queues based on their priority.  Not all
- * devices support a complete set of hardware transmit queues.
- * For those devices the array sc_ac2q will map multiple
- * priorities to fewer hardware queues (typically all to one
- * hardware queue).
+/**
+ * struct ath5k_txq - Transmit queue state
+ * @qnum: Hardware q number
+ * @link: Link ptr in last TX desc
+ * @q: Transmit queue (&struct list_head)
+ * @lock: Lock on q and link
+ * @setup: Is the queue configured
+ * @txq_len:Number of queued buffers
+ * @txq_max: Max allowed num of queued buffers
+ * @txq_poll_mark: Used to check if queue got stuck
+ * @txq_stuck: Queue stuck counter
+ *
+ * One of these exists for each hardware transmit queue.
+ * Packets sent to us from above are assigned to queues based
+ * on their priority.  Not all devices support a complete set
+ * of hardware transmit queues. For those devices the array
+ * sc_ac2q will map multiple priorities to fewer hardware queues
+ * (typically all to one hardware queue).
  */
 struct ath5k_txq {
-       unsigned int            qnum;   /* hardware q number */
-       u32                     *link;  /* link ptr in last TX desc */
-       struct list_head        q;      /* transmit queue */
-       spinlock_t              lock;   /* lock on q and link */
+       unsigned int            qnum;
+       u32                     *link;
+       struct list_head        q;
+       spinlock_t              lock;
        bool                    setup;
-       int                     txq_len; /* number of queued buffers */
-       int                     txq_max; /* max allowed num of queued buffers */
+       int                     txq_len;
+       int                     txq_max;
        bool                    txq_poll_mark;
-       unsigned int            txq_stuck;      /* informational counter */
+       unsigned int            txq_stuck;
 };
 
-/*
- * A struct to hold tx queue's parameters
+/**
+ * struct ath5k_txq_info - A struct to hold TX queue's parameters
+ * @tqi_type: One of enum ath5k_tx_queue
+ * @tqi_subtype: One of enum ath5k_tx_queue_subtype
+ * @tqi_flags: TX queue flags (see above)
+ * @tqi_aifs: Arbitrated Inter-frame Space
+ * @tqi_cw_min: Minimum Contention Window
+ * @tqi_cw_max: Maximum Contention Window
+ * @tqi_cbr_period: Constant bit rate period
+ * @tqi_ready_time: Time queue waits after an event when RDYTIME is enabled
  */
 struct ath5k_txq_info {
        enum ath5k_tx_queue tqi_type;
        enum ath5k_tx_queue_subtype tqi_subtype;
-       u16     tqi_flags;      /* Tx queue flags (see above) */
-       u8      tqi_aifs;       /* Arbitrated Interframe Space */
-       u16     tqi_cw_min;     /* Minimum Contention Window */
-       u16     tqi_cw_max;     /* Maximum Contention Window */
-       u32     tqi_cbr_period; /* Constant bit rate period */
+       u16     tqi_flags;
+       u8      tqi_aifs;
+       u16     tqi_cw_min;
+       u16     tqi_cw_max;
+       u32     tqi_cbr_period;
        u32     tqi_cbr_overflow_limit;
        u32     tqi_burst_time;
-       u32     tqi_ready_time; /* Time queue waits after an event */
+       u32     tqi_ready_time;
 };
 
-/*
- * Transmit packet types.
- * used on tx control descriptor
+/**
+ * enum ath5k_pkt_type - Transmit packet types
+ * @AR5K_PKT_TYPE_NORMAL: Normal data
+ * @AR5K_PKT_TYPE_ATIM: ATIM
+ * @AR5K_PKT_TYPE_PSPOLL: PS-Poll
+ * @AR5K_PKT_TYPE_BEACON: Beacon
+ * @AR5K_PKT_TYPE_PROBE_RESP: Probe response
+ * @AR5K_PKT_TYPE_PIFS: PIFS
+ * Used on tx control descriptor
  */
 enum ath5k_pkt_type {
        AR5K_PKT_TYPE_NORMAL            = 0,
@@ -583,27 +689,23 @@ enum ath5k_pkt_type {
        (ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v)     \
 )
 
-/*
- * DMA size definitions (2^(n+2))
- */
-enum ath5k_dmasize {
-       AR5K_DMASIZE_4B = 0,
-       AR5K_DMASIZE_8B,
-       AR5K_DMASIZE_16B,
-       AR5K_DMASIZE_32B,
-       AR5K_DMASIZE_64B,
-       AR5K_DMASIZE_128B,
-       AR5K_DMASIZE_256B,
-       AR5K_DMASIZE_512B
-};
 
 
 /****************\
   RX DEFINITIONS
 \****************/
 
-/*
- * RX Status descriptor
+/**
+ * struct ath5k_rx_status - RX Status descriptor
+ * @rs_datalen: Data length
+ * @rs_tstamp: Timestamp
+ * @rs_status: Status code
+ * @rs_phyerr: PHY error mask
+ * @rs_rssi: RSSI in 0.5dbm units
+ * @rs_keyix: Index to the key used for decrypting
+ * @rs_rate: Rate used to decode the frame
+ * @rs_antenna: Antenna used to receive the frame
+ * @rs_more: Indicates this is a frame fragment (Fast frames)
  */
 struct ath5k_rx_status {
        u16     rs_datalen;
@@ -645,10 +747,18 @@ struct ath5k_rx_status {
 #define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
 
 
+
 /*******************************\
   GAIN OPTIMIZATION DEFINITIONS
 \*******************************/
 
+/**
+ * enum ath5k_rfgain - RF Gain optimization engine state
+ * @AR5K_RFGAIN_INACTIVE: Engine disabled
+ * @AR5K_RFGAIN_ACTIVE: Probe active
+ * @AR5K_RFGAIN_READ_REQUESTED: Probe requested
+ * @AR5K_RFGAIN_NEED_CHANGE: Gain_F needs change
+ */
 enum ath5k_rfgain {
        AR5K_RFGAIN_INACTIVE = 0,
        AR5K_RFGAIN_ACTIVE,
@@ -656,6 +766,16 @@ enum ath5k_rfgain {
        AR5K_RFGAIN_NEED_CHANGE,
 };
 
+/**
+ * struct ath5k_gain - RF Gain optimization engine state data
+ * @g_step_idx: Current step index
+ * @g_current: Current gain
+ * @g_target: Target gain
+ * @g_low: Low gain boundary
+ * @g_high: High gain boundary
+ * @g_f_corr: Gain_F correction
+ * @g_state: One of enum ath5k_rfgain
+ */
 struct ath5k_gain {
        u8                      g_step_idx;
        u8                      g_current;
@@ -666,6 +786,8 @@ struct ath5k_gain {
        u8                      g_state;
 };
 
+
+
 /********************\
   COMMON DEFINITIONS
 \********************/
@@ -674,9 +796,14 @@ struct ath5k_gain {
 #define AR5K_SLOT_TIME_20      880
 #define AR5K_SLOT_TIME_MAX     0xffff
 
-/*
- * The following structure is used to map 2GHz channels to
- * 5GHz Atheros channels.
+/**
+ * struct ath5k_athchan_2ghz - 2GHz to 5GHZ map for RF5111
+ * @a2_flags: Channel flags (internal)
+ * @a2_athchan: HW channel number (internal)
+ *
+ * This structure is used to map 2GHz channels to
+ * 5GHz Atheros channels on 2111 frequency converter
+ * that comes together with RF5111
  * TODO: Clean up
  */
 struct ath5k_athchan_2ghz {
@@ -684,36 +811,80 @@ struct ath5k_athchan_2ghz {
        u16     a2_athchan;
 };
 
+/**
+ * enum ath5k_dmasize -  DMA size definitions (2^(n+2))
+ * @AR5K_DMASIZE_4B: 4Bytes
+ * @AR5K_DMASIZE_8B: 8Bytes
+ * @AR5K_DMASIZE_16B: 16Bytes
+ * @AR5K_DMASIZE_32B: 32Bytes
+ * @AR5K_DMASIZE_64B: 64Bytes (Default)
+ * @AR5K_DMASIZE_128B: 128Bytes
+ * @AR5K_DMASIZE_256B: 256Bytes
+ * @AR5K_DMASIZE_512B: 512Bytes
+ *
+ * These are used to set DMA burst size on hw
+ *
+ * Note: Some platforms can't handle more than 4Bytes
+ * be careful on embedded boards.
+ */
+enum ath5k_dmasize {
+       AR5K_DMASIZE_4B = 0,
+       AR5K_DMASIZE_8B,
+       AR5K_DMASIZE_16B,
+       AR5K_DMASIZE_32B,
+       AR5K_DMASIZE_64B,
+       AR5K_DMASIZE_128B,
+       AR5K_DMASIZE_256B,
+       AR5K_DMASIZE_512B
+};
+
+
 
 /******************\
   RATE DEFINITIONS
 \******************/
 
 /**
+ * DOC: Rate codes
+ *
  * Seems the ar5xxx hardware supports up to 32 rates, indexed by 1-32.
  *
  * The rate code is used to get the RX rate or set the TX rate on the
  * hardware descriptors. It is also used for internal modulation control
  * and settings.
  *
- * This is the hardware rate map we are aware of:
- *
- * rate_code   0x01    0x02    0x03    0x04    0x05    0x06    0x07    0x08
- * rate_kbps   3000    1000    ?       ?       ?       2000    500     48000
- *
- * rate_code   0x09    0x0A    0x0B    0x0C    0x0D    0x0E    0x0F    0x10
- * rate_kbps   24000   12000   6000    54000   36000   18000   9000    ?
+ * This is the hardware rate map we are aware of (html unfriendly):
  *
- * rate_code   17      18      19      20      21      22      23      24
- * rate_kbps   ?       ?       ?       ?       ?       ?       ?       11000
+ * Rate code   Rate (Kbps)
+ * ---------   -----------
+ * 0x01                 3000 (XR)
+ * 0x02                 1000 (XR)
+ * 0x03                  250 (XR)
+ * 0x04 - 05   -Reserved-
+ * 0x06                 2000 (XR)
+ * 0x07                  500 (XR)
+ * 0x08                48000 (OFDM)
+ * 0x09                24000 (OFDM)
+ * 0x0A                12000 (OFDM)
+ * 0x0B                 6000 (OFDM)
+ * 0x0C                54000 (OFDM)
+ * 0x0D                36000 (OFDM)
+ * 0x0E                18000 (OFDM)
+ * 0x0F                 9000 (OFDM)
+ * 0x10 - 17   -Reserved-
+ * 0x18                11000L (CCK)
+ * 0x19                 5500L (CCK)
+ * 0x1A                 2000L (CCK)
+ * 0x1B                 1000L (CCK)
+ * 0x1C                11000S (CCK)
+ * 0x1D                 5500S (CCK)
+ * 0x1E                 2000S (CCK)
+ * 0x1F                -Reserved-
  *
- * rate_code   25      26      27      28      29      30      31      32
- * rate_kbps   5500    2000    1000    11000S  5500S   2000S   ?       ?
- *
- * "S" indicates CCK rates with short preamble.
+ * "S" indicates CCK rates with short preamble and "L" with long preamble.
  *
  * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the
- * lowest 4 bits, so they are the same as below with a 0xF mask.
+ * lowest 4 bits, so they are the same as above with a 0xF mask.
  * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M).
  * We handle this in ath5k_setup_bands().
  */
@@ -733,13 +904,9 @@ struct ath5k_athchan_2ghz {
 #define ATH5K_RATE_CODE_36M    0x0D
 #define ATH5K_RATE_CODE_48M    0x08
 #define ATH5K_RATE_CODE_54M    0x0C
-/* XR */
-#define ATH5K_RATE_CODE_XR_500K        0x07
-#define ATH5K_RATE_CODE_XR_1M  0x02
-#define ATH5K_RATE_CODE_XR_2M  0x06
-#define ATH5K_RATE_CODE_XR_3M  0x01
 
-/* adding this flag to rate_code enables short preamble */
+/* Adding this flag to rate_code on B rates
+ * enables short preamble */
 #define AR5K_SET_SHORT_PREAMBLE 0x04
 
 /*
@@ -769,49 +936,65 @@ extern int ath5k_modparam_nohwcrypt;
 
 /**
  * enum ath5k_int - Hardware interrupt masks helpers
+ * @AR5K_INT_RXOK: Frame successfully received
+ * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor
+ * @AR5K_INT_RXERR: Frame reception failed
+ * @AR5K_INT_RXNOFRM: No frame received within a specified time period
+ * @AR5K_INT_RXEOL: Reached "End Of List", means we need more RX descriptors
+ * @AR5K_INT_RXORN: Indicates we got RX FIFO overrun. Note that Rx overrun is
+ *             not always fatal, on some chips we can continue operation
+ *             without resetting the card, that's why %AR5K_INT_FATAL is not
+ *             common for all chips.
+ * @AR5K_INT_RX_ALL: Mask to identify all RX related interrupts
+ *
+ * @AR5K_INT_TXOK: Frame transmission success
+ * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor
+ * @AR5K_INT_TXERR: Frame transmission failure
+ * @AR5K_INT_TXEOL: Received End Of List for VEOL (Virtual End Of List). The
+ *             Queue Control Unit (QCU) signals an EOL interrupt only if a
+ *             descriptor's LinkPtr is NULL. For more details, refer to:
+ *             "http://www.freepatentsonline.com/20030225739.html"
+ * @AR5K_INT_TXNOFRM: No frame was transmitted within a specified time period
+ * @AR5K_INT_TXURN: Indicates we got TX FIFO underrun. In such case we should
+ *             increase the TX trigger threshold.
+ * @AR5K_INT_TX_ALL: Mask to identify all TX related interrupts
  *
- * @AR5K_INT_RX: mask to identify received frame interrupts, of type
- *     AR5K_ISR_RXOK or AR5K_ISR_RXERR
- * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?)
- * @AR5K_INT_RXNOFRM: No frame received (?)
- * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The
- *     Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
- *     LinkPtr is NULL. For more details, refer to:
- *     http://www.freepatentsonline.com/20030225739.html
- * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors).
- *     Note that Rx overrun is not always fatal, on some chips we can continue
- *     operation without resetting the card, that's why int_fatal is not
- *     common for all chips.
- * @AR5K_INT_TX: mask to identify received frame interrupts, of type
- *     AR5K_ISR_TXOK or AR5K_ISR_TXERR
- * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?)
- * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
- *     We currently do increments on interrupt by
- *     (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
  * @AR5K_INT_MIB: Indicates the either Management Information Base counters or
- *     one of the PHY error counters reached the maximum value and should be
- *     read and cleared.
+ *             one of the PHY error counters reached the maximum value and
+ *             should be read and cleared.
+ * @AR5K_INT_SWI: Software triggered interrupt.
  * @AR5K_INT_RXPHY: RX PHY Error
  * @AR5K_INT_RXKCM: RX Key cache miss
  * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
- *     beacon that must be handled in software. The alternative is if you
- *     have VEOL support, in that case you let the hardware deal with things.
+ *             beacon that must be handled in software. The alternative is if
+ *             you have VEOL support, in that case you let the hardware deal
+ *             with things.
+ * @AR5K_INT_BRSSI: Beacon received with an RSSI value below our threshold
  * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing
- *     beacons from the AP have associated with, we should probably try to
- *     reassociate. When in IBSS mode this might mean we have not received
- *     any beacons from any local stations. Note that every station in an
- *     IBSS schedules to send beacons at the Target Beacon Transmission Time
- *     (TBTT) with a random backoff.
- * @AR5K_INT_BNR: Beacon Not Ready interrupt - ??
- * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now
- *     until properly handled
- * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
- *     errors. These types of errors we can enable seem to be of type
- *     AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
+ *             beacons from the AP have associated with, we should probably
+ *             try to reassociate. When in IBSS mode this might mean we have
+ *             not received any beacons from any local stations. Note that
+ *             every station in an IBSS schedules to send beacons at the
+ *             Target Beacon Transmission Time (TBTT) with a random backoff.
+ * @AR5K_INT_BNR: Beacon queue got triggered (DMA beacon alert) while empty.
+ * @AR5K_INT_TIM: Beacon with local station's TIM bit set
+ * @AR5K_INT_DTIM: Beacon with DTIM bit and zero DTIM count received
+ * @AR5K_INT_DTIM_SYNC: DTIM sync lost
+ * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill switches connected to
+ *             our GPIO pins.
+ * @AR5K_INT_BCN_TIMEOUT: Beacon timeout, we waited after TBTT but got noting
+ * @AR5K_INT_CAB_TIMEOUT: We waited for CAB traffic after the beacon but got
+ *             nothing or an incomplete CAB frame sequence.
+ * @AR5K_INT_QCBRORN: A queue got it's CBR counter expired
+ * @AR5K_INT_QCBRURN: A queue got triggered wile empty
+ * @AR5K_INT_QTRIG: A queue got triggered
+ *
+ * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by bus/DMA
+ *             errors. Indicates we need to reset the card.
  * @AR5K_INT_GLOBAL: Used to clear and set the IER
- * @AR5K_INT_NOCARD: signals the card has been removed
- * @AR5K_INT_COMMON: common interrupts shared among MACs with the same
- *     bit value
+ * @AR5K_INT_NOCARD: Signals the card has been removed
+ * @AR5K_INT_COMMON: Common interrupts shared among MACs with the same
+ *             bit value
  *
  * These are mapped to take advantage of some common bits
  * between the MACs, to be able to set intr properties
@@ -847,15 +1030,15 @@ enum ath5k_int {
        AR5K_INT_GPIO   =       0x01000000,
        AR5K_INT_BCN_TIMEOUT =  0x02000000, /* Non common */
        AR5K_INT_CAB_TIMEOUT =  0x04000000, /* Non common */
-       AR5K_INT_RX_DOPPLER =   0x08000000, /* Non common */
-       AR5K_INT_QCBRORN =      0x10000000, /* Non common */
-       AR5K_INT_QCBRURN =      0x20000000, /* Non common */
-       AR5K_INT_QTRIG  =       0x40000000, /* Non common */
+       AR5K_INT_QCBRORN =      0x08000000, /* Non common */
+       AR5K_INT_QCBRURN =      0x10000000, /* Non common */
+       AR5K_INT_QTRIG  =       0x20000000, /* Non common */
        AR5K_INT_GLOBAL =       0x80000000,
 
        AR5K_INT_TX_ALL = AR5K_INT_TXOK
                | AR5K_INT_TXDESC
                | AR5K_INT_TXERR
+               | AR5K_INT_TXNOFRM
                | AR5K_INT_TXEOL
                | AR5K_INT_TXURN,
 
@@ -891,15 +1074,32 @@ enum ath5k_int {
        AR5K_INT_NOCARD = 0xffffffff
 };
 
-/* mask which calibration is active at the moment */
+/**
+ * enum ath5k_calibration_mask - Mask which calibration is active at the moment
+ * @AR5K_CALIBRATION_FULL: Full calibration (AGC + SHORT)
+ * @AR5K_CALIBRATION_SHORT: Short calibration (NF + I/Q)
+ * @AR5K_CALIBRATION_NF: Noise Floor calibration
+ * @AR5K_CALIBRATION_ANI: Adaptive Noise Immunity
+ */
 enum ath5k_calibration_mask {
        AR5K_CALIBRATION_FULL = 0x01,
        AR5K_CALIBRATION_SHORT = 0x02,
-       AR5K_CALIBRATION_ANI = 0x04,
+       AR5K_CALIBRATION_NF = 0x04,
+       AR5K_CALIBRATION_ANI = 0x08,
 };
 
-/*
- * Power management
+/**
+ * enum ath5k_power_mode - Power management modes
+ * @AR5K_PM_UNDEFINED: Undefined
+ * @AR5K_PM_AUTO: Allow card to sleep if possible
+ * @AR5K_PM_AWAKE: Force card to wake up
+ * @AR5K_PM_FULL_SLEEP: Force card to full sleep (DANGEROUS)
+ * @AR5K_PM_NETWORK_SLEEP: Allow to sleep for a specified duration
+ *
+ * Currently only PM_AWAKE is used, FULL_SLEEP and NETWORK_SLEEP/AUTO
+ * are also known to have problems on some cards. This is not a big
+ * problem though because we can have almost the same effect as
+ * FULL_SLEEP by putting card on warm reset (it's almost powered down).
  */
 enum ath5k_power_mode {
        AR5K_PM_UNDEFINED = 0,
@@ -957,6 +1157,8 @@ struct ath5k_capabilities {
        } cap_queues;
 
        bool cap_has_phyerr_counters;
+       bool cap_has_mrr_support;
+       bool cap_needs_2GHz_ovr;
 };
 
 /* size of noise floor history (keep it a power of two) */
@@ -1072,13 +1274,11 @@ struct ath5k_hw {
        dma_addr_t              desc_daddr;     /* DMA (physical) address */
        size_t                  desc_len;       /* size of TX/RX descriptors */
 
-       DECLARE_BITMAP(status, 6);
+       DECLARE_BITMAP(status, 4);
 #define ATH_STAT_INVALID       0               /* disable hardware accesses */
-#define ATH_STAT_MRRETRY       1               /* multi-rate retry support */
-#define ATH_STAT_PROMISC       2
-#define ATH_STAT_LEDSOFT       3               /* enable LED gpio status */
-#define ATH_STAT_STARTED       4               /* opened & irqs enabled */
-#define ATH_STAT_2G_DISABLED   5               /* multiband radio without 2G */
+#define ATH_STAT_PROMISC       1
+#define ATH_STAT_LEDSOFT       2               /* enable LED gpio status */
+#define ATH_STAT_STARTED       3               /* opened & irqs enabled */
 
        unsigned int            filter_flags;   /* HW flags, AR5K_RX_FILTER_* */
        struct ieee80211_channel *curchan;      /* current h/w channel */
@@ -1097,6 +1297,7 @@ struct ath5k_hw {
                                led_on;         /* pin setting for LED on */
 
        struct work_struct      reset_work;     /* deferred chip reset */
+       struct work_struct      calib_work;     /* deferred phy calibration */
 
        struct list_head        rxbuf;          /* receive buffer */
        spinlock_t              rxbuflock;
@@ -1113,8 +1314,6 @@ struct ath5k_hw {
 
        struct ath5k_rfkill     rf_kill;
 
-       struct tasklet_struct   calib;          /* calibration tasklet */
-
        spinlock_t              block;          /* protects beacon */
        struct tasklet_struct   beacontq;       /* beacon intr tasklet */
        struct list_head        bcbuf;          /* beacon buffer */
@@ -1144,7 +1343,7 @@ struct ath5k_hw {
        enum ath5k_int          ah_imr;
 
        struct ieee80211_channel *ah_current_channel;
-       bool                    ah_calibration;
+       bool                    ah_iq_cal_needed;
        bool                    ah_single_chip;
 
        enum ath5k_version      ah_version;
@@ -1187,7 +1386,13 @@ struct ath5k_hw {
        u32                     ah_txq_imr_cbrurn;
        u32                     ah_txq_imr_qtrig;
        u32                     ah_txq_imr_nofrm;
-       u32                     ah_txq_isr;
+
+       u32                     ah_txq_isr_txok_all;
+       u32                     ah_txq_isr_txurn;
+       u32                     ah_txq_isr_qcborn;
+       u32                     ah_txq_isr_qcburn;
+       u32                     ah_txq_isr_qtrig;
+
        u32                     *ah_rf_banks;
        size_t                  ah_rf_banks_size;
        size_t                  ah_rf_regs_count;
@@ -1228,8 +1433,8 @@ struct ath5k_hw {
 
        /* Calibration timestamp */
        unsigned long           ah_cal_next_full;
+       unsigned long           ah_cal_next_short;
        unsigned long           ah_cal_next_ani;
-       unsigned long           ah_cal_next_nf;
 
        /* Calibration mask */
        u8                      ah_cal_mask;
@@ -1338,11 +1543,11 @@ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
 u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
 void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64);
 void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
-void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
+void ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon,
+                                                       u32 interval);
 bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval);
 /* Init function */
-void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
-                                                               u8 mode);
+void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode);
 
 /* Queue Control Unit, DFS Control Unit Functions */
 int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
index 91627dd..d7114c7 100644 (file)
@@ -27,8 +27,7 @@
 #include "debug.h"
 
 /**
- * ath5k_hw_post - Power On Self Test helper function
- *
+ * ath5k_hw_post() - Power On Self Test helper function
  * @ah: The &struct ath5k_hw
  */
 static int ath5k_hw_post(struct ath5k_hw *ah)
@@ -92,8 +91,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
 }
 
 /**
- * ath5k_hw_init - Check if hw is supported and init the needed structs
- *
+ * ath5k_hw_init() - Check if hw is supported and init the needed structs
  * @ah: The &struct ath5k_hw associated with the device
  *
  * Check if the device is supported, perform a POST and initialize the needed
@@ -298,7 +296,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
 
                /* Reset SERDES to load new settings */
                ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
-               mdelay(1);
+               usleep_range(1000, 1500);
        }
 
        /* Get misc capabilities */
@@ -308,11 +306,6 @@ int ath5k_hw_init(struct ath5k_hw *ah)
                goto err;
        }
 
-       if (test_bit(ATH_STAT_2G_DISABLED, ah->status)) {
-               __clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode);
-               __clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode);
-       }
-
        /* Crypto settings */
        common->keymax = (ah->ah_version == AR5K_AR5210 ?
                          AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
@@ -349,8 +342,7 @@ err:
 }
 
 /**
- * ath5k_hw_deinit - Free the ath5k_hw struct
- *
+ * ath5k_hw_deinit() - Free the &struct ath5k_hw
  * @ah: The &struct ath5k_hw
  */
 void ath5k_hw_deinit(struct ath5k_hw *ah)
index b346d04..178a4dd 100644 (file)
@@ -80,6 +80,11 @@ static int 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;
+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");
+
 
 /* Module info */
 MODULE_AUTHOR("Jiri Slaby");
@@ -183,7 +188,6 @@ static const struct ieee80211_rate ath5k_rates[] = {
        { .bitrate = 540,
          .hw_value = ATH5K_RATE_CODE_54M,
          .flags = 0 },
-       /* XR missing */
 };
 
 static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
@@ -721,21 +725,24 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
        if (ret)
                goto err_unmap;
 
-       memset(mrr_rate, 0, sizeof(mrr_rate));
-       memset(mrr_tries, 0, sizeof(mrr_tries));
-       for (i = 0; i < 3; i++) {
-               rate = ieee80211_get_alt_retry_rate(ah->hw, info, i);
-               if (!rate)
-                       break;
+       /* Set up MRR descriptor */
+       if (ah->ah_capabilities.cap_has_mrr_support) {
+               memset(mrr_rate, 0, sizeof(mrr_rate));
+               memset(mrr_tries, 0, sizeof(mrr_tries));
+               for (i = 0; i < 3; i++) {
+                       rate = ieee80211_get_alt_retry_rate(ah->hw, info, i);
+                       if (!rate)
+                               break;
 
-               mrr_rate[i] = rate->hw_value;
-               mrr_tries[i] = info->control.rates[i + 1].count;
-       }
+                       mrr_rate[i] = rate->hw_value;
+                       mrr_tries[i] = info->control.rates[i + 1].count;
+               }
 
-       ath5k_hw_setup_mrr_tx_desc(ah, ds,
-               mrr_rate[0], mrr_tries[0],
-               mrr_rate[1], mrr_tries[1],
-               mrr_rate[2], mrr_tries[2]);
+               ath5k_hw_setup_mrr_tx_desc(ah, ds,
+                       mrr_rate[0], mrr_tries[0],
+                       mrr_rate[1], mrr_tries[1],
+                       mrr_rate[2], mrr_tries[2]);
+       }
 
        ds->ds_link = 0;
        ds->ds_data = bf->skbaddr;
@@ -1689,7 +1696,7 @@ ath5k_tasklet_tx(unsigned long data)
        struct ath5k_hw *ah = (void *)data;
 
        for (i = 0; i < AR5K_NUM_TX_QUEUES; i++)
-               if (ah->txqs[i].setup && (ah->ah_txq_isr & BIT(i)))
+               if (ah->txqs[i].setup && (ah->ah_txq_isr_txok_all & BIT(i)))
                        ath5k_tx_processq(ah, &ah->txqs[i]);
 
        ah->tx_pending = false;
@@ -2005,7 +2012,7 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf)
        ah->nexttbtt = nexttbtt;
 
        intval |= AR5K_BEACON_ENA;
-       ath5k_hw_init_beacon(ah, nexttbtt, intval);
+       ath5k_hw_init_beacon_timers(ah, nexttbtt, intval);
 
        /*
         * debugging output last in order to preserve the time critical aspect
@@ -2112,16 +2119,29 @@ static void
 ath5k_intr_calibration_poll(struct ath5k_hw *ah)
 {
        if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) &&
-           !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) {
-               /* run ANI only when full calibration is not active */
+          !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) &&
+          !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) {
+
+               /* Run ANI only when calibration is not active */
+
                ah->ah_cal_next_ani = jiffies +
                        msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI);
                tasklet_schedule(&ah->ani_tasklet);
 
-       } else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) {
-               ah->ah_cal_next_full = jiffies +
-                       msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
-               tasklet_schedule(&ah->calib);
+       } else if (time_is_before_eq_jiffies(ah->ah_cal_next_short) &&
+               !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) &&
+               !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) {
+
+               /* Run calibration only when another calibration
+                * is not running.
+                *
+                * Note: This is for both full/short calibration,
+                * if it's time for a full one, ath5k_calibrate_work will deal
+                * with it. */
+
+               ah->ah_cal_next_short = jiffies +
+                       msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT);
+               ieee80211_queue_work(ah->hw, &ah->calib_work);
        }
        /* we could use SWI to generate enough interrupts to meet our
         * calibration interval requirements, if necessary:
@@ -2149,69 +2169,110 @@ ath5k_intr(int irq, void *dev_id)
        enum ath5k_int status;
        unsigned int counter = 1000;
 
+
+       /*
+        * If hw is not ready (or detached) and we get an
+        * interrupt, or if we have no interrupts pending
+        * (that means it's not for us) skip it.
+        *
+        * NOTE: Group 0/1 PCI interface registers are not
+        * supported on WiSOCs, so we can't check for pending
+        * interrupts (ISR belongs to another register group
+        * so we are ok).
+        */
        if (unlikely(test_bit(ATH_STAT_INVALID, ah->status) ||
-               ((ath5k_get_bus_type(ah) != ATH_AHB) &&
-                               !ath5k_hw_is_intr_pending(ah))))
+                       ((ath5k_get_bus_type(ah) != ATH_AHB) &&
+                       !ath5k_hw_is_intr_pending(ah))))
                return IRQ_NONE;
 
+       /** Main loop **/
        do {
-               ath5k_hw_get_isr(ah, &status);          /* NB: clears IRQ too */
+               ath5k_hw_get_isr(ah, &status);  /* NB: clears IRQ too */
+
                ATH5K_DBG(ah, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n",
                                status, ah->imask);
+
+               /*
+                * Fatal hw error -> Log and reset
+                *
+                * Fatal errors are unrecoverable so we have to
+                * reset the card. These errors include bus and
+                * dma errors.
+                */
                if (unlikely(status & AR5K_INT_FATAL)) {
-                       /*
-                        * Fatal errors are unrecoverable.
-                        * Typically these are caused by DMA errors.
-                        */
+
                        ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
                                  "fatal int, resetting\n");
                        ieee80211_queue_work(ah->hw, &ah->reset_work);
+
+               /*
+                * RX Overrun -> Count and reset if needed
+                *
+                * Receive buffers are full. Either the bus is busy or
+                * the CPU is not fast enough to process all received
+                * frames.
+                */
                } else if (unlikely(status & AR5K_INT_RXORN)) {
+
                        /*
-                        * Receive buffers are full. Either the bus is busy or
-                        * the CPU is not fast enough to process all received
-                        * frames.
                         * Older chipsets need a reset to come out of this
                         * condition, but we treat it as RX for newer chips.
-                        * We don't know exactly which versions need a reset -
+                        * We don't know exactly which versions need a reset
                         * this guess is copied from the HAL.
                         */
                        ah->stats.rxorn_intr++;
+
                        if (ah->ah_mac_srev < AR5K_SREV_AR5212) {
                                ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
                                          "rx overrun, resetting\n");
                                ieee80211_queue_work(ah->hw, &ah->reset_work);
                        } else
                                ath5k_schedule_rx(ah);
+
                } else {
+
+                       /* Software Beacon Alert -> Schedule beacon tasklet */
                        if (status & AR5K_INT_SWBA)
                                tasklet_hi_schedule(&ah->beacontq);
 
-                       if (status & AR5K_INT_RXEOL) {
-                               /*
-                               * NB: the hardware should re-read the link when
-                               *     RXE bit is written, but it doesn't work at
-                               *     least on older hardware revs.
-                               */
+                       /*
+                        * No more RX descriptors -> Just count
+                        *
+                        * NB: the hardware should re-read the link when
+                        *     RXE bit is written, but it doesn't work at
+                        *     least on older hardware revs.
+                        */
+                       if (status & AR5K_INT_RXEOL)
                                ah->stats.rxeol_intr++;
-                       }
-                       if (status & AR5K_INT_TXURN) {
-                               /* bump tx trigger level */
+
+
+                       /* TX Underrun -> Bump tx trigger level */
+                       if (status & AR5K_INT_TXURN)
                                ath5k_hw_update_tx_triglevel(ah, true);
-                       }
+
+                       /* RX -> Schedule rx tasklet */
                        if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
                                ath5k_schedule_rx(ah);
-                       if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
-                                       | AR5K_INT_TXERR | AR5K_INT_TXEOL))
+
+                       /* TX -> Schedule tx tasklet */
+                       if (status & (AR5K_INT_TXOK
+                                       | AR5K_INT_TXDESC
+                                       | AR5K_INT_TXERR
+                                       | AR5K_INT_TXEOL))
                                ath5k_schedule_tx(ah);
-                       if (status & AR5K_INT_BMISS) {
-                               /* TODO */
-                       }
+
+                       /* Missed beacon -> TODO
+                       if (status & AR5K_INT_BMISS)
+                       */
+
+                       /* MIB event -> Update counters and notify ANI */
                        if (status & AR5K_INT_MIB) {
                                ah->stats.mib_intr++;
                                ath5k_hw_update_mib_counters(ah);
                                ath5k_ani_mib_intr(ah);
                        }
+
+                       /* GPIO -> Notify RFKill layer */
                        if (status & AR5K_INT_GPIO)
                                tasklet_schedule(&ah->rf_kill.toggleq);
 
@@ -2222,12 +2283,19 @@ ath5k_intr(int irq, void *dev_id)
 
        } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
 
+       /*
+        * Until we handle rx/tx interrupts mask them on IMR
+        *
+        * NOTE: ah->(rx/tx)_pending are set when scheduling the tasklets
+        * and unset after we 've handled the interrupts.
+        */
        if (ah->rx_pending || ah->tx_pending)
                ath5k_set_current_imask(ah);
 
        if (unlikely(!counter))
                ATH5K_WARN(ah, "too many interrupts, giving up for now\n");
 
+       /* Fire up calibration poll */
        ath5k_intr_calibration_poll(ah);
 
        return IRQ_HANDLED;
@@ -2238,41 +2306,58 @@ ath5k_intr(int irq, void *dev_id)
  * for temperature/environment changes.
  */
 static void
-ath5k_tasklet_calibrate(unsigned long data)
+ath5k_calibrate_work(struct work_struct *work)
 {
-       struct ath5k_hw *ah = (void *)data;
+       struct ath5k_hw *ah = container_of(work, struct ath5k_hw,
+               calib_work);
+
+       /* Should we run a full calibration ? */
+       if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) {
+
+               ah->ah_cal_next_full = jiffies +
+                       msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
+               ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
+
+               ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE,
+                               "running full calibration\n");
+
+               if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
+                       /*
+                        * Rfgain is out of bounds, reset the chip
+                        * to load new gain values.
+                        */
+                       ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
+                                       "got new rfgain, resetting\n");
+                       ieee80211_queue_work(ah->hw, &ah->reset_work);
+               }
+
+               /* TODO: On full calibration we should stop TX here,
+                * so that it doesn't interfere (mostly due to gain_f
+                * calibration that messes with tx packets -see phy.c).
+                *
+                * NOTE: Stopping the queues from above is not enough
+                * to stop TX but saves us from disconecting (at least
+                * we don't lose packets). */
+               ieee80211_stop_queues(ah->hw);
+       } else
+               ah->ah_cal_mask |= AR5K_CALIBRATION_SHORT;
 
-       /* Only full calibration for now */
-       ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
 
        ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
                ieee80211_frequency_to_channel(ah->curchan->center_freq),
                ah->curchan->hw_value);
 
-       if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
-               /*
-                * Rfgain is out of bounds, reset the chip
-                * to load new gain values.
-                */
-               ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "calibration, resetting\n");
-               ieee80211_queue_work(ah->hw, &ah->reset_work);
-       }
        if (ath5k_hw_phy_calibrate(ah, ah->curchan))
                ATH5K_ERR(ah, "calibration of channel %u failed\n",
                        ieee80211_frequency_to_channel(
                                ah->curchan->center_freq));
 
-       /* Noise floor calibration interrupts rx/tx path while I/Q calibration
-        * doesn't.
-        * TODO: We should stop TX here, so that it doesn't interfere.
-        * Note that stopping the queues is not enough to stop TX! */
-       if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) {
-               ah->ah_cal_next_nf = jiffies +
-                       msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF);
-               ath5k_hw_update_noise_floor(ah);
-       }
-
-       ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
+       /* Clear calibration flags */
+       if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) {
+               ieee80211_wake_queues(ah->hw);
+               ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
+       } else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)
+               ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT;
 }
 
 
@@ -2407,8 +2492,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
        if (ret)
                goto err_irq;
 
-       /* set up multi-rate retry capabilities */
-       if (ah->ah_version == AR5K_AR5212) {
+       /* Set up multi-rate retry capabilities */
+       if (ah->ah_capabilities.cap_has_mrr_support) {
                hw->max_rates = 4;
                hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT,
                                         AR5K_INIT_RETRY_LONG);
@@ -2544,15 +2629,22 @@ int ath5k_start(struct ieee80211_hw *hw)
         * and then setup of the interrupt mask.
         */
        ah->curchan = ah->hw->conf.channel;
-       ah->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
-               AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
-               AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
+       ah->imask = AR5K_INT_RXOK
+               | AR5K_INT_RXERR
+               | AR5K_INT_RXEOL
+               | AR5K_INT_RXORN
+               | AR5K_INT_TXDESC
+               | AR5K_INT_TXEOL
+               | AR5K_INT_FATAL
+               | AR5K_INT_GLOBAL
+               | AR5K_INT_MIB;
 
        ret = ath5k_reset(ah, NULL, false);
        if (ret)
                goto done;
 
-       ath5k_rfkill_hw_start(ah);
+       if (!ath5k_modparam_no_hw_rfkill_switch)
+               ath5k_rfkill_hw_start(ah);
 
        /*
         * Reset the key cache since some parts do not reset the
@@ -2585,7 +2677,6 @@ static void ath5k_stop_tasklets(struct ath5k_hw *ah)
        ah->tx_pending = false;
        tasklet_kill(&ah->rxtq);
        tasklet_kill(&ah->txtq);
-       tasklet_kill(&ah->calib);
        tasklet_kill(&ah->beacontq);
        tasklet_kill(&ah->ani_tasklet);
 }
@@ -2637,7 +2728,8 @@ void ath5k_stop(struct ieee80211_hw *hw)
 
        cancel_delayed_work_sync(&ah->tx_complete_work);
 
-       ath5k_rfkill_hw_stop(ah);
+       if (!ath5k_modparam_no_hw_rfkill_switch)
+               ath5k_rfkill_hw_stop(ah);
 }
 
 /*
@@ -2689,9 +2781,24 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
 
        ath5k_ani_init(ah, ani_mode);
 
-       ah->ah_cal_next_full = jiffies + msecs_to_jiffies(100);
-       ah->ah_cal_next_ani = jiffies;
-       ah->ah_cal_next_nf = jiffies;
+       /*
+        * Set calibration intervals
+        *
+        * Note: We don't need to run calibration imediately
+        * since some initial calibration is done on reset
+        * even for fast channel switching. Also on scanning
+        * this will get set again and again and it won't get
+        * executed unless we connect somewhere and spend some
+        * time on the channel (that's what calibration needs
+        * anyway to be accurate).
+        */
+       ah->ah_cal_next_full = jiffies +
+               msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
+       ah->ah_cal_next_ani = jiffies +
+               msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI);
+       ah->ah_cal_next_short = jiffies +
+               msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT);
+
        ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8);
 
        /* clear survey data and cycle counters */
@@ -2744,20 +2851,6 @@ ath5k_init(struct ieee80211_hw *hw)
        int ret;
 
 
-       /*
-        * Check if the MAC has multi-rate retry support.
-        * We do this by trying to setup a fake extended
-        * descriptor.  MACs that don't have support will
-        * return false w/o doing anything.  MACs that do
-        * support it will return true w/o doing anything.
-        */
-       ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
-
-       if (ret < 0)
-               goto err;
-       if (ret > 0)
-               __set_bit(ATH_STAT_MRRETRY, ah->status);
-
        /*
         * Collect the channel list.  The 802.11 layer
         * is responsible for filtering this list based
@@ -2841,11 +2934,11 @@ ath5k_init(struct ieee80211_hw *hw)
 
        tasklet_init(&ah->rxtq, ath5k_tasklet_rx, (unsigned long)ah);
        tasklet_init(&ah->txtq, ath5k_tasklet_tx, (unsigned long)ah);
-       tasklet_init(&ah->calib, ath5k_tasklet_calibrate, (unsigned long)ah);
        tasklet_init(&ah->beacontq, ath5k_tasklet_beacon, (unsigned long)ah);
        tasklet_init(&ah->ani_tasklet, ath5k_tasklet_ani, (unsigned long)ah);
 
        INIT_WORK(&ah->reset_work, ath5k_reset_work);
+       INIT_WORK(&ah->calib_work, ath5k_calibrate_work);
        INIT_DELAYED_WORK(&ah->tx_complete_work, ath5k_tx_complete_poll_work);
 
        ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac);
index 810fba9..994169a 100644 (file)
@@ -85,12 +85,19 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
                        caps->cap_range.range_2ghz_min = 2412;
                        caps->cap_range.range_2ghz_max = 2732;
 
-                       if (AR5K_EEPROM_HDR_11B(ee_header))
-                               __set_bit(AR5K_MODE_11B, caps->cap_mode);
-
-                       if (AR5K_EEPROM_HDR_11G(ee_header) &&
-                           ah->ah_version != AR5K_AR5211)
-                               __set_bit(AR5K_MODE_11G, caps->cap_mode);
+                       /* Override 2GHz modes on SoCs that need it
+                        * NOTE: cap_needs_2GHz_ovr gets set from
+                        * ath_ahb_probe */
+                       if (!caps->cap_needs_2GHz_ovr) {
+                               if (AR5K_EEPROM_HDR_11B(ee_header))
+                                       __set_bit(AR5K_MODE_11B,
+                                                       caps->cap_mode);
+
+                               if (AR5K_EEPROM_HDR_11G(ee_header) &&
+                               ah->ah_version != AR5K_AR5211)
+                                       __set_bit(AR5K_MODE_11G,
+                                                       caps->cap_mode);
+                       }
                }
        }
 
@@ -103,12 +110,18 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
        else
                caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
 
-       /* newer hardware has PHY error counters */
+       /* Newer hardware has PHY error counters */
        if (ah->ah_mac_srev >= AR5K_SREV_AR5213A)
                caps->cap_has_phyerr_counters = true;
        else
                caps->cap_has_phyerr_counters = false;
 
+       /* MACs since AR5212 have MRR support */
+       if (ah->ah_version == AR5K_AR5212)
+               caps->cap_has_mrr_support = true;
+       else
+               caps->cap_has_mrr_support = false;
+
        return 0;
 }
 
index 7e88dda..f8bfa3a 100644 (file)
 #include "debug.h"
 
 
+/**
+ * DOC: Hardware descriptor functions
+ *
+ * Here we handle the processing of the low-level hw descriptors
+ * that hw reads and writes via DMA for each TX and RX attempt (that means
+ * we can also have descriptors for failed TX/RX tries). We have two kind of
+ * descriptors for RX and TX, control descriptors tell the hw how to send or
+ * receive a packet where to read/write it from/to etc and status descriptors
+ * that contain information about how the packet was sent or received (errors
+ * included).
+ *
+ * Descriptor format is not exactly the same for each MAC chip version so we
+ * have function pointers on &struct ath5k_hw we initialize at runtime based on
+ * the chip used.
+ */
+
+
 /************************\
 * TX Control descriptors *
 \************************/
 
-/*
- * Initialize the 2-word tx control descriptor on 5210/5211
+/**
+ * ath5k_hw_setup_2word_tx_desc() - Initialize a 2-word tx control descriptor
+ * @ah: The &struct ath5k_hw
+ * @desc: The &struct ath5k_desc
+ * @pkt_len: Frame length in bytes
+ * @hdr_len: Header length in bytes (only used on AR5210)
+ * @padsize: Any padding we've added to the frame length
+ * @type: One of enum ath5k_pkt_type
+ * @tx_power: Tx power in 0.5dB steps
+ * @tx_rate0: HW idx for transmission rate
+ * @tx_tries0: Max number of retransmissions
+ * @key_index: Index on key table to use for encryption
+ * @antenna_mode: Which antenna to use (0 for auto)
+ * @flags: One of AR5K_TXDESC_* flags (desc.h)
+ * @rtscts_rate: HW idx for RTS/CTS transmission rate
+ * @rtscts_duration: What to put on duration field on the header of RTS/CTS
+ *
+ * Internal function to initialize a 2-Word TX control descriptor
+ * found on AR5210 and AR5211 MACs chips.
+ *
+ * Returns 0 on success or -EINVAL on false input
  */
 static int
-ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
-       unsigned int pkt_len, unsigned int hdr_len, int padsize,
-       enum ath5k_pkt_type type,
-       unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0,
-       unsigned int key_index, unsigned int antenna_mode, unsigned int flags,
-       unsigned int rtscts_rate, unsigned int rtscts_duration)
+ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah,
+                       struct ath5k_desc *desc,
+                       unsigned int pkt_len, unsigned int hdr_len,
+                       int padsize,
+                       enum ath5k_pkt_type type,
+                       unsigned int tx_power,
+                       unsigned int tx_rate0, unsigned int tx_tries0,
+                       unsigned int key_index,
+                       unsigned int antenna_mode,
+                       unsigned int flags,
+                       unsigned int rtscts_rate, unsigned int rtscts_duration)
 {
        u32 frame_type;
        struct ath5k_hw_2w_tx_ctl *tx_ctl;
@@ -172,17 +213,40 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
        return 0;
 }
 
-/*
- * Initialize the 4-word tx control descriptor on 5212
+/**
+ * ath5k_hw_setup_4word_tx_desc() - Initialize a 4-word tx control descriptor
+ * @ah: The &struct ath5k_hw
+ * @desc: The &struct ath5k_desc
+ * @pkt_len: Frame length in bytes
+ * @hdr_len: Header length in bytes (only used on AR5210)
+ * @padsize: Any padding we've added to the frame length
+ * @type: One of enum ath5k_pkt_type
+ * @tx_power: Tx power in 0.5dB steps
+ * @tx_rate0: HW idx for transmission rate
+ * @tx_tries0: Max number of retransmissions
+ * @key_index: Index on key table to use for encryption
+ * @antenna_mode: Which antenna to use (0 for auto)
+ * @flags: One of AR5K_TXDESC_* flags (desc.h)
+ * @rtscts_rate: HW idx for RTS/CTS transmission rate
+ * @rtscts_duration: What to put on duration field on the header of RTS/CTS
+ *
+ * Internal function to initialize a 4-Word TX control descriptor
+ * found on AR5212 and later MACs chips.
+ *
+ * Returns 0 on success or -EINVAL on false input
  */
-static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
-       struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len,
-       int padsize,
-       enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
-       unsigned int tx_tries0, unsigned int key_index,
-       unsigned int antenna_mode, unsigned int flags,
-       unsigned int rtscts_rate,
-       unsigned int rtscts_duration)
+static int
+ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
+                       struct ath5k_desc *desc,
+                       unsigned int pkt_len, unsigned int hdr_len,
+                       int padsize,
+                       enum ath5k_pkt_type type,
+                       unsigned int tx_power,
+                       unsigned int tx_rate0, unsigned int tx_tries0,
+                       unsigned int key_index,
+                       unsigned int antenna_mode,
+                       unsigned int flags,
+                       unsigned int rtscts_rate, unsigned int rtscts_duration)
 {
        struct ath5k_hw_4w_tx_ctl *tx_ctl;
        unsigned int frame_len;
@@ -292,13 +356,29 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
        return 0;
 }
 
-/*
- * Initialize a 4-word multi rate retry tx control descriptor on 5212
+/**
+ * ath5k_hw_setup_mrr_tx_desc() - Initialize an MRR tx control descriptor
+ * @ah: The &struct ath5k_hw
+ * @desc: The &struct ath5k_desc
+ * @tx_rate1: HW idx for rate used on transmission series 1
+ * @tx_tries1: Max number of retransmissions for transmission series 1
+ * @tx_rate2: HW idx for rate used on transmission series 2
+ * @tx_tries2: Max number of retransmissions for transmission series 2
+ * @tx_rate3: HW idx for rate used on transmission series 3
+ * @tx_tries3: Max number of retransmissions for transmission series 3
+ *
+ * Multi rate retry (MRR) tx control descriptors are available only on AR5212
+ * MACs, they are part of the normal 4-word tx control descriptor (see above)
+ * but we handle them through a separate function for better abstraction.
+ *
+ * Returns 0 on success or -EINVAL on invalid input
  */
 int
-ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
-       unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
-       u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
+ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah,
+                       struct ath5k_desc *desc,
+                       u_int tx_rate1, u_int tx_tries1,
+                       u_int tx_rate2, u_int tx_tries2,
+                       u_int tx_rate3, u_int tx_tries3)
 {
        struct ath5k_hw_4w_tx_ctl *tx_ctl;
 
@@ -350,11 +430,16 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
 * TX Status descriptors *
 \***********************/
 
-/*
- * Process the tx status descriptor on 5210/5211
+/**
+ * ath5k_hw_proc_2word_tx_status() - Process a tx status descriptor on 5210/1
+ * @ah: The &struct ath5k_hw
+ * @desc: The &struct ath5k_desc
+ * @ts: The &struct ath5k_tx_status
  */
-static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
-               struct ath5k_desc *desc, struct ath5k_tx_status *ts)
+static int
+ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
+                               struct ath5k_desc *desc,
+                               struct ath5k_tx_status *ts)
 {
        struct ath5k_hw_2w_tx_ctl *tx_ctl;
        struct ath5k_hw_tx_status *tx_status;
@@ -399,11 +484,16 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
        return 0;
 }
 
-/*
- * Process a tx status descriptor on 5212
+/**
+ * ath5k_hw_proc_4word_tx_status() - Process a tx status descriptor on 5212
+ * @ah: The &struct ath5k_hw
+ * @desc: The &struct ath5k_desc
+ * @ts: The &struct ath5k_tx_status
  */
-static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
-               struct ath5k_desc *desc, struct ath5k_tx_status *ts)
+static int
+ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
+                               struct ath5k_desc *desc,
+                               struct ath5k_tx_status *ts)
 {
        struct ath5k_hw_4w_tx_ctl *tx_ctl;
        struct ath5k_hw_tx_status *tx_status;
@@ -460,11 +550,17 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
 * RX Descriptors *
 \****************/
 
-/*
- * Initialize an rx control descriptor
+/**
+ * ath5k_hw_setup_rx_desc() - Initialize an rx control descriptor
+ * @ah: The &struct ath5k_hw
+ * @desc: The &struct ath5k_desc
+ * @size: RX buffer length in bytes
+ * @flags: One of AR5K_RXDESC_* flags
  */
-int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
-                          u32 size, unsigned int flags)
+int
+ath5k_hw_setup_rx_desc(struct ath5k_hw *ah,
+                       struct ath5k_desc *desc,
+                       u32 size, unsigned int flags)
 {
        struct ath5k_hw_rx_ctl *rx_ctl;
 
@@ -491,11 +587,22 @@ int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
        return 0;
 }
 
-/*
- * Process the rx status descriptor on 5210/5211
+/**
+ * ath5k_hw_proc_5210_rx_status() - Process the rx status descriptor on 5210/1
+ * @ah: The &struct ath5k_hw
+ * @desc: The &struct ath5k_desc
+ * @rs: The &struct ath5k_rx_status
+ *
+ * Internal function used to process an RX status descriptor
+ * on AR5210/5211 MAC.
+ *
+ * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
+ * frame yet.
  */
-static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
-               struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+static int
+ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
+                               struct ath5k_desc *desc,
+                               struct ath5k_rx_status *rs)
 {
        struct ath5k_hw_rx_status *rx_status;
 
@@ -574,12 +681,22 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
        return 0;
 }
 
-/*
- * Process the rx status descriptor on 5212
+/**
+ * ath5k_hw_proc_5212_rx_status() - Process the rx status descriptor on 5212
+ * @ah: The &struct ath5k_hw
+ * @desc: The &struct ath5k_desc
+ * @rs: The &struct ath5k_rx_status
+ *
+ * Internal function used to process an RX status descriptor
+ * on AR5212 and later MAC.
+ *
+ * Returns 0 on success or -EINPROGRESS in case we haven't received the who;e
+ * frame yet.
  */
-static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
-                                       struct ath5k_desc *desc,
-                                       struct ath5k_rx_status *rs)
+static int
+ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
+                               struct ath5k_desc *desc,
+                               struct ath5k_rx_status *rs)
 {
        struct ath5k_hw_rx_status *rx_status;
        u32 rxstat0, rxstat1;
@@ -646,10 +763,16 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
 * Attach *
 \********/
 
-/*
- * Init function pointers inside ath5k_hw struct
+/**
+ * ath5k_hw_init_desc_functions() - Init function pointers inside ah
+ * @ah: The &struct ath5k_hw
+ *
+ * Maps the internal descriptor functions to the function pointers on ah, used
+ * from above. This is used as an abstraction layer to handle the various chips
+ * the same way.
  */
-int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
+int
+ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
 {
        if (ah->ah_version == AR5K_AR5212) {
                ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
index cfd529b..8d6c01a 100644 (file)
  * RX/TX descriptor structures
  */
 
-/*
- * Common hardware RX control descriptor
+/**
+ * struct ath5k_hw_rx_ctl - Common hardware RX control descriptor
+ * @rx_control_0: RX control word 0
+ * @rx_control_1: RX control word 1
  */
 struct ath5k_hw_rx_ctl {
-       u32     rx_control_0; /* RX control word 0 */
-       u32     rx_control_1; /* RX control word 1 */
+       u32     rx_control_0;
+       u32     rx_control_1;
 } __packed __aligned(4);
 
 /* RX control word 1 fields/flags */
 #define AR5K_DESC_RX_CTL1_BUF_LEN              0x00000fff /* data buffer length */
 #define AR5K_DESC_RX_CTL1_INTREQ               0x00002000 /* RX interrupt request */
 
-/*
- * Common hardware RX status descriptor
+/**
+ * struct ath5k_hw_rx_status - Common hardware RX status descriptor
+ * @rx_status_0: RX status word 0
+ * @rx_status_1: RX status word 1
+ *
  * 5210, 5211 and 5212 differ only in the fields and flags defined below
  */
 struct ath5k_hw_rx_status {
-       u32     rx_status_0; /* RX status word 0 */
-       u32     rx_status_1; /* RX status word 1 */
+       u32     rx_status_0;
+       u32     rx_status_1;
 } __packed __aligned(4);
 
 /* 5210/5211 */
@@ -98,17 +103,36 @@ struct ath5k_hw_rx_status {
 
 /**
  * enum ath5k_phy_error_code - PHY Error codes
+ * @AR5K_RX_PHY_ERROR_UNDERRUN: Transmit underrun, [5210] No error
+ * @AR5K_RX_PHY_ERROR_TIMING: Timing error
+ * @AR5K_RX_PHY_ERROR_PARITY: Illegal parity
+ * @AR5K_RX_PHY_ERROR_RATE: Illegal rate
+ * @AR5K_RX_PHY_ERROR_LENGTH: Illegal length
+ * @AR5K_RX_PHY_ERROR_RADAR: Radar detect, [5210] 64 QAM rate
+ * @AR5K_RX_PHY_ERROR_SERVICE: Illegal service
+ * @AR5K_RX_PHY_ERROR_TOR: Transmit override receive
+ * @AR5K_RX_PHY_ERROR_OFDM_TIMING: OFDM Timing error [5212+]
+ * @AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY: OFDM Signal parity error [5212+]
+ * @AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL: OFDM Illegal rate [5212+]
+ * @AR5K_RX_PHY_ERROR_OFDM_LENGTH_ILLEGAL: OFDM Illegal length [5212+]
+ * @AR5K_RX_PHY_ERROR_OFDM_POWER_DROP: OFDM Power drop [5212+]
+ * @AR5K_RX_PHY_ERROR_OFDM_SERVICE: OFDM Service (?) [5212+]
+ * @AR5K_RX_PHY_ERROR_OFDM_RESTART: OFDM Restart (?) [5212+]
+ * @AR5K_RX_PHY_ERROR_CCK_TIMING: CCK Timing error [5212+]
+ * @AR5K_RX_PHY_ERROR_CCK_HEADER_CRC: Header CRC error [5212+]
+ * @AR5K_RX_PHY_ERROR_CCK_RATE_ILLEGAL: Illegal rate [5212+]
+ * @AR5K_RX_PHY_ERROR_CCK_SERVICE: CCK Service (?) [5212+]
+ * @AR5K_RX_PHY_ERROR_CCK_RESTART: CCK Restart (?) [5212+]
  */
 enum ath5k_phy_error_code {
-       AR5K_RX_PHY_ERROR_UNDERRUN              = 0,    /* Transmit underrun, [5210] No error */
-       AR5K_RX_PHY_ERROR_TIMING                = 1,    /* Timing error */
-       AR5K_RX_PHY_ERROR_PARITY                = 2,    /* Illegal parity */
-       AR5K_RX_PHY_ERROR_RATE                  = 3,    /* Illegal rate */
-       AR5K_RX_PHY_ERROR_LENGTH                = 4,    /* Illegal length */
-       AR5K_RX_PHY_ERROR_RADAR                 = 5,    /* Radar detect, [5210] 64 QAM rate */
-       AR5K_RX_PHY_ERROR_SERVICE               = 6,    /* Illegal service */
-       AR5K_RX_PHY_ERROR_TOR                   = 7,    /* Transmit override receive */
-       /* these are specific to the 5212 */
+       AR5K_RX_PHY_ERROR_UNDERRUN              = 0,
+       AR5K_RX_PHY_ERROR_TIMING                = 1,
+       AR5K_RX_PHY_ERROR_PARITY                = 2,
+       AR5K_RX_PHY_ERROR_RATE                  = 3,
+       AR5K_RX_PHY_ERROR_LENGTH                = 4,
+       AR5K_RX_PHY_ERROR_RADAR                 = 5,
+       AR5K_RX_PHY_ERROR_SERVICE               = 6,
+       AR5K_RX_PHY_ERROR_TOR                   = 7,
        AR5K_RX_PHY_ERROR_OFDM_TIMING           = 17,
        AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY    = 18,
        AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL     = 19,
@@ -123,12 +147,14 @@ enum ath5k_phy_error_code {
        AR5K_RX_PHY_ERROR_CCK_RESTART           = 31,
 };
 
-/*
- * 5210/5211 hardware 2-word TX control descriptor
+/**
+ * struct ath5k_hw_2w_tx_ctl  - 5210/5211 hardware 2-word TX control descriptor
+ * @tx_control_0: TX control word 0
+ * @tx_control_1: TX control word 1
  */
 struct ath5k_hw_2w_tx_ctl {
-       u32     tx_control_0; /* TX control word 0 */
-       u32     tx_control_1; /* TX control word 1 */
+       u32     tx_control_0;
+       u32     tx_control_1;
 } __packed __aligned(4);
 
 /* TX control word 0 fields/flags */
@@ -177,14 +203,18 @@ struct ath5k_hw_2w_tx_ctl {
 #define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS    4
 #define AR5K_AR5211_TX_DESC_FRAME_TYPE_PRESP   4
 
-/*
- * 5212 hardware 4-word TX control descriptor
+/**
+ * struct ath5k_hw_4w_tx_ctl - 5212 hardware 4-word TX control descriptor
+ * @tx_control_0: TX control word 0
+ * @tx_control_1: TX control word 1
+ * @tx_control_2: TX control word 2
+ * @tx_control_3: TX control word 3
  */
 struct ath5k_hw_4w_tx_ctl {
-       u32     tx_control_0; /* TX control word 0 */
-       u32     tx_control_1; /* TX control word 1 */
-       u32     tx_control_2; /* TX control word 2 */
-       u32     tx_control_3; /* TX control word 3 */
+       u32     tx_control_0;
+       u32     tx_control_1;
+       u32     tx_control_2;
+       u32     tx_control_3;
 } __packed __aligned(4);
 
 /* TX control word 0 fields/flags */
@@ -238,12 +268,14 @@ struct ath5k_hw_4w_tx_ctl {
 #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE      0x01f00000 /* RTS or CTS rate */
 #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S    20
 
-/*
- * Common TX status descriptor
+/**
+ * struct ath5k_hw_tx_status - Common TX status descriptor
+ * @tx_status_0: TX status word 0
+ * @tx_status_1: TX status word 1
  */
 struct ath5k_hw_tx_status {
-       u32     tx_status_0; /* TX status word 0 */
-       u32     tx_status_1; /* TX status word 1 */
+       u32     tx_status_0;
+       u32     tx_status_1;
 } __packed __aligned(4);
 
 /* TX status word 0 fields/flags */
@@ -276,37 +308,47 @@ struct ath5k_hw_tx_status {
 #define AR5K_DESC_TX_STATUS1_COMP_SUCCESS_5212 0x00800000 /* [5212] compression status */
 #define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212 0x01000000 /* [5212] transmit antenna */
 
-/*
- * 5210/5211 hardware TX descriptor
+/**
+ * struct ath5k_hw_5210_tx_desc - 5210/5211 hardware TX descriptor
+ * @tx_ctl: The &struct ath5k_hw_2w_tx_ctl
+ * @tx_stat: The &struct ath5k_hw_tx_status
  */
 struct ath5k_hw_5210_tx_desc {
        struct ath5k_hw_2w_tx_ctl       tx_ctl;
        struct ath5k_hw_tx_status       tx_stat;
 } __packed __aligned(4);
 
-/*
- * 5212 hardware TX descriptor
+/**
+ * struct ath5k_hw_5212_tx_desc - 5212 hardware TX descriptor
+ * @tx_ctl: The &struct ath5k_hw_4w_tx_ctl
+ * @tx_stat: The &struct ath5k_hw_tx_status
  */
 struct ath5k_hw_5212_tx_desc {
        struct ath5k_hw_4w_tx_ctl       tx_ctl;
        struct ath5k_hw_tx_status       tx_stat;
 } __packed __aligned(4);
 
-/*
- * Common hardware RX descriptor
+/**
+ * struct ath5k_hw_all_rx_desc - Common hardware RX descriptor
+ * @rx_ctl: The &struct ath5k_hw_rx_ctl
+ * @rx_stat: The &struct ath5k_hw_rx_status
  */
 struct ath5k_hw_all_rx_desc {
        struct ath5k_hw_rx_ctl          rx_ctl;
        struct ath5k_hw_rx_status       rx_stat;
 } __packed __aligned(4);
 
-/*
- * Atheros hardware DMA descriptor
+/**
+ * struct ath5k_desc - Atheros hardware DMA descriptor
+ * @ds_link: Physical address of the next descriptor
+ * @ds_data: Physical address of data buffer (skb)
+ * @ud: Union containing hw_5xxx_tx_desc structs and hw_all_rx_desc
+ *
  * This is read and written to by the hardware
  */
 struct ath5k_desc {
-       u32     ds_link;        /* physical address of the next descriptor */
-       u32     ds_data;        /* physical address of data buffer (skb) */
+       u32     ds_link;
+       u32     ds_data;
 
        union {
                struct ath5k_hw_5210_tx_desc    ds_tx5210;
index 2481f9c..5cc9aa8 100644 (file)
 * DMA and interrupt masking functions *
 \*************************************/
 
-/*
- * dma.c - DMA and interrupt masking functions
+/**
+ * DOC: DMA and interrupt masking functions
  *
  * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
  * handle queue setup for 5210 chipset (rest are handled on qcu.c).
  * Also we setup interrupt mask register (IMR) and read the various interrupt
  * status registers (ISR).
- *
- * TODO: Handle SISR on 5211+ and introduce a function to return the queue
- * number that resulted the interrupt.
  */
 
 #include "ath5k.h"
 \*********/
 
 /**
- * ath5k_hw_start_rx_dma - Start DMA receive
- *
+ * ath5k_hw_start_rx_dma() - Start DMA receive
  * @ah:        The &struct ath5k_hw
  */
-void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
+void
+ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
 {
        ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
        ath5k_hw_reg_read(ah, AR5K_CR);
 }
 
 /**
- * ath5k_hw_stop_rx_dma - Stop DMA receive
- *
+ * ath5k_hw_stop_rx_dma() - Stop DMA receive
  * @ah:        The &struct ath5k_hw
  */
-static int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
+static int
+ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
 {
        unsigned int i;
 
@@ -79,24 +76,24 @@ static int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
 }
 
 /**
- * ath5k_hw_get_rxdp - Get RX Descriptor's address
- *
+ * ath5k_hw_get_rxdp() - Get RX Descriptor's address
  * @ah: The &struct ath5k_hw
  */
-u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
+u32
+ath5k_hw_get_rxdp(struct ath5k_hw *ah)
 {
        return ath5k_hw_reg_read(ah, AR5K_RXDP);
 }
 
 /**
- * ath5k_hw_set_rxdp - Set RX Descriptor's address
- *
+ * ath5k_hw_set_rxdp() - Set RX Descriptor's address
  * @ah: The &struct ath5k_hw
  * @phys_addr: RX descriptor address
  *
  * Returns -EIO if rx is active
  */
-int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
+int
+ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
 {
        if (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) {
                ATH5K_DBG(ah, ATH5K_DEBUG_DMA,
@@ -114,8 +111,7 @@ int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
 \**********/
 
 /**
- * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue
- *
+ * ath5k_hw_start_tx_dma() - Start DMA transmit for a specific queue
  * @ah: The &struct ath5k_hw
  * @queue: The hw queue number
  *
@@ -128,7 +124,8 @@ int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
  * NOTE: Must be called after setting up tx control descriptor for that
  * queue (see below).
  */
-int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+int
+ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 {
        u32 tx_queue;
 
@@ -177,17 +174,16 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 }
 
 /**
- * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue
- *
+ * ath5k_hw_stop_tx_dma() - Stop DMA transmit on a specific queue
  * @ah: The &struct ath5k_hw
  * @queue: The hw queue number
  *
  * Stop DMA transmit on a specific hw queue and drain queue so we don't
  * have any pending frames. Returns -EBUSY if we still have pending frames,
  * -EINVAL if queue number is out of range or inactive.
- *
  */
-static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+static int
+ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 {
        unsigned int i = 40;
        u32 tx_queue, pending;
@@ -320,14 +316,14 @@ static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 }
 
 /**
- * ath5k_hw_stop_beacon_queue - Stop beacon queue
- *
- * @ah The &struct ath5k_hw
- * @queue The queue number
+ * ath5k_hw_stop_beacon_queue() - Stop beacon queue
+ * @ah: The &struct ath5k_hw
+ * @queue: The queue number
  *
  * Returns -EIO if queue didn't stop
  */
-int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
+int
+ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
 {
        int ret;
        ret = ath5k_hw_stop_tx_dma(ah, queue);
@@ -340,8 +336,7 @@ int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
 }
 
 /**
- * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
- *
+ * ath5k_hw_get_txdp() - Get TX Descriptor's address for a specific queue
  * @ah: The &struct ath5k_hw
  * @queue: The hw queue number
  *
@@ -352,7 +347,8 @@ int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
  *
  * XXX: Is TXDP read and clear ?
  */
-u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
+u32
+ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
 {
        u16 tx_reg;
 
@@ -382,10 +378,10 @@ u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
 }
 
 /**
- * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue
- *
+ * ath5k_hw_set_txdp() - Set TX Descriptor's address for a specific queue
  * @ah: The &struct ath5k_hw
  * @queue: The hw queue number
+ * @phys_addr: The physical address
  *
  * Set TX descriptor's address for a specific queue. For 5210 we ignore
  * the queue number and we use tx queue type since we only have 2 queues
@@ -394,7 +390,8 @@ u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
  * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still
  * active.
  */
-int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
+int
+ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
 {
        u16 tx_reg;
 
@@ -435,8 +432,7 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
 }
 
 /**
- * ath5k_hw_update_tx_triglevel - Update tx trigger level
- *
+ * ath5k_hw_update_tx_triglevel() - Update tx trigger level
  * @ah: The &struct ath5k_hw
  * @increase: Flag to force increase of trigger level
  *
@@ -444,15 +440,15 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
  * buffer (aka FIFO threshold) that is used to indicate when PCU flushes
  * the buffer and transmits its data. Lowering this results sending small
  * frames more quickly but can lead to tx underruns, raising it a lot can
- * result other problems (i think bmiss is related). Right now we start with
- * the lowest possible (64Bytes) and if we get tx underrun we increase it using
- * the increase flag. Returns -EIO if we have reached maximum/minimum.
+ * result other problems. Right now we start with the lowest possible
+ * (64Bytes) and if we get tx underrun we increase it using the increase
+ * flag. Returns -EIO if we have reached maximum/minimum.
  *
  * XXX: Link this with tx DMA size ?
- * XXX: Use it to save interrupts ?
- * TODO: Needs testing, i think it's related to bmiss...
+ * XXX2: Use it to save interrupts ?
  */
-int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
+int
+ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
 {
        u32 trigger_level, imr;
        int ret = -EIO;
@@ -498,21 +494,20 @@ done:
 \*******************/
 
 /**
- * ath5k_hw_is_intr_pending - Check if we have pending interrupts
- *
+ * ath5k_hw_is_intr_pending() - Check if we have pending interrupts
  * @ah: The &struct ath5k_hw
  *
  * Check if we have pending interrupts to process. Returns 1 if we
  * have pending interrupts and 0 if we haven't.
  */
-bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
+bool
+ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
 {
        return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
 }
 
 /**
- * ath5k_hw_get_isr - Get interrupt status
- *
+ * ath5k_hw_get_isr() - Get interrupt status
  * @ah: The @struct ath5k_hw
  * @interrupt_mask: Driver's interrupt mask used to filter out
  * interrupts in sw.
@@ -523,62 +518,162 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
  * being mapped on some standard non hw-specific positions
  * (check out &ath5k_int).
  *
- * NOTE: We use read-and-clear register, so after this function is called ISR
- * is zeroed.
+ * NOTE: We do write-to-clear, so the active PISR/SISR bits at the time this
+ * function gets called are cleared on return.
  */
-int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
+int
+ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
 {
-       u32 data;
+       u32 data = 0;
 
        /*
-        * Read interrupt status from the Interrupt Status register
-        * on 5210
+        * Read interrupt status from Primary Interrupt
+        * Register.
+        *
+        * Note: PISR/SISR Not available on 5210
         */
        if (ah->ah_version == AR5K_AR5210) {
-               data = ath5k_hw_reg_read(ah, AR5K_ISR);
-               if (unlikely(data == AR5K_INT_NOCARD)) {
-                       *interrupt_mask = data;
+               u32 isr = 0;
+               isr = ath5k_hw_reg_read(ah, AR5K_ISR);
+               if (unlikely(isr == AR5K_INT_NOCARD)) {
+                       *interrupt_mask = isr;
                        return -ENODEV;
                }
-       } else {
+
                /*
-                * Read interrupt status from Interrupt
-                * Status Register shadow copy (Read And Clear)
-                *
-                * Note: PISR/SISR Not available on 5210
+                * Filter out the non-common bits from the interrupt
+                * status.
                 */
-               data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
-               if (unlikely(data == AR5K_INT_NOCARD)) {
-                       *interrupt_mask = data;
+               *interrupt_mask = (isr & AR5K_INT_COMMON) & ah->ah_imr;
+
+               /* Hanlde INT_FATAL */
+               if (unlikely(isr & (AR5K_ISR_SSERR | AR5K_ISR_MCABT
+                                               | AR5K_ISR_DPERR)))
+                       *interrupt_mask |= AR5K_INT_FATAL;
+
+               /*
+                * XXX: BMISS interrupts may occur after association.
+                * I found this on 5210 code but it needs testing. If this is
+                * true we should disable them before assoc and re-enable them
+                * after a successful assoc + some jiffies.
+                       interrupt_mask &= ~AR5K_INT_BMISS;
+                */
+
+               data = isr;
+       } else {
+               u32 pisr = 0;
+               u32 pisr_clear = 0;
+               u32 sisr0 = 0;
+               u32 sisr1 = 0;
+               u32 sisr2 = 0;
+               u32 sisr3 = 0;
+               u32 sisr4 = 0;
+
+               /* Read PISR and SISRs... */
+               pisr = ath5k_hw_reg_read(ah, AR5K_PISR);
+               if (unlikely(pisr == AR5K_INT_NOCARD)) {
+                       *interrupt_mask = pisr;
                        return -ENODEV;
                }
-       }
 
-       /*
-        * Get abstract interrupt mask (driver-compatible)
-        */
-       *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
+               sisr0 = ath5k_hw_reg_read(ah, AR5K_SISR0);
+               sisr1 = ath5k_hw_reg_read(ah, AR5K_SISR1);
+               sisr2 = ath5k_hw_reg_read(ah, AR5K_SISR2);
+               sisr3 = ath5k_hw_reg_read(ah, AR5K_SISR3);
+               sisr4 = ath5k_hw_reg_read(ah, AR5K_SISR4);
 
-       if (ah->ah_version != AR5K_AR5210) {
-               u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2);
+               /*
+                * PISR holds the logical OR of interrupt bits
+                * from SISR registers:
+                *
+                * TXOK and TXDESC  -> Logical OR of TXOK and TXDESC
+                *                      per-queue bits on SISR0
+                *
+                * TXERR and TXEOL -> Logical OR of TXERR and TXEOL
+                *                      per-queue bits on SISR1
+                *
+                * TXURN -> Logical OR of TXURN per-queue bits on SISR2
+                *
+                * HIUERR -> Logical OR of MCABT, SSERR and DPER bits on SISR2
+                *
+                * BCNMISC -> Logical OR of TIM, CAB_END, DTIM_SYNC
+                *              BCN_TIMEOUT, CAB_TIMEOUT and DTIM
+                *              (and TSFOOR ?) bits on SISR2
+                *
+                * QCBRORN and QCBRURN -> Logical OR of QCBRORN and
+                *                      QCBRURN per-queue bits on SISR3
+                * QTRIG -> Logical OR of QTRIG per-queue bits on SISR4
+                *
+                * If we clean these bits on PISR we 'll also clear all
+                * related bits from SISRs, e.g. if we write the TXOK bit on
+                * PISR we 'll clean all TXOK bits from SISR0 so if a new TXOK
+                * interrupt got fired for another queue while we were reading
+                * the interrupt registers and we write back the TXOK bit on
+                * PISR we 'll lose it. So make sure that we don't write back
+                * on PISR any bits that come from SISRs. Clearing them from
+                * SISRs will also clear PISR so no need to worry here.
+                */
 
-               /*HIU = Host Interface Unit (PCI etc)*/
-               if (unlikely(data & (AR5K_ISR_HIUERR)))
-                       *interrupt_mask |= AR5K_INT_FATAL;
+               pisr_clear = pisr & ~AR5K_ISR_BITS_FROM_SISRS;
 
-               /*Beacon Not Ready*/
-               if (unlikely(data & (AR5K_ISR_BNR)))
-                       *interrupt_mask |= AR5K_INT_BNR;
+               /*
+                * Write to clear them...
+                * Note: This means that each bit we write back
+                * to the registers will get cleared, leaving the
+                * rest unaffected. So this won't affect new interrupts
+                * we didn't catch while reading/processing, we 'll get
+                * them next time get_isr gets called.
+                */
+               ath5k_hw_reg_write(ah, sisr0, AR5K_SISR0);
+               ath5k_hw_reg_write(ah, sisr1, AR5K_SISR1);
+               ath5k_hw_reg_write(ah, sisr2, AR5K_SISR2);
+               ath5k_hw_reg_write(ah, sisr3, AR5K_SISR3);
+               ath5k_hw_reg_write(ah, sisr4, AR5K_SISR4);
+               ath5k_hw_reg_write(ah, pisr_clear, AR5K_PISR);
+               /* Flush previous write */
+               ath5k_hw_reg_read(ah, AR5K_PISR);
 
-               if (unlikely(sisr2 & (AR5K_SISR2_SSERR |
-                                       AR5K_SISR2_DPERR |
-                                       AR5K_SISR2_MCABT)))
-                       *interrupt_mask |= AR5K_INT_FATAL;
+               /*
+                * Filter out the non-common bits from the interrupt
+                * status.
+                */
+               *interrupt_mask = (pisr & AR5K_INT_COMMON) & ah->ah_imr;
+
+
+               /* We treat TXOK,TXDESC, TXERR and TXEOL
+                * the same way (schedule the tx tasklet)
+                * so we track them all together per queue */
+               if (pisr & AR5K_ISR_TXOK)
+                       ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr0,
+                                               AR5K_SISR0_QCU_TXOK);
 
-               if (data & AR5K_ISR_TIM)
+               if (pisr & AR5K_ISR_TXDESC)
+                       ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr0,
+                                               AR5K_SISR0_QCU_TXDESC);
+
+               if (pisr & AR5K_ISR_TXERR)
+                       ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr1,
+                                               AR5K_SISR1_QCU_TXERR);
+
+               if (pisr & AR5K_ISR_TXEOL)
+                       ah->ah_txq_isr_txok_all |= AR5K_REG_MS(sisr1,
+                                               AR5K_SISR1_QCU_TXEOL);
+
+               /* Currently this is not much usefull since we treat
+                * all queues the same way if we get a TXURN (update
+                * tx trigger level) but we might need it later on*/
+               if (pisr & AR5K_ISR_TXURN)
+                       ah->ah_txq_isr_txurn |= AR5K_REG_MS(sisr2,
+                                               AR5K_SISR2_QCU_TXURN);
+
+               /* Misc Beacon related interrupts */
+
+               /* For AR5211 */
+               if (pisr & AR5K_ISR_TIM)
                        *interrupt_mask |= AR5K_INT_TIM;
 
-               if (data & AR5K_ISR_BCNMISC) {
+               /* For AR5212+ */
+               if (pisr & AR5K_ISR_BCNMISC) {
                        if (sisr2 & AR5K_SISR2_TIM)
                                *interrupt_mask |= AR5K_INT_TIM;
                        if (sisr2 & AR5K_SISR2_DTIM)
@@ -591,63 +686,39 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
                                *interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
                }
 
-               if (data & AR5K_ISR_RXDOPPLER)
-                       *interrupt_mask |= AR5K_INT_RX_DOPPLER;
-               if (data & AR5K_ISR_QCBRORN) {
+               /* Below interrupts are unlikely to happen */
+
+               /* HIU = Host Interface Unit (PCI etc)
+                * Can be one of MCABT, SSERR, DPERR from SISR2 */
+               if (unlikely(pisr & (AR5K_ISR_HIUERR)))
+                       *interrupt_mask |= AR5K_INT_FATAL;
+
+               /*Beacon Not Ready*/
+               if (unlikely(pisr & (AR5K_ISR_BNR)))
+                       *interrupt_mask |= AR5K_INT_BNR;
+
+               /* A queue got CBR overrun */
+               if (unlikely(pisr & (AR5K_ISR_QCBRORN))) {
                        *interrupt_mask |= AR5K_INT_QCBRORN;
-                       ah->ah_txq_isr |= AR5K_REG_MS(
-                                       ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
-                                       AR5K_SISR3_QCBRORN);
+                       ah->ah_txq_isr_qcborn |= AR5K_REG_MS(sisr3,
+                                               AR5K_SISR3_QCBRORN);
                }
-               if (data & AR5K_ISR_QCBRURN) {
+
+               /* A queue got CBR underrun */
+               if (unlikely(pisr & (AR5K_ISR_QCBRURN))) {
                        *interrupt_mask |= AR5K_INT_QCBRURN;
-                       ah->ah_txq_isr |= AR5K_REG_MS(
-                                       ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
-                                       AR5K_SISR3_QCBRURN);
+                       ah->ah_txq_isr_qcburn |= AR5K_REG_MS(sisr3,
+                                               AR5K_SISR3_QCBRURN);
                }
-               if (data & AR5K_ISR_QTRIG) {
+
+               /* A queue got triggered */
+               if (unlikely(pisr & (AR5K_ISR_QTRIG))) {
                        *interrupt_mask |= AR5K_INT_QTRIG;
-                       ah->ah_txq_isr |= AR5K_REG_MS(
-                                       ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
-                                       AR5K_SISR4_QTRIG);
+                       ah->ah_txq_isr_qtrig |= AR5K_REG_MS(sisr4,
+                                               AR5K_SISR4_QTRIG);
                }
 
-               if (data & AR5K_ISR_TXOK)
-                       ah->ah_txq_isr |= AR5K_REG_MS(
-                                       ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
-                                       AR5K_SISR0_QCU_TXOK);
-
-               if (data & AR5K_ISR_TXDESC)
-                       ah->ah_txq_isr |= AR5K_REG_MS(
-                                       ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
-                                       AR5K_SISR0_QCU_TXDESC);
-
-               if (data & AR5K_ISR_TXERR)
-                       ah->ah_txq_isr |= AR5K_REG_MS(
-                                       ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
-                                       AR5K_SISR1_QCU_TXERR);
-
-               if (data & AR5K_ISR_TXEOL)
-                       ah->ah_txq_isr |= AR5K_REG_MS(
-                                       ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
-                                       AR5K_SISR1_QCU_TXEOL);
-
-               if (data & AR5K_ISR_TXURN)
-                       ah->ah_txq_isr |= AR5K_REG_MS(
-                                       ath5k_hw_reg_read(ah, AR5K_RAC_SISR2),
-                                       AR5K_SISR2_QCU_TXURN);
-       } else {
-               if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT
-                               | AR5K_ISR_HIUERR | AR5K_ISR_DPERR)))
-                       *interrupt_mask |= AR5K_INT_FATAL;
-
-               /*
-                * XXX: BMISS interrupts may occur after association.
-                * I found this on 5210 code but it needs testing. If this is
-                * true we should disable them before assoc and re-enable them
-                * after a successful assoc + some jiffies.
-                       interrupt_mask &= ~AR5K_INT_BMISS;
-                */
+               data = pisr;
        }
 
        /*
@@ -661,8 +732,7 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
 }
 
 /**
- * ath5k_hw_set_imr - Set interrupt mask
- *
+ * ath5k_hw_set_imr() - Set interrupt mask
  * @ah: The &struct ath5k_hw
  * @new_mask: The new interrupt mask to be set
  *
@@ -670,7 +740,8 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
  * ath5k_int bits to hw-specific bits to remove abstraction and writing
  * Interrupt Mask Register.
  */
-enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
+enum ath5k_int
+ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
 {
        enum ath5k_int old_mask, int_mask;
 
@@ -697,16 +768,14 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
                u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
                                & AR5K_SIMR2_QCU_TXURN;
 
+               /* Fatal interrupt abstraction for 5211+ */
                if (new_mask & AR5K_INT_FATAL) {
                        int_mask |= AR5K_IMR_HIUERR;
                        simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
                                | AR5K_SIMR2_DPERR);
                }
 
-               /*Beacon Not Ready*/
-               if (new_mask & AR5K_INT_BNR)
-                       int_mask |= AR5K_INT_BNR;
-
+               /* Misc beacon related interrupts */
                if (new_mask & AR5K_INT_TIM)
                        int_mask |= AR5K_IMR_TIM;
 
@@ -721,8 +790,9 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
                if (new_mask & AR5K_INT_CAB_TIMEOUT)
                        simr2 |= AR5K_SISR2_CAB_TIMEOUT;
 
-               if (new_mask & AR5K_INT_RX_DOPPLER)
-                       int_mask |= AR5K_IMR_RXDOPPLER;
+               /*Beacon Not Ready*/
+               if (new_mask & AR5K_INT_BNR)
+                       int_mask |= AR5K_INT_BNR;
 
                /* Note: Per queue interrupt masks
                 * are set via ath5k_hw_reset_tx_queue() (qcu.c) */
@@ -730,10 +800,12 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
                ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
 
        } else {
+               /* Fatal interrupt abstraction for 5210 */
                if (new_mask & AR5K_INT_FATAL)
                        int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
                                | AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
 
+               /* Only common interrupts left for 5210 (no SIMRs) */
                ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
        }
 
@@ -760,8 +832,7 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
 \********************/
 
 /**
- * ath5k_hw_dma_init - Initialize DMA unit
- *
+ * ath5k_hw_dma_init() - Initialize DMA unit
  * @ah: The &struct ath5k_hw
  *
  * Set DMA size and pre-enable interrupts
@@ -770,7 +841,8 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
  *
  * XXX: Save/restore RXDP/TXDP registers ?
  */
-void ath5k_hw_dma_init(struct ath5k_hw *ah)
+void
+ath5k_hw_dma_init(struct ath5k_hw *ah)
 {
        /*
         * Set Rx/Tx DMA Configuration
@@ -799,8 +871,7 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah)
 }
 
 /**
- * ath5k_hw_dma_stop - stop DMA unit
- *
+ * ath5k_hw_dma_stop() - stop DMA unit
  * @ah: The &struct ath5k_hw
  *
  * Stop tx/rx DMA and interrupts. Returns
@@ -810,7 +881,8 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah)
  * stuck frames on tx queues, only a reset
  * can fix that.
  */
-int ath5k_hw_dma_stop(struct ath5k_hw *ah)
+int
+ath5k_hw_dma_stop(struct ath5k_hw *ah)
 {
        int i, qmax, err;
        err = 0;
index 8592978..73d3dd8 100644 (file)
 #include "reg.h"
 #include "debug.h"
 
-/*
- * Set led state
+
+/**
+ * DOC: GPIO/LED functions
+ *
+ * Here we control the 6 bidirectional GPIO pins provided by the hw.
+ * We can set a GPIO pin to be an input or an output pin on GPIO control
+ * register and then read or set its status from GPIO data input/output
+ * registers.
+ *
+ * We also control the two LED pins provided by the hw, LED_0 is our
+ * "power" LED and LED_1 is our "network activity" LED but many scenarios
+ * are available from hw. Vendors might also provide LEDs connected to the
+ * GPIO pins, we handle them through the LED subsystem on led.c
+ */
+
+
+/**
+ * ath5k_hw_set_ledstate() - Set led state
+ * @ah: The &struct ath5k_hw
+ * @state: One of AR5K_LED_*
+ *
+ * Used to set the LED blinking state. This only
+ * works for the LED connected to the LED_0, LED_1 pins,
+ * not the GPIO based.
  */
-void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
+void
+ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
 {
        u32 led;
        /*5210 has different led mode handling*/
@@ -74,10 +97,13 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
                AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
 }
 
-/*
- * Set GPIO inputs
+/**
+ * ath5k_hw_set_gpio_input() - Set GPIO inputs
+ * @ah: The &struct ath5k_hw
+ * @gpio: GPIO pin to set as input
  */
-int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
+int
+ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
 {
        if (gpio >= AR5K_NUM_GPIO)
                return -EINVAL;
@@ -89,10 +115,13 @@ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
        return 0;
 }
 
-/*
- * Set GPIO outputs
+/**
+ * ath5k_hw_set_gpio_output() - Set GPIO outputs
+ * @ah: The &struct ath5k_hw
+ * @gpio: The GPIO pin to set as output
  */
-int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
+int
+ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
 {
        if (gpio >= AR5K_NUM_GPIO)
                return -EINVAL;
@@ -104,10 +133,13 @@ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
        return 0;
 }
 
-/*
- * Get GPIO state
+/**
+ * ath5k_hw_get_gpio() - Get GPIO state
+ * @ah: The &struct ath5k_hw
+ * @gpio: The GPIO pin to read
  */
-u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
+u32
+ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
 {
        if (gpio >= AR5K_NUM_GPIO)
                return 0xffffffff;
@@ -117,10 +149,14 @@ u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
                0x1;
 }
 
-/*
- * Set GPIO state
+/**
+ * ath5k_hw_set_gpio() - Set GPIO state
+ * @ah: The &struct ath5k_hw
+ * @gpio: The GPIO pin to set
+ * @val: Value to set (boolean)
  */
-int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
+int
+ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
 {
        u32 data;
 
@@ -138,10 +174,19 @@ int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
        return 0;
 }
 
-/*
- * Initialize the GPIO interrupt (RFKill switch)
+/**
+ * ath5k_hw_set_gpio_intr() - Initialize the GPIO interrupt (RFKill switch)
+ * @ah: The &struct ath5k_hw
+ * @gpio: The GPIO pin to use
+ * @interrupt_level: True to generate interrupt on active pin (high)
+ *
+ * This function is used to set up the GPIO interrupt for the hw RFKill switch.
+ * That switch is connected to a GPIO pin and it's number is stored on EEPROM.
+ * It can either open or close the circuit to indicate that we should disable
+ * RF/Wireless to save power (we also get that from EEPROM).
  */
-void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
+void
+ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
                u32 interrupt_level)
 {
        u32 data;
index 1ffecc0..a1ea78e 100644 (file)
 #include "reg.h"
 #include "debug.h"
 
-/*
- * Mode-independent initial register writes
+/**
+ * struct ath5k_ini - Mode-independent initial register writes
+ * @ini_register: Register address
+ * @ini_value: Default value
+ * @ini_mode: 0 to write 1 to read (and clear)
  */
-
 struct ath5k_ini {
        u16     ini_register;
        u32     ini_value;
 
        enum {
                AR5K_INI_WRITE = 0,     /* Default */
-               AR5K_INI_READ = 1,      /* Cleared on read */
+               AR5K_INI_READ = 1,
        } ini_mode;
 };
 
-/*
- * Mode specific initial register values
+/**
+ * struct ath5k_ini_mode - Mode specific initial register values
+ * @mode_register: Register address
+ * @mode_value: Set of values for each enum ath5k_driver_mode
  */
-
 struct ath5k_ini_mode {
        u16     mode_register;
        u32     mode_value[3];
@@ -386,11 +389,10 @@ static const struct ath5k_ini ar5211_ini[] = {
 
 /* Initial mode-specific settings for AR5211
  * 5211 supports OFDM-only g (draft g) but we
- * need to test it !
- */
+ * need to test it ! */
 static const struct ath5k_ini_mode ar5211_ini_mode[] = {
        { AR5K_TXCFG,
-       /*      A/XR          B           G       */
+       /*      A          B           G       */
           { 0x00000015, 0x0000001d, 0x00000015 } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(0),
           { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
@@ -460,7 +462,7 @@ static const struct ath5k_ini_mode ar5211_ini_mode[] = {
           { 0x00000010, 0x00000010, 0x00000010 } },
 };
 
-/* Initial register settings for AR5212 */
+/* Initial register settings for AR5212 and newer chips */
 static const struct ath5k_ini ar5212_ini_common_start[] = {
        { AR5K_RXDP,            0x00000000 },
        { AR5K_RXCFG,           0x00000005 },
@@ -724,7 +726,8 @@ static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
           { 0x00000000, 0x00000000, 0x00000108 } },
 };
 
-/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */
+/* Initial mode-specific settings for AR5212 + RF5111
+ * (Written after ar5212_ini) */
 static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
        { AR5K_TXCFG,
        /*      A/XR          B           G       */
@@ -757,6 +760,7 @@ static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
           { 0x1883800a, 0x1873800a, 0x1883800a } },
 };
 
+/* Common for all modes */
 static const struct ath5k_ini rf5111_ini_common_end[] = {
        { AR5K_DCU_FP,          0x00000000 },
        { AR5K_PHY_AGC,         0x00000000 },
@@ -774,7 +778,9 @@ static const struct ath5k_ini rf5111_ini_common_end[] = {
        { 0xa23c,               0x13c889af },
 };
 
-/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
+
+/* Initial mode-specific settings for AR5212 + RF5112
+ * (Written after ar5212_ini) */
 static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
        { AR5K_TXCFG,
        /*      A/XR          B           G       */
@@ -825,7 +831,9 @@ static const struct ath5k_ini rf5112_ini_common_end[] = {
        { 0xa23c,               0x13c889af },
 };
 
-/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
+
+/* Initial mode-specific settings for RF5413/5414
+ * (Written after ar5212_ini) */
 static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
        { AR5K_TXCFG,
        /*      A/XR          B           G       */
@@ -963,7 +971,8 @@ static const struct ath5k_ini rf5413_ini_common_end[] = {
        { 0xa384, 0xf3307ff0 },
 };
 
-/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */
+/* Initial mode-specific settings for RF2413/2414
+ * (Written after ar5212_ini) */
 /* XXX: a mode ? */
 static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
        { AR5K_TXCFG,
@@ -1085,7 +1094,8 @@ static const struct ath5k_ini rf2413_ini_common_end[] = {
        { 0xa384, 0xf3307ff0 },
 };
 
-/* Initial mode-specific settings for RF2425 (Written after ar5212_ini) */
+/* Initial mode-specific settings for RF2425
+ * (Written after ar5212_ini) */
 /* XXX: a mode ? */
 static const struct ath5k_ini_mode rf2425_ini_mode_end[] = {
        { AR5K_TXCFG,
@@ -1357,10 +1367,15 @@ static const struct ath5k_ini rf5112_ini_bbgain[] = {
 };
 
 
-/*
- * Write initial register dump
+/**
+ * ath5k_hw_ini_registers() - Write initial register dump common for all modes
+ * @ah: The &struct ath5k_hw
+ * @size: Dump size
+ * @ini_regs: The array of &struct ath5k_ini
+ * @skip_pcu: Skip PCU registers
  */
-static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
+static void
+ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
                const struct ath5k_ini *ini_regs, bool skip_pcu)
 {
        unsigned int i;
@@ -1388,7 +1403,15 @@ static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
        }
 }
 
-static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
+/**
+ * ath5k_hw_ini_mode_registers() - Write initial mode-specific register dump
+ * @ah: The &struct ath5k_hw
+ * @size: Dump size
+ * @ini_mode: The array of &struct ath5k_ini_mode
+ * @mode: One of enum ath5k_driver_mode
+ */
+static void
+ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
                unsigned int size, const struct ath5k_ini_mode *ini_mode,
                u8 mode)
 {
@@ -1402,7 +1425,17 @@ static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
 
 }
 
-int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu)
+/**
+ * ath5k_hw_write_initvals() - Write initial chip-specific register dump
+ * @ah: The &struct ath5k_hw
+ * @mode: One of enum ath5k_driver_mode
+ * @skip_pcu: Skip PCU registers
+ *
+ * Write initial chip-specific register dump, to get the chipset on a
+ * clean and ready-to-work state after warm reset.
+ */
+int
+ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu)
 {
        /*
         * Write initial register settings
index dfa48eb..849fa06 100644 (file)
@@ -98,7 +98,7 @@ ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
                                        0xffff);
                        return true;
                }
-               udelay(15);
+               usleep_range(15, 20);
        }
 
        return false;
index a7eafa3..cebfd6f 100644 (file)
 #include "reg.h"
 #include "debug.h"
 
-/*
+/**
+ * DOC: Protocol Control Unit (PCU) functions
+ *
+ * Protocol control unit is responsible to maintain various protocol
+ * properties before a frame is send and after a frame is received to/from
+ * baseband. To be more specific, PCU handles:
+ *
+ * - Buffering of RX and TX frames (after QCU/DCUs)
+ *
+ * - Encrypting and decrypting (using the built-in engine)
+ *
+ * - Generating ACKs, RTS/CTS frames
+ *
+ * - Maintaining TSF
+ *
+ * - FCS
+ *
+ * - Updating beacon data (with TSF etc)
+ *
+ * - Generating virtual CCA
+ *
+ * - RX/Multicast filtering
+ *
+ * - BSSID filtering
+ *
+ * - Various statistics
+ *
+ * -Different operating modes: AP, STA, IBSS
+ *
+ * Note: Most of these functions can be tweaked/bypassed so you can do
+ * them on sw above for debugging or research. For more infos check out PCU
+ * registers on reg.h.
+ */
+
+/**
+ * DOC: ACK rates
+ *
  * AR5212+ can use higher rates for ack transmission
  * based on current tx rate instead of the base rate.
  * It does this to better utilize channel usage.
- * This is a mapping between G rates (that cover both
+ * There is a mapping between G rates (that cover both
  * CCK and OFDM) and ack rates that we use when setting
  * rate -> duration table. This mapping is hw-based so
  * don't change anything.
@@ -63,17 +99,18 @@ static const unsigned int ack_rates_high[] =
 \*******************/
 
 /**
- * ath5k_hw_get_frame_duration - Get tx time of a frame
- *
+ * ath5k_hw_get_frame_duration() - Get tx time of a frame
  * @ah: The &struct ath5k_hw
  * @len: Frame's length in bytes
  * @rate: The @struct ieee80211_rate
+ * @shortpre: Indicate short preample
  *
  * Calculate tx duration of a frame given it's rate and length
  * It extends ieee80211_generic_frame_duration for non standard
  * bwmodes.
  */
-int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
+int
+ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
                int len, struct ieee80211_rate *rate, bool shortpre)
 {
        int sifs, preamble, plcp_bits, sym_time;
@@ -129,11 +166,11 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
 }
 
 /**
- * ath5k_hw_get_default_slottime - Get the default slot time for current mode
- *
+ * ath5k_hw_get_default_slottime() - Get the default slot time for current mode
  * @ah: The &struct ath5k_hw
  */
-unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
+unsigned int
+ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
 {
        struct ieee80211_channel *channel = ah->ah_current_channel;
        unsigned int slot_time;
@@ -160,11 +197,11 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
 }
 
 /**
- * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
- *
+ * ath5k_hw_get_default_sifs() - Get the default SIFS for current mode
  * @ah: The &struct ath5k_hw
  */
-unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
+unsigned int
+ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
 {
        struct ieee80211_channel *channel = ah->ah_current_channel;
        unsigned int sifs;
@@ -191,17 +228,17 @@ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
 }
 
 /**
- * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics)
- *
+ * ath5k_hw_update_mib_counters() - Update MIB counters (mac layer statistics)
  * @ah: The &struct ath5k_hw
  *
  * Reads MIB counters from PCU and updates sw statistics. Is called after a
  * MIB interrupt, because one of these counters might have reached their maximum
  * and triggered the MIB interrupt, to let us read and clear the counter.
  *
- * Is called in interrupt context!
+ * NOTE: Is called in interrupt context!
  */
-void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
+void
+ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
 {
        struct ath5k_statistics *stats = &ah->stats;
 
@@ -219,10 +256,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
 \******************/
 
 /**
- * ath5k_hw_write_rate_duration - fill rate code to duration table
- *
- * @ah: the &struct ath5k_hw
- * @mode: one of enum ath5k_driver_mode
+ * ath5k_hw_write_rate_duration() - Fill rate code to duration table
+ * @ah: The &struct ath5k_hw
  *
  * Write the rate code to duration table upon hw reset. This is a helper for
  * ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on
@@ -236,7 +271,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
  * that include all OFDM and CCK rates.
  *
  */
-static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
+static inline void
+ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
 {
        struct ieee80211_rate *rate;
        unsigned int i;
@@ -280,12 +316,12 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
 }
 
 /**
- * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
- *
+ * ath5k_hw_set_ack_timeout() - Set ACK timeout on PCU
  * @ah: The &struct ath5k_hw
  * @timeout: Timeout in usec
  */
-static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
+static int
+ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
 {
        if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
                        <= timeout)
@@ -298,12 +334,12 @@ static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
 }
 
 /**
- * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
- *
+ * ath5k_hw_set_cts_timeout() - Set CTS timeout on PCU
  * @ah: The &struct ath5k_hw
  * @timeout: Timeout in usec
  */
-static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
+static int
+ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
 {
        if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
                        <= timeout)
@@ -321,14 +357,14 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
 \*******************/
 
 /**
- * ath5k_hw_set_lladdr - Set station id
- *
+ * ath5k_hw_set_lladdr() - Set station id
  * @ah: The &struct ath5k_hw
- * @mac: The card's mac address
+ * @mac: The card's mac address (array of octets)
  *
  * Set station id on hw using the provided mac address
  */
-int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
+int
+ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
 {
        struct ath_common *common = ath5k_hw_common(ah);
        u32 low_id, high_id;
@@ -349,14 +385,14 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
 }
 
 /**
- * ath5k_hw_set_bssid - Set current BSSID on hw
- *
+ * ath5k_hw_set_bssid() - Set current BSSID on hw
  * @ah: The &struct ath5k_hw
  *
  * Sets the current BSSID and BSSID mask we have from the
  * common struct into the hardware
  */
-void ath5k_hw_set_bssid(struct ath5k_hw *ah)
+void
+ath5k_hw_set_bssid(struct ath5k_hw *ah)
 {
        struct ath_common *common = ath5k_hw_common(ah);
        u16 tim_offset = 0;
@@ -389,7 +425,23 @@ void ath5k_hw_set_bssid(struct ath5k_hw *ah)
        ath5k_hw_enable_pspoll(ah, NULL, 0);
 }
 
-void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
+/**
+ * ath5k_hw_set_bssid_mask() - Filter out bssids we listen
+ * @ah: The &struct ath5k_hw
+ * @mask: The BSSID mask to set (array of octets)
+ *
+ * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
+ * which bits of the interface's MAC address should be looked at when trying
+ * to decide which packets to ACK. In station mode and AP mode with a single
+ * BSS every bit matters since we lock to only one BSS. In AP mode with
+ * multiple BSSes (virtual interfaces) not every bit matters because hw must
+ * accept frames for all BSSes and so we tweak some bits of our mac address
+ * in order to have multiple BSSes.
+ *
+ * For more information check out ../hw.c of the common ath module.
+ */
+void
+ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
 {
        struct ath_common *common = ath5k_hw_common(ah);
 
@@ -400,18 +452,21 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
                ath_hw_setbssidmask(common);
 }
 
-/*
- * Set multicast filter
+/**
+ * ath5k_hw_set_mcast_filter() - Set multicast filter
+ * @ah: The &struct ath5k_hw
+ * @filter0: Lower 32bits of muticast filter
+ * @filter1: Higher 16bits of multicast filter
  */
-void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
+void
+ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
 {
        ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
        ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
 }
 
 /**
- * ath5k_hw_get_rx_filter - Get current rx filter
- *
+ * ath5k_hw_get_rx_filter() - Get current rx filter
  * @ah: The &struct ath5k_hw
  *
  * Returns the RX filter by reading rx filter and
@@ -420,7 +475,8 @@ void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
  * and pass to the driver. For a list of frame types
  * check out reg.h.
  */
-u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
+u32
+ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
 {
        u32 data, filter = 0;
 
@@ -440,8 +496,7 @@ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
 }
 
 /**
- * ath5k_hw_set_rx_filter - Set rx filter
- *
+ * ath5k_hw_set_rx_filter() - Set rx filter
  * @ah: The &struct ath5k_hw
  * @filter: RX filter mask (see reg.h)
  *
@@ -449,7 +504,8 @@ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
  * register on 5212 and newer chips so that we have proper PHY
  * error reporting.
  */
-void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
+void
+ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
 {
        u32 data = 0;
 
@@ -493,13 +549,13 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
 #define ATH5K_MAX_TSF_READ 10
 
 /**
- * ath5k_hw_get_tsf64 - Get the full 64bit TSF
- *
+ * ath5k_hw_get_tsf64() - Get the full 64bit TSF
  * @ah: The &struct ath5k_hw
  *
  * Returns the current TSF
  */
-u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
+u64
+ath5k_hw_get_tsf64(struct ath5k_hw *ah)
 {
        u32 tsf_lower, tsf_upper1, tsf_upper2;
        int i;
@@ -536,28 +592,30 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
        return ((u64)tsf_upper1 << 32) | tsf_lower;
 }
 
+#undef ATH5K_MAX_TSF_READ
+
 /**
- * ath5k_hw_set_tsf64 - Set a new 64bit TSF
- *
+ * ath5k_hw_set_tsf64() - Set a new 64bit TSF
  * @ah: The &struct ath5k_hw
  * @tsf64: The new 64bit TSF
  *
  * Sets the new TSF
  */
-void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
+void
+ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
 {
        ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
        ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
 }
 
 /**
- * ath5k_hw_reset_tsf - Force a TSF reset
- *
+ * ath5k_hw_reset_tsf() - Force a TSF reset
  * @ah: The &struct ath5k_hw
  *
  * Forces a TSF reset on PCU
  */
-void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
+void
+ath5k_hw_reset_tsf(struct ath5k_hw *ah)
 {
        u32 val;
 
@@ -573,10 +631,17 @@ void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
        ath5k_hw_reg_write(ah, val, AR5K_BEACON);
 }
 
-/*
- * Initialize beacon timers
+/**
+ * ath5k_hw_init_beacon_timers() - Initialize beacon timers
+ * @ah: The &struct ath5k_hw
+ * @next_beacon: Next TBTT
+ * @interval: Current beacon interval
+ *
+ * This function is used to initialize beacon timers based on current
+ * operation mode and settings.
  */
-void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
+void
+ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
 {
        u32 timer1, timer2, timer3;
 
@@ -655,8 +720,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
 }
 
 /**
- * ath5k_check_timer_win - Check if timer B is timer A + window
- *
+ * ath5k_check_timer_win() - Check if timer B is timer A + window
  * @a: timer a (before b)
  * @b: timer b (after a)
  * @window: difference between a and b
@@ -686,12 +750,11 @@ ath5k_check_timer_win(int a, int b, int window, int intval)
 }
 
 /**
- * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct
- *
+ * ath5k_hw_check_beacon_timers() - Check if the beacon timers are correct
  * @ah: The &struct ath5k_hw
  * @intval: beacon interval
  *
- * This is a workaround for IBSS mode:
+ * This is a workaround for IBSS mode
  *
  * The need for this function arises from the fact that we have 4 separate
  * HW timer registers (TIMER0 - TIMER3), which are closely related to the
@@ -746,14 +809,14 @@ ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval)
 }
 
 /**
- * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
- *
+ * ath5k_hw_set_coverage_class() - Set IEEE 802.11 coverage class
  * @ah: The &struct ath5k_hw
  * @coverage_class: IEEE 802.11 coverage class number
  *
  * Sets IFS intervals and ACK/CTS timeouts for given coverage class.
  */
-void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
+void
+ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
 {
        /* As defined by IEEE 802.11-2007 17.3.8.6 */
        int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class;
@@ -772,8 +835,7 @@ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
 \***************************/
 
 /**
- * ath5k_hw_start_rx_pcu - Start RX engine
- *
+ * ath5k_hw_start_rx_pcu() - Start RX engine
  * @ah: The &struct ath5k_hw
  *
  * Starts RX engine on PCU so that hw can process RXed frames
@@ -781,32 +843,33 @@ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
  *
  * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
  */
-void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
+void
+ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
 {
        AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
 }
 
 /**
- * at5k_hw_stop_rx_pcu - Stop RX engine
- *
+ * at5k_hw_stop_rx_pcu() - Stop RX engine
  * @ah: The &struct ath5k_hw
  *
  * Stops RX engine on PCU
  */
-void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
+void
+ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
 {
        AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
 }
 
 /**
- * ath5k_hw_set_opmode - Set PCU operating mode
- *
+ * ath5k_hw_set_opmode() - Set PCU operating mode
  * @ah: The &struct ath5k_hw
- * @op_mode: &enum nl80211_iftype operating mode
+ * @op_mode: One of enum nl80211_iftype
  *
  * Configure PCU for the various operating modes (AP/STA etc)
  */
-int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
+int
+ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
 {
        struct ath_common *common = ath5k_hw_common(ah);
        u32 pcu_reg, beacon_reg, low_id, high_id;
@@ -873,8 +936,17 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
        return 0;
 }
 
-void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
-                                                               u8 mode)
+/**
+ * ath5k_hw_pcu_init() - Initialize PCU
+ * @ah: The &struct ath5k_hw
+ * @op_mode: One of enum nl80211_iftype
+ * @mode: One of enum ath5k_driver_mode
+ *
+ * This function is used to initialize PCU by setting current
+ * operation mode and various other settings.
+ */
+void
+ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
 {
        /* Set bssid and bssid mask */
        ath5k_hw_set_bssid(ah);
index 01cb72d..e1f8613 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * PHY functions
- *
  * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
  * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
  * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
  *
  */
 
+/***********************\
+* PHY related functions *
+\***********************/
+
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <asm/unaligned.h>
 #include "../regd.h"
 
 
+/**
+ * DOC: PHY related functions
+ *
+ * Here we handle the low-level functions related to baseband
+ * and analog frontend (RF) parts. This is by far the most complex
+ * part of the hw code so make sure you know what you are doing.
+ *
+ * Here is a list of what this is all about:
+ *
+ * - Channel setting/switching
+ *
+ * - Automatic Gain Control (AGC) calibration
+ *
+ * - Noise Floor calibration
+ *
+ * - I/Q imbalance calibration (QAM correction)
+ *
+ * - Calibration due to thermal changes (gain_F)
+ *
+ * - Spur noise mitigation
+ *
+ * - RF/PHY initialization for the various operating modes and bwmodes
+ *
+ * - Antenna control
+ *
+ * - TX power control per channel/rate/packet type
+ *
+ * Also have in mind we never got documentation for most of these
+ * functions, what we have comes mostly from Atheros's code, reverse
+ * engineering and patent docs/presentations etc.
+ */
+
+
 /******************\
 * Helper functions *
 \******************/
 
-/*
- * Get the PHY Chip revision
+/**
+ * ath5k_hw_radio_revision() - Get the PHY Chip revision
+ * @ah: The &struct ath5k_hw
+ * @band: One of enum ieee80211_band
+ *
+ * Returns the revision number of a 2GHz, 5GHz or single chip
+ * radio.
  */
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
+u16
+ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
 {
        unsigned int i;
        u32 srev;
@@ -58,7 +99,7 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
                return 0;
        }
 
-       mdelay(2);
+       usleep_range(2000, 2500);
 
        /* ...wait until PHY is ready and read the selected radio revision */
        ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
@@ -81,10 +122,16 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
        return ret;
 }
 
-/*
- * Check if a channel is supported
+/**
+ * ath5k_channel_ok() - Check if a channel is supported by the hw
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
+ * Note: We don't do any regulatory domain checks here, it's just
+ * a sanity check.
  */
-bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel)
+bool
+ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel)
 {
        u16 freq = channel->center_freq;
 
@@ -101,7 +148,13 @@ bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel)
        return false;
 }
 
-bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
+/**
+ * ath5k_hw_chan_has_spur_noise() - Check if channel is sensitive to spur noise
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ */
+bool
+ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
                                struct ieee80211_channel *channel)
 {
        u8 refclk_freq;
@@ -122,11 +175,20 @@ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
                return false;
 }
 
-/*
- * Used to modify RF Banks before writing them to AR5K_RF_BUFFER
+/**
+ * ath5k_hw_rfb_op() - Perform an operation on the given RF Buffer
+ * @ah: The &struct ath5k_hw
+ * @rf_regs: The struct ath5k_rf_reg
+ * @val: New value
+ * @reg_id: RF register ID
+ * @set: Indicate we need to swap data
+ *
+ * This is an internal function used to modify RF Banks before
+ * writing them to AR5K_RF_BUFFER. Check out rfbuffer.h for more
+ * infos.
  */
-static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
-                                       const struct ath5k_rf_reg *rf_regs,
+static unsigned int
+ath5k_hw_rfb_op(struct ath5k_hw *ah, const struct ath5k_rf_reg *rf_regs,
                                        u32 val, u8 reg_id, bool set)
 {
        const struct ath5k_rf_reg *rfreg = NULL;
@@ -204,8 +266,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
 }
 
 /**
- * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
- *
+ * ath5k_hw_write_ofdm_timings() - set OFDM timings on AR5212
  * @ah: the &struct ath5k_hw
  * @channel: the currently set channel upon reset
  *
@@ -216,10 +277,11 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
  * mantissa and provide these values on hw.
  *
  * For more infos i think this patent is related
- * http://www.freepatentsonline.com/7184495.html
+ * "http://www.freepatentsonline.com/7184495.html"
  */
-static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
-       struct ieee80211_channel *channel)
+static inline int
+ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
+                               struct ieee80211_channel *channel)
 {
        /* Get exponent and mantissa and set it */
        u32 coef_scaled, coef_exp, coef_man,
@@ -278,6 +340,10 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
        return 0;
 }
 
+/**
+ * ath5k_hw_phy_disable() - Disable PHY
+ * @ah: The &struct ath5k_hw
+ */
 int ath5k_hw_phy_disable(struct ath5k_hw *ah)
 {
        /*Just a try M.F.*/
@@ -286,10 +352,13 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah)
        return 0;
 }
 
-/*
- * Wait for synth to settle
+/**
+ * ath5k_hw_wait_for_synth() - Wait for synth to settle
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
  */
-static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
+static void
+ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
                        struct ieee80211_channel *channel)
 {
        /*
@@ -308,9 +377,9 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
                        delay = delay << 2;
                /* XXX: /2 on turbo ? Let's be safe
                 * for now */
-               udelay(100 + delay);
+               usleep_range(100 + delay, 100 + (2 * delay));
        } else {
-               mdelay(1);
+               usleep_range(1000, 1500);
        }
 }
 
@@ -319,7 +388,9 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
 * RF Gain optimization *
 \**********************/
 
-/*
+/**
+ * DOC: RF Gain optimization
+ *
  * This code is used to optimize RF gain on different environments
  * (temperature mostly) based on feedback from a power detector.
  *
@@ -328,22 +399,22 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
  * no gain optimization ladder-.
  *
  * For more infos check out this patent doc
- * http://www.freepatentsonline.com/7400691.html
+ * "http://www.freepatentsonline.com/7400691.html"
  *
  * This paper describes power drops as seen on the receiver due to
  * probe packets
- * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
- * %20of%20Power%20Control.pdf
+ * "http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
+ * %20of%20Power%20Control.pdf"
  *
  * And this is the MadWiFi bug entry related to the above
- * http://madwifi-project.org/ticket/1659
+ * "http://madwifi-project.org/ticket/1659"
  * with various measurements and diagrams
- *
- * TODO: Deal with power drops due to probes by setting an appropriate
- * tx power on the probe packets ! Make this part of the calibration process.
  */
 
-/* Initialize ah_gain during attach */
+/**
+ * ath5k_hw_rfgain_opt_init() - Initialize ah_gain during attach
+ * @ah: The &struct ath5k_hw
+ */
 int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
 {
        /* Initialize the gain optimization values */
@@ -367,17 +438,21 @@ int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
        return 0;
 }
 
-/* Schedule a gain probe check on the next transmitted packet.
+/**
+ * ath5k_hw_request_rfgain_probe() - Request a PAPD probe packet
+ * @ah: The &struct ath5k_hw
+ *
+ * Schedules a gain probe check on the next transmitted packet.
  * That means our next packet is going to be sent with lower
  * tx power and a Peak to Average Power Detector (PAPD) will try
  * to measure the gain.
  *
- * XXX:  How about forcing a tx packet (bypassing PCU arbitrator etc)
+ * TODO: Force a tx packet (bypassing PCU arbitrator etc)
  * just after we enable the probe so that we don't mess with
- * standard traffic ? Maybe it's time to use sw interrupts and
- * a probe tasklet !!!
+ * standard traffic.
  */
-static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
+static void
+ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
 {
 
        /* Skip if gain calibration is inactive or
@@ -395,9 +470,15 @@ static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
 
 }
 
-/* Calculate gain_F measurement correction
- * based on the current step for RF5112 rev. 2 */
-static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
+/**
+ * ath5k_hw_rf_gainf_corr() - Calculate Gain_F measurement correction
+ * @ah: The &struct ath5k_hw
+ *
+ * Calculate Gain_F measurement correction
+ * based on the current step for RF5112 rev. 2
+ */
+static u32
+ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
 {
        u32 mix, step;
        u32 *rf;
@@ -450,11 +531,19 @@ static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
        return ah->ah_gain.g_f_corr;
 }
 
-/* Check if current gain_F measurement is in the range of our
+/**
+ * ath5k_hw_rf_check_gainf_readback() - Validate Gain_F feedback from detector
+ * @ah: The &struct ath5k_hw
+ *
+ * Check if current gain_F measurement is in the range of our
  * power detector windows. If we get a measurement outside range
  * we know it's not accurate (detectors can't measure anything outside
- * their detection window) so we must ignore it */
-static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
+ * their detection window) so we must ignore it.
+ *
+ * Returns true if readback was O.K. or false on failure
+ */
+static bool
+ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
 {
        const struct ath5k_rf_reg *rf_regs;
        u32 step, mix_ovr, level[4];
@@ -506,9 +595,15 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
                        ah->ah_gain.g_current <= level[3]);
 }
 
-/* Perform gain_F adjustment by choosing the right set
- * of parameters from RF gain optimization ladder */
-static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
+/**
+ * ath5k_hw_rf_gainf_adjust() - Perform Gain_F adjustment
+ * @ah: The &struct ath5k_hw
+ *
+ * Choose the right target gain based on current gain
+ * and RF gain optimization ladder
+ */
+static s8
+ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
 {
        const struct ath5k_gain_opt *go;
        const struct ath5k_gain_opt_step *g_step;
@@ -572,13 +667,18 @@ done:
        return ret;
 }
 
-/* Main callback for thermal RF gain calibration engine
+/**
+ * ath5k_hw_gainf_calibrate() - Do a gain_F calibration
+ * @ah: The &struct ath5k_hw
+ *
+ * Main callback for thermal RF gain calibration engine
  * Check for a new gain reading and schedule an adjustment
  * if needed.
  *
- * TODO: Use sw interrupt to schedule reset if gain_F needs
- * adjustment */
-enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
+ * Returns one of enum ath5k_rfgain codes
+ */
+enum ath5k_rfgain
+ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
 {
        u32 data, type;
        struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
@@ -638,10 +738,18 @@ done:
        return ah->ah_gain.g_state;
 }
 
-/* Write initial RF gain table to set the RF sensitivity
- * this one works on all RF chips and has nothing to do
- * with gain_F calibration */
-static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band)
+/**
+ * ath5k_hw_rfgain_init() - Write initial RF gain settings to hw
+ * @ah: The &struct ath5k_hw
+ * @band: One of enum ieee80211_band
+ *
+ * Write initial RF gain table to set the RF sensitivity.
+ *
+ * NOTE: This one works on all RF chips and has nothing to do
+ * with Gain_F calibration
+ */
+static int
+ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band)
 {
        const struct ath5k_ini_rfgain *ath5k_rfg;
        unsigned int i, size, index;
@@ -688,16 +796,23 @@ static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, enum ieee80211_band band)
 }
 
 
-
 /********************\
 * RF Registers setup *
 \********************/
 
-/*
- * Setup RF registers by writing RF buffer on hw
+/**
+ * ath5k_hw_rfregs_init() - Initialize RF register settings
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ * @mode: One of enum ath5k_driver_mode
+ *
+ * Setup RF registers by writing RF buffer on hw. For
+ * more infos on this, check out rfbuffer.h
  */
-static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
-       struct ieee80211_channel *channel, unsigned int mode)
+static int
+ath5k_hw_rfregs_init(struct ath5k_hw *ah,
+                       struct ieee80211_channel *channel,
+                       unsigned int mode)
 {
        const struct ath5k_rf_reg *rf_regs;
        const struct ath5k_ini_rfbuffer *ini_rfb;
@@ -1055,19 +1170,18 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
   PHY/RF channel functions
 \**************************/
 
-/*
- * Conversion needed for RF5110
+/**
+ * ath5k_hw_rf5110_chan2athchan() - Convert channel freq on RF5110
+ * @channel: The &struct ieee80211_channel
+ *
+ * Map channel frequency to IEEE channel number and convert it
+ * to an internal channel value used by the RF5110 chipset.
  */
-static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel)
+static u32
+ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel)
 {
        u32 athchan;
 
-       /*
-        * Convert IEEE channel/MHz to an internal channel value used
-        * by the AR5210 chipset. This has not been verified with
-        * newer chipsets like the AR5212A who have a completely
-        * different RF/PHY part.
-        */
        athchan = (ath5k_hw_bitswap(
                        (ieee80211_frequency_to_channel(
                                channel->center_freq) - 24) / 2, 5)
@@ -1075,10 +1189,13 @@ static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel)
        return athchan;
 }
 
-/*
- * Set channel on RF5110
+/**
+ * ath5k_hw_rf5110_channel() - Set channel frequency on RF5110
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
  */
-static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
+static int
+ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
                struct ieee80211_channel *channel)
 {
        u32 data;
@@ -1089,15 +1206,23 @@ static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
        data = ath5k_hw_rf5110_chan2athchan(channel);
        ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER);
        ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0);
-       mdelay(1);
+       usleep_range(1000, 1500);
 
        return 0;
 }
 
-/*
- * Conversion needed for 5111
+/**
+ * ath5k_hw_rf5111_chan2athchan() - Handle 2GHz channels on RF5111/2111
+ * @ieee: IEEE channel number
+ * @athchan: The &struct ath5k_athchan_2ghz
+ *
+ * In order to enable the RF2111 frequency converter on RF5111/2111 setups
+ * we need to add some offsets and extra flags to the data values we pass
+ * on to the PHY. So for every 2GHz channel this function gets called
+ * to do the conversion.
  */
-static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
+static int
+ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
                struct ath5k_athchan_2ghz *athchan)
 {
        int channel;
@@ -1123,10 +1248,13 @@ static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
        return 0;
 }
 
-/*
- * Set channel on 5111
+/**
+ * ath5k_hw_rf5111_channel() - Set channel frequency on RF5111/2111
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
  */
-static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
+static int
+ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
                struct ieee80211_channel *channel)
 {
        struct ath5k_athchan_2ghz ath5k_channel_2ghz;
@@ -1171,10 +1299,20 @@ static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
        return 0;
 }
 
-/*
- * Set channel on 5112 and newer
+/**
+ * ath5k_hw_rf5112_channel() - Set channel frequency on 5112 and newer
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
+ * On RF5112/2112 and newer we don't need to do any conversion.
+ * We pass the frequency value after a few modifications to the
+ * chip directly.
+ *
+ * NOTE: Make sure channel frequency given is within our range or else
+ * we might damage the chip ! Use ath5k_channel_ok before calling this one.
  */
-static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
+static int
+ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
                struct ieee80211_channel *channel)
 {
        u32 data, data0, data1, data2;
@@ -1183,17 +1321,37 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
        data = data0 = data1 = data2 = 0;
        c = channel->center_freq;
 
+       /* My guess based on code:
+        * 2GHz RF has 2 synth modes, one with a Local Oscillator
+        * at 2224Hz and one with a LO at 2192Hz. IF is 1520Hz
+        * (3040/2). data0 is used to set the PLL divider and data1
+        * selects synth mode. */
        if (c < 4800) {
+               /* Channel 14 and all frequencies with 2Hz spacing
+                * below/above (non-standard channels) */
                if (!((c - 2224) % 5)) {
+                       /* Same as (c - 2224) / 5 */
                        data0 = ((2 * (c - 704)) - 3040) / 10;
                        data1 = 1;
+               /* Channel 1 and all frequencies with 5Hz spacing
+                * below/above (standard channels without channel 14) */
                } else if (!((c - 2192) % 5)) {
+                       /* Same as (c - 2192) / 5 */
                        data0 = ((2 * (c - 672)) - 3040) / 10;
                        data1 = 0;
                } else
                        return -EINVAL;
 
                data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
+       /* This is more complex, we have a single synthesizer with
+        * 4 reference clock settings (?) based on frequency spacing
+        * and set using data2. LO is at 4800Hz and data0 is again used
+        * to set some divider.
+        *
+        * NOTE: There is an old atheros presentation at Stanford
+        * that mentions a method called dual direct conversion
+        * with 1GHz sliding IF for RF5110. Maybe that's what we
+        * have here, or an updated version. */
        } else if ((c % 5) != 2 || c > 5435) {
                if (!(c % 20) && c >= 5120) {
                        data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
@@ -1219,10 +1377,16 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
        return 0;
 }
 
-/*
- * Set the channel on the RF2425
+/**
+ * ath5k_hw_rf2425_channel() - Set channel frequency on RF2425
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
+ * AR2425/2417 have a different 2GHz RF so code changes
+ * a little bit from RF5112.
  */
-static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
+static int
+ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
                struct ieee80211_channel *channel)
 {
        u32 data, data0, data2;
@@ -1258,10 +1422,16 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
        return 0;
 }
 
-/*
- * Set a channel on the radio chip
+/**
+ * ath5k_hw_channel() - Set a channel on the radio chip
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
+ * This is the main function called to set a channel on the
+ * radio chip based on the radio chip version.
  */
-static int ath5k_hw_channel(struct ath5k_hw *ah,
+static int
+ath5k_hw_channel(struct ath5k_hw *ah,
                struct ieee80211_channel *channel)
 {
        int ret;
@@ -1313,11 +1483,46 @@ static int ath5k_hw_channel(struct ath5k_hw *ah,
        return 0;
 }
 
+
 /*****************\
   PHY calibration
 \*****************/
 
-static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
+/**
+ * DOC: PHY Calibration routines
+ *
+ * Noise floor calibration: When we tell the hardware to
+ * perform a noise floor calibration by setting the
+ * AR5K_PHY_AGCCTL_NF bit on AR5K_PHY_AGCCTL, it will periodically
+ * sample-and-hold the minimum noise level seen at the antennas.
+ * This value is then stored in a ring buffer of recently measured
+ * noise floor values so we have a moving window of the last few
+ * samples. The median of the values in the history is then loaded
+ * into the hardware for its own use for RSSI and CCA measurements.
+ * This type of calibration doesn't interfere with traffic.
+ *
+ * AGC calibration: When we tell the hardware to perform
+ * an AGC (Automatic Gain Control) calibration by setting the
+ * AR5K_PHY_AGCCTL_CAL, hw disconnects the antennas and does
+ * a calibration on the DC offsets of ADCs. During this period
+ * rx/tx gets disabled so we have to deal with it on the driver
+ * part.
+ *
+ * I/Q calibration: When we tell the hardware to perform
+ * an I/Q calibration, it tries to correct I/Q imbalance and
+ * fix QAM constellation by sampling data from rxed frames.
+ * It doesn't interfere with traffic.
+ *
+ * For more infos on AGC and I/Q calibration check out patent doc
+ * #03/094463.
+ */
+
+/**
+ * ath5k_hw_read_measured_noise_floor() - Read measured NF from hw
+ * @ah: The &struct ath5k_hw
+ */
+static s32
+ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
 {
        s32 val;
 
@@ -1325,7 +1530,12 @@ static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
        return sign_extend32(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 8);
 }
 
-void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
+/**
+ * ath5k_hw_init_nfcal_hist() - Initialize NF calibration history buffer
+ * @ah: The &struct ath5k_hw
+ */
+void
+ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
 {
        int i;
 
@@ -1334,6 +1544,11 @@ void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
                ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
 }
 
+/**
+ * ath5k_hw_update_nfcal_hist() - Update NF calibration history buffer
+ * @ah: The &struct ath5k_hw
+ * @noise_floor: The NF we got from hw
+ */
 static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
 {
        struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist;
@@ -1341,7 +1556,12 @@ static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
        hist->nfval[hist->index] = noise_floor;
 }
 
-static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
+/**
+ * ath5k_hw_get_median_noise_floor() - Get median NF from history buffer
+ * @ah: The &struct ath5k_hw
+ */
+static s16
+ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
 {
        s16 sort[ATH5K_NF_CAL_HIST_MAX];
        s16 tmp;
@@ -1364,18 +1584,16 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
        return sort[(ATH5K_NF_CAL_HIST_MAX - 1) / 2];
 }
 
-/*
- * When we tell the hardware to perform a noise floor calibration
- * by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically
- * sample-and-hold the minimum noise level seen at the antennas.
- * This value is then stored in a ring buffer of recently measured
- * noise floor values so we have a moving window of the last few
- * samples.
+/**
+ * ath5k_hw_update_noise_floor() - Update NF on hardware
+ * @ah: The &struct ath5k_hw
  *
- * The median of the values in the history is then loaded into the
- * hardware for its own use for RSSI and CCA measurements.
+ * This is the main function we call to perform a NF calibration,
+ * it reads NF from hardware, calculates the median and updates
+ * NF on hw.
  */
-void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
+void
+ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
 {
        struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
        u32 val;
@@ -1390,6 +1608,8 @@ void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
                return;
        }
 
+       ah->ah_cal_mask |= AR5K_CALIBRATION_NF;
+
        ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
 
        /* completed NF calibration, test threshold */
@@ -1434,20 +1654,29 @@ void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
 
        ah->ah_noise_floor = nf;
 
+       ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF;
+
        ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE,
                "noise floor calibrated: %d\n", nf);
 }
 
-/*
- * Perform a PHY calibration on RF5110
- * -Fix BPSK/QAM Constellation (I/Q correction)
+/**
+ * ath5k_hw_rf5110_calibrate() - Perform a PHY calibration on RF5110
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
+ * Do a complete PHY calibration (AGC + NF + I/Q) on RF5110
  */
-static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
+static int
+ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
                struct ieee80211_channel *channel)
 {
        u32 phy_sig, phy_agc, phy_sat, beacon;
        int ret;
 
+       if (!(ah->ah_cal_mask & AR5K_CALIBRATION_FULL))
+               return 0;
+
        /*
         * Disable beacons and RX/TX queues, wait
         */
@@ -1456,7 +1685,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
        beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
        ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
 
-       mdelay(2);
+       usleep_range(2000, 2500);
 
        /*
         * Set the channel (with AGC turned off)
@@ -1469,7 +1698,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
         * Activate PHY and wait
         */
        ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
-       mdelay(1);
+       usleep_range(1000, 1500);
 
        AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
 
@@ -1506,7 +1735,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
        ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG);
        AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
 
-       mdelay(1);
+       usleep_range(1000, 1500);
 
        /*
         * Enable calibration and wait until completion
@@ -1537,8 +1766,9 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
        return 0;
 }
 
-/*
- * Perform I/Q calibration on RF5111/5112 and newer chips
+/**
+ * ath5k_hw_rf511x_iq_calibrate() - Perform I/Q calibration on RF5111 and newer
+ * @ah: The &struct ath5k_hw
  */
 static int
 ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
@@ -1547,12 +1777,19 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
        s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
        int i;
 
-       if (!ah->ah_calibration ||
-               ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
-               return 0;
+       /* Skip if I/Q calibration is not needed or if it's still running */
+       if (!ah->ah_iq_cal_needed)
+               return -EINVAL;
+       else if (ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) {
+               ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE,
+                               "I/Q calibration still running");
+               return -EBUSY;
+       }
 
        /* Calibration has finished, get the results and re-run */
-       /* work around empty results which can apparently happen on 5212 */
+
+       /* Work around for empty results which can apparently happen on 5212:
+        * Read registers up to 10 times until we get both i_pr and q_pwr */
        for (i = 0; i <= 10; i++) {
                iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
                i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
@@ -1570,9 +1807,13 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
        else
                q_coffd = q_pwr >> 7;
 
-       /* protect against divide by 0 and loss of sign bits */
+       /* In case i_coffd became zero, cancel calibration
+        * not only it's too small, it'll also result a divide
+        * by zero later on. */
        if (i_coffd == 0 || q_coffd < 2)
-               return 0;
+               return -ECANCELED;
+
+       /* Protect against loss of sign bits */
 
        i_coff = (-iq_corr) / i_coffd;
        i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
@@ -1601,10 +1842,17 @@ ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
        return 0;
 }
 
-/*
- * Perform a PHY calibration
+/**
+ * ath5k_hw_phy_calibrate() - Perform a PHY calibration
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
+ * The main function we call from above to perform
+ * a short or full PHY calibration based on RF chip
+ * and current channel
  */
-int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
+int
+ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
                struct ieee80211_channel *channel)
 {
        int ret;
@@ -1613,10 +1861,43 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
                return ath5k_hw_rf5110_calibrate(ah, channel);
 
        ret = ath5k_hw_rf511x_iq_calibrate(ah);
+       if (ret) {
+               ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_CALIBRATE,
+                       "No I/Q correction performed (%uMHz)\n",
+                       channel->center_freq);
+
+               /* Happens all the time if there is not much
+                * traffic, consider it normal behaviour. */
+               ret = 0;
+       }
+
+       /* On full calibration do an AGC calibration and
+        * request a PAPD probe for gainf calibration if
+        * needed */
+       if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) {
 
-       if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) &&
-           (channel->hw_value != AR5K_MODE_11B))
-               ath5k_hw_request_rfgain_probe(ah);
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+                                       AR5K_PHY_AGCCTL_CAL);
+
+               ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+                       AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF,
+                       0, false);
+               if (ret) {
+                       ATH5K_ERR(ah,
+                               "gain calibration timeout (%uMHz)\n",
+                               channel->center_freq);
+               }
+
+               if ((ah->ah_radio == AR5K_RF5111 ||
+                       ah->ah_radio == AR5K_RF5112)
+                       && (channel->hw_value != AR5K_MODE_11B))
+                       ath5k_hw_request_rfgain_probe(ah);
+       }
+
+       /* Update noise floor
+        * XXX: Only do this after AGC calibration */
+       if (!(ah->ah_cal_mask & AR5K_CALIBRATION_NF))
+               ath5k_hw_update_noise_floor(ah);
 
        return ret;
 }
@@ -1626,6 +1907,16 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
 * Spur mitigation functions *
 \***************************/
 
+/**
+ * ath5k_hw_set_spur_mitigation_filter() - Configure SPUR filter
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
+ * This function gets called during PHY initialization to
+ * configure the spur filter for the given channel. Spur is noise
+ * generated due to "reflection" effects, for more information on this
+ * method check out patent US7643810
+ */
 static void
 ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
                                struct ieee80211_channel *channel)
@@ -1865,15 +2156,73 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
 * Antenna control *
 \*****************/
 
-static void /*TODO:Boundary check*/
+/**
+ * DOC: Antenna control
+ *
+ * Hw supports up to 14 antennas ! I haven't found any card that implements
+ * that. The maximum number of antennas I've seen is up to 4 (2 for 2GHz and 2
+ * for 5GHz). Antenna 1 (MAIN) should be omnidirectional, 2 (AUX)
+ * omnidirectional or sectorial and antennas 3-14 sectorial (or directional).
+ *
+ * We can have a single antenna for RX and multiple antennas for TX.
+ * RX antenna is our "default" antenna (usually antenna 1) set on
+ * DEFAULT_ANTENNA register and TX antenna is set on each TX control descriptor
+ * (0 for automatic selection, 1 - 14 antenna number).
+ *
+ * We can let hw do all the work doing fast antenna diversity for both
+ * tx and rx or we can do things manually. Here are the options we have
+ * (all are bits of STA_ID1 register):
+ *
+ * AR5K_STA_ID1_DEFAULT_ANTENNA -> When 0 is set as the TX antenna on TX
+ * control descriptor, use the default antenna to transmit or else use the last
+ * antenna on which we received an ACK.
+ *
+ * AR5K_STA_ID1_DESC_ANTENNA -> Update default antenna after each TX frame to
+ * the antenna on which we got the ACK for that frame.
+ *
+ * AR5K_STA_ID1_RTS_DEF_ANTENNA -> Use default antenna for RTS or else use the
+ * one on the TX descriptor.
+ *
+ * AR5K_STA_ID1_SELFGEN_DEF_ANT -> Use default antenna for self generated frames
+ * (ACKs etc), or else use current antenna (the one we just used for TX).
+ *
+ * Using the above we support the following scenarios:
+ *
+ * AR5K_ANTMODE_DEFAULT -> Hw handles antenna diversity etc automatically
+ *
+ * AR5K_ANTMODE_FIXED_A        -> Only antenna A (MAIN) is present
+ *
+ * AR5K_ANTMODE_FIXED_B        -> Only antenna B (AUX) is present
+ *
+ * AR5K_ANTMODE_SINGLE_AP -> Sta locked on a single ap
+ *
+ * AR5K_ANTMODE_SECTOR_AP -> AP with tx antenna set on tx desc
+ *
+ * AR5K_ANTMODE_SECTOR_STA -> STA with tx antenna set on tx desc
+ *
+ * AR5K_ANTMODE_DEBUG Debug mode -A -> Rx, B-> Tx-
+ *
+ * Also note that when setting antenna to F on tx descriptor card inverts
+ * current tx antenna.
+ */
+
+/**
+ * ath5k_hw_set_def_antenna() - Set default rx antenna on AR5211/5212 and newer
+ * @ah: The &struct ath5k_hw
+ * @ant: Antenna number
+ */
+static void
 ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant)
 {
        if (ah->ah_version != AR5K_AR5210)
                ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA);
 }
 
-/*
- * Enable/disable fast rx antenna diversity
+/**
+ * ath5k_hw_set_fast_div() -  Enable/disable fast rx antenna diversity
+ * @ah: The &struct ath5k_hw
+ * @ee_mode: One of enum ath5k_driver_mode
+ * @enable: True to enable, false to disable
  */
 static void
 ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable)
@@ -1913,6 +2262,14 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable)
        }
 }
 
+/**
+ * ath5k_hw_set_antenna_switch() - Set up antenna switch table
+ * @ah: The &struct ath5k_hw
+ * @ee_mode: One of enum ath5k_driver_mode
+ *
+ * Switch table comes from EEPROM and includes information on controlling
+ * the 2 antenna RX attenuators
+ */
 void
 ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode)
 {
@@ -1944,8 +2301,10 @@ ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode)
                AR5K_PHY_ANT_SWITCH_TABLE_1);
 }
 
-/*
- * Set antenna operating mode
+/**
+ * ath5k_hw_set_antenna_mode() -  Set antenna operating mode
+ * @ah: The &struct ath5k_hw
+ * @ant_mode: One of enum ath5k_ant_mode
  */
 void
 ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
@@ -2068,8 +2427,13 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
  * Helper functions
  */
 
-/*
- * Do linear interpolation between two given (x, y) points
+/**
+ * ath5k_get_interpolated_value() - Get interpolated Y val between two points
+ * @target: X value of the middle point
+ * @x_left: X value of the left point
+ * @x_right: X value of the right point
+ * @y_left: Y value of the left point
+ * @y_right: Y value of the right point
  */
 static s16
 ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right,
@@ -2096,13 +2460,18 @@ ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right,
        return result;
 }
 
-/*
- * Find vertical boundary (min pwr) for the linear PCDAC curve.
+/**
+ * ath5k_get_linear_pcdac_min() - Find vertical boundary (min pwr) for the
+ * linear PCDAC curve
+ * @stepL: Left array with y values (pcdac steps)
+ * @stepR: Right array with y values (pcdac steps)
+ * @pwrL: Left array with x values (power steps)
+ * @pwrR: Right array with x values (power steps)
  *
  * Since we have the top of the curve and we draw the line below
  * until we reach 1 (1 pcdac step) we need to know which point
- * (x value) that is so that we don't go below y axis and have negative
- * pcdac values when creating the curve, or fill the table with zeroes.
+ * (x value) that is so that we don't go below x axis and have negative
+ * pcdac values when creating the curve, or fill the table with zeros.
  */
 static s16
 ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
@@ -2148,7 +2517,16 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
        return max(min_pwrL, min_pwrR);
 }
 
-/*
+/**
+ * ath5k_create_power_curve() - Create a Power to PDADC or PCDAC curve
+ * @pmin: Minimum power value (xmin)
+ * @pmax: Maximum power value (xmax)
+ * @pwr: Array of power steps (x values)
+ * @vpd: Array of matching PCDAC/PDADC steps (y values)
+ * @num_points: Number of provided points
+ * @vpd_table: Array to fill with the full PCDAC/PDADC values (y values)
+ * @type: One of enum ath5k_powertable_type (eeprom.h)
+ *
  * Interpolate (pwr,vpd) points to create a Power to PDADC or a
  * Power to PCDAC curve.
  *
@@ -2206,7 +2584,14 @@ ath5k_create_power_curve(s16 pmin, s16 pmax,
        }
 }
 
-/*
+/**
+ * ath5k_get_chan_pcal_surrounding_piers() - Get surrounding calibration piers
+ * for a given channel.
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ * @pcinfo_l: The &struct ath5k_chan_pcal_info to put the left cal. pier
+ * @pcinfo_r: The &struct ath5k_chan_pcal_info to put the right cal. pier
+ *
  * Get the surrounding per-channel power calibration piers
  * for a given frequency so that we can interpolate between
  * them and come up with an appropriate dataset for our current
@@ -2289,11 +2674,17 @@ done:
        *pcinfo_r = &pcinfo[idx_r];
 }
 
-/*
+/**
+ * ath5k_get_rate_pcal_data() - Get the interpolated per-rate power
+ * calibration data
+ * @ah: The &struct ath5k_hw *ah,
+ * @channel: The &struct ieee80211_channel
+ * @rates: The &struct ath5k_rate_pcal_info to fill
+ *
  * Get the surrounding per-rate power calibration data
  * for a given frequency and interpolate between power
  * values to set max target power supported by hw for
- * each rate.
+ * each rate on this frequency.
  */
 static void
 ath5k_get_rate_pcal_data(struct ath5k_hw *ah,
@@ -2381,7 +2772,11 @@ done:
                                        rpinfo[idx_r].target_power_54);
 }
 
-/*
+/**
+ * ath5k_get_max_ctl_power() - Get max edge power for a given frequency
+ * @ah: the &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
  * Get the max edge power for this channel if
  * we have such data from EEPROM's Conformance Test
  * Limits (CTL), and limit max power if needed.
@@ -2461,8 +2856,39 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah,
  * Power to PCDAC table functions
  */
 
-/*
- * Fill Power to PCDAC table on RF5111
+/**
+ * DOC: Power to PCDAC table functions
+ *
+ * For RF5111 we have an XPD -eXternal Power Detector- curve
+ * for each calibrated channel. Each curve has 0,5dB Power steps
+ * on x axis and PCDAC steps (offsets) on y axis and looks like an
+ * exponential function. To recreate the curve we read 11 points
+ * from eeprom (eeprom.c) and interpolate here.
+ *
+ * For RF5112 we have 4 XPD -eXternal Power Detector- curves
+ * for each calibrated channel on 0, -6, -12 and -18dBm but we only
+ * use the higher (3) and the lower (0) curves. Each curve again has 0.5dB
+ * power steps on x axis and PCDAC steps on y axis and looks like a
+ * linear function. To recreate the curve and pass the power values
+ * on hw, we get 4 points for xpd 0 (lower gain -> max power)
+ * and 3 points for xpd 3 (higher gain -> lower power) from eeprom (eeprom.c)
+ * and interpolate here.
+ *
+ * For a given channel we get the calibrated points (piers) for it or
+ * -if we don't have calibration data for this specific channel- from the
+ * available surrounding channels we have calibration data for, after we do a
+ * linear interpolation between them. Then since we have our calibrated points
+ * for this channel, we do again a linear interpolation between them to get the
+ * whole curve.
+ *
+ * We finally write the Y values of the curve(s) (the PCDAC values) on hw
+ */
+
+/**
+ * ath5k_fill_pwr_to_pcdac_table() - Fill Power to PCDAC table on RF5111
+ * @ah: The &struct ath5k_hw
+ * @table_min: Minimum power (x min)
+ * @table_max: Maximum power (x max)
  *
  * No further processing is needed for RF5111, the only thing we have to
  * do is fill the values below and above calibration range since eeprom data
@@ -2503,10 +2929,14 @@ ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min,
 
 }
 
-/*
- * Combine available XPD Curves and fill Linear Power to PCDAC table
- * on RF5112
+/**
+ * ath5k_combine_linear_pcdac_curves() - Combine available PCDAC Curves
+ * @ah: The &struct ath5k_hw
+ * @table_min: Minimum power (x min)
+ * @table_max: Maximum power (x max)
+ * @pdcurves: Number of pd curves
  *
+ * Combine available XPD Curves and fill Linear Power to PCDAC table on RF5112
  * RFX112 can have up to 2 curves (one for low txpower range and one for
  * higher txpower range). We need to put them both on pcdac_out and place
  * them in the correct location. In case we only have one curve available
@@ -2608,7 +3038,10 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
        }
 }
 
-/* Write PCDAC values on hw */
+/**
+ * ath5k_write_pcdac_table() - Write the PCDAC values on hw
+ * @ah: The &struct ath5k_hw
+ */
 static void
 ath5k_write_pcdac_table(struct ath5k_hw *ah)
 {
@@ -2631,9 +3064,32 @@ ath5k_write_pcdac_table(struct ath5k_hw *ah)
  * Power to PDADC table functions
  */
 
-/*
- * Set the gain boundaries and create final Power to PDADC table
+/**
+ * DOC: Power to PDADC table functions
+ *
+ * For RF2413 and later we have a Power to PDADC table (Power Detector)
+ * instead of a PCDAC (Power Control) and 4 pd gain curves for each
+ * calibrated channel. Each curve has power on x axis in 0.5 db steps and
+ * PDADC steps on y axis and looks like an exponential function like the
+ * RF5111 curve.
+ *
+ * To recreate the curves we read the points from eeprom (eeprom.c)
+ * and interpolate here. Note that in most cases only 2 (higher and lower)
+ * curves are used (like RF5112) but vendors have the opportunity to include
+ * all 4 curves on eeprom. The final curve (higher power) has an extra
+ * point for better accuracy like RF5112.
  *
+ * The process is similar to what we do above for RF5111/5112
+ */
+
+/**
+ * ath5k_combine_pwr_to_pdadc_curves() - Combine the various PDADC curves
+ * @ah: The &struct ath5k_hw
+ * @pwr_min: Minimum power (x min)
+ * @pwr_max: Maximum power (x max)
+ * @pdcurves: Number of available curves
+ *
+ * Combine the various pd curves and create the final Power to PDADC table
  * We can have up to 4 pd curves, we need to do a similar process
  * as we do for RF5112. This time we don't have an edge_flag but we
  * set the gain boundaries on a separate register.
@@ -2757,7 +3213,11 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah,
 
 }
 
-/* Write PDADC values on hw */
+/**
+ * ath5k_write_pwr_to_pdadc_table() - Write the PDADC values on hw
+ * @ah: The &struct ath5k_hw
+ * @ee_mode: One of enum ath5k_driver_mode
+ */
 static void
 ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode)
 {
@@ -2814,7 +3274,13 @@ ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode)
  * Common code for PCDAC/PDADC tables
  */
 
-/*
+/**
+ * ath5k_setup_channel_powertable() - Set up power table for this channel
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ * @ee_mode: One of enum ath5k_driver_mode
+ * @type: One of enum ath5k_powertable_type (eeprom.h)
+ *
  * This is the main function that uses all of the above
  * to set PCDAC/PDADC table on hw for the current channel.
  * This table is used for tx power calibration on the baseband,
@@ -3012,7 +3478,12 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
        return 0;
 }
 
-/* Write power table for current channel to hw */
+/**
+ * ath5k_write_channel_powertable() - Set power table for current channel on hw
+ * @ah: The &struct ath5k_hw
+ * @ee_mode: One of enum ath5k_driver_mode
+ * @type: One of enum ath5k_powertable_type (eeprom.h)
+ */
 static void
 ath5k_write_channel_powertable(struct ath5k_hw *ah, u8 ee_mode, u8 type)
 {
@@ -3022,28 +3493,36 @@ ath5k_write_channel_powertable(struct ath5k_hw *ah, u8 ee_mode, u8 type)
                ath5k_write_pcdac_table(ah);
 }
 
-/*
- * Per-rate tx power setting
+
+/**
+ * DOC: Per-rate tx power setting
  *
- * This is the code that sets the desired tx power (below
+ * This is the code that sets the desired tx power limit (below
  * maximum) on hw for each rate (we also have TPC that sets
- * power per packet). We do that by providing an index on the
- * PCDAC/PDADC table we set up.
- */
-
-/*
- * Set rate power table
+ * power per packet type). We do that by providing an index on the
+ * PCDAC/PDADC table we set up above, for each rate.
  *
  * For now we only limit txpower based on maximum tx power
- * supported by hw (what's inside rate_info). We need to limit
- * this even more, based on regulatory domain etc.
+ * supported by hw (what's inside rate_info) + conformance test
+ * limits. We need to limit this even more, based on regulatory domain
+ * etc to be safe. Normally this is done from above so we don't care
+ * here, all we care is that the tx power we set will be O.K.
+ * for the hw (e.g. won't create noise on PA etc).
  *
- * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps)
- * and is indexed as follows:
+ * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps -
+ * x values) and is indexed as follows:
  * rates[0] - rates[7] -> OFDM rates
  * rates[8] - rates[14] -> CCK rates
  * rates[15] -> XR rates (they all have the same power)
  */
+
+/**
+ * ath5k_setup_rate_powertable() - Set up rate power table for a given tx power
+ * @ah: The &struct ath5k_hw
+ * @max_pwr: The maximum tx power requested in 0.5dB steps
+ * @rate_info: The &struct ath5k_rate_pcal_info to fill
+ * @ee_mode: One of enum ath5k_driver_mode
+ */
 static void
 ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
                        struct ath5k_rate_pcal_info *rate_info,
@@ -3114,8 +3593,14 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
 }
 
 
-/*
- * Set transmission power
+/**
+ * ath5k_hw_txpower() - Set transmission power limit for a given channel
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ * @txpower: Requested tx power in 0.5dB steps
+ *
+ * Combines all of the above to set the requested tx power limit
+ * on hw.
  */
 static int
 ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
@@ -3233,7 +3718,16 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
        return 0;
 }
 
-int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
+/**
+ * ath5k_hw_set_txpower_limit() - Set txpower limit for the current channel
+ * @ah: The &struct ath5k_hw
+ * @txpower: The requested tx power limit in 0.5dB steps
+ *
+ * This function provides access to ath5k_hw_txpower to the driver in
+ * case user or an application changes it while PHY is running.
+ */
+int
+ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
 {
        ATH5K_DBG(ah, ATH5K_DEBUG_TXPOWER,
                "changing txpower to %d\n", txpower);
@@ -3241,11 +3735,26 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
        return ath5k_hw_txpower(ah, ah->ah_current_channel, txpower);
 }
 
+
 /*************\
  Init function
 \*************/
 
-int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+/**
+ * ath5k_hw_phy_init() - Initialize PHY
+ * @ah: The &struct ath5k_hw
+ * @channel: The @struct ieee80211_channel
+ * @mode: One of enum ath5k_driver_mode
+ * @fast: Try a fast channel switch instead
+ *
+ * This is the main function used during reset to initialize PHY
+ * or do a fast channel change if possible.
+ *
+ * NOTE: Do not call this one from the driver, it assumes PHY is in a
+ * warm reset state !
+ */
+int
+ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                      u8 mode, bool fast)
 {
        struct ieee80211_channel *curr_channel;
@@ -3355,7 +3864,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                if (ret)
                        return ret;
 
-               mdelay(1);
+               usleep_range(1000, 1500);
 
                /*
                 * Write RF buffer
@@ -3376,10 +3885,10 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                }
 
        } else if (ah->ah_version == AR5K_AR5210) {
-               mdelay(1);
+               usleep_range(1000, 1500);
                /* Disable phy and wait */
                ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
-               mdelay(1);
+               usleep_range(1000, 1500);
        }
 
        /* Set channel on PHY */
@@ -3405,7 +3914,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
        for (i = 0; i <= 20; i++) {
                if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
                        break;
-               udelay(200);
+               usleep_range(200, 250);
        }
        ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
 
@@ -3433,9 +3942,9 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
 
        /* At the same time start I/Q calibration for QAM constellation
         * -no need for CCK- */
-       ah->ah_calibration = false;
+       ah->ah_iq_cal_needed = false;
        if (!(mode == AR5K_MODE_11B)) {
-               ah->ah_calibration = true;
+               ah->ah_iq_cal_needed = true;
                AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
                                AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
                AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
index 7766542..30b50f9 100644 (file)
  */
 
 /********************************************\
-Queue Control Unit, DFS Control Unit Functions
+Queue Control Unit, DCF Control Unit Functions
 \********************************************/
 
 #include "ath5k.h"
 #include "reg.h"
 #include "debug.h"
+#include <linux/log2.h>
+
+/**
+ * DOC: Queue Control Unit (QCU)/DCF Control Unit (DCU) functions
+ *
+ * Here we setup parameters for the 12 available TX queues. Note that
+ * on the various registers we can usually only map the first 10 of them so
+ * basically we have 10 queues to play with. Each queue has a matching
+ * QCU that controls when the queue will get triggered and multiple QCUs
+ * can be mapped to a single DCU that controls the various DFS parameters
+ * for the various queues. In our setup we have a 1:1 mapping between QCUs
+ * and DCUs allowing us to have different DFS settings for each queue.
+ *
+ * When a frame goes into a TX queue, QCU decides when it'll trigger a
+ * transmission based on various criteria (such as how many data we have inside
+ * it's buffer or -if it's a beacon queue- if it's time to fire up the queue
+ * based on TSF etc), DCU adds backoff, IFSes etc and then a scheduler
+ * (arbitrator) decides the priority of each QCU based on it's configuration
+ * (e.g. beacons are always transmitted when they leave DCU bypassing all other
+ * frames from other queues waiting to be transmitted). After a frame leaves
+ * the DCU it goes to PCU for further processing and then to PHY for
+ * the actual transmission.
+ */
 
 
 /******************\
 * Helper functions *
 \******************/
 
-/*
- * Get number of pending frames
- * for a specific queue [5211+]
+/**
+ * ath5k_hw_num_tx_pending() - Get number of pending frames for a  given queue
+ * @ah: The &struct ath5k_hw
+ * @queue: One of enum ath5k_tx_queue_id
  */
-u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
+u32
+ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
 {
        u32 pending;
        AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
@@ -58,10 +83,13 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
        return pending;
 }
 
-/*
- * Set a transmit queue inactive
+/**
+ * ath5k_hw_release_tx_queue() - Set a transmit queue inactive
+ * @ah: The &struct ath5k_hw
+ * @queue: One of enum ath5k_tx_queue_id
  */
-void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+void
+ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
 {
        if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
                return;
@@ -72,34 +100,56 @@ void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
        AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
 }
 
-/*
+/**
+ * ath5k_cw_validate() - Make sure the given cw is valid
+ * @cw_req: The contention window value to check
+ *
  * Make sure cw is a power of 2 minus 1 and smaller than 1024
  */
-static u16 ath5k_cw_validate(u16 cw_req)
+static u16
+ath5k_cw_validate(u16 cw_req)
 {
-       u32 cw = 1;
        cw_req = min(cw_req, (u16)1023);
 
-       while (cw < cw_req)
-               cw = (cw << 1) | 1;
+       /* Check if cw_req + 1 a power of 2 */
+       if (is_power_of_2(cw_req + 1))
+               return cw_req;
 
-       return cw;
+       /* Check if cw_req is a power of 2 */
+       if (is_power_of_2(cw_req))
+               return cw_req - 1;
+
+       /* If none of the above is correct
+        * find the closest power of 2 */
+       cw_req = (u16) roundup_pow_of_two(cw_req) - 1;
+
+       return cw_req;
 }
 
-/*
- * Get properties for a transmit queue
+/**
+ * ath5k_hw_get_tx_queueprops() - Get properties for a transmit queue
+ * @ah: The &struct ath5k_hw
+ * @queue: One of enum ath5k_tx_queue_id
+ * @queue_info: The &struct ath5k_txq_info to fill
  */
-int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
+int
+ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
                struct ath5k_txq_info *queue_info)
 {
        memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
        return 0;
 }
 
-/*
- * Set properties for a transmit queue
+/**
+ * ath5k_hw_set_tx_queueprops() - Set properties for a transmit queue
+ * @ah: The &struct ath5k_hw
+ * @queue: One of enum ath5k_tx_queue_id
+ * @qinfo: The &struct ath5k_txq_info to use
+ *
+ * Returns 0 on success or -EIO if queue is inactive
  */
-int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
+int
+ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
                                const struct ath5k_txq_info *qinfo)
 {
        struct ath5k_txq_info *qi;
@@ -139,10 +189,16 @@ int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
        return 0;
 }
 
-/*
- * Initialize a transmit queue
+/**
+ * ath5k_hw_setup_tx_queue() - Initialize a transmit queue
+ * @ah: The &struct ath5k_hw
+ * @queue_type: One of enum ath5k_tx_queue
+ * @queue_info: The &struct ath5k_txq_info to use
+ *
+ * Returns 0 on success, -EINVAL on invalid arguments
  */
-int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
+int
+ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
                struct ath5k_txq_info *queue_info)
 {
        unsigned int queue;
@@ -217,10 +273,16 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
 * Single QCU/DCU initialization *
 \*******************************/
 
-/*
- * Set tx retry limits on DCU
+/**
+ * ath5k_hw_set_tx_retry_limits() - Set tx retry limits on DCU
+ * @ah: The &struct ath5k_hw
+ * @queue: One of enum ath5k_tx_queue_id
+ *
+ * This function is used when initializing a queue, to set
+ * retry limits based on ah->ah_retry_* and the chipset used.
  */
-void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
+void
+ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
                                  unsigned int queue)
 {
        /* Single data queue on AR5210 */
@@ -255,15 +317,15 @@ void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
 }
 
 /**
- * ath5k_hw_reset_tx_queue - Initialize a single hw queue
+ * ath5k_hw_reset_tx_queue() - Initialize a single hw queue
+ * @ah: The &struct ath5k_hw
+ * @queue: One of enum ath5k_tx_queue_id
  *
- * @ah The &struct ath5k_hw
- * @queue The hw queue number
- *
- * Set DFS properties for the given transmit queue on DCU
+ * Set DCF properties for the given transmit queue on DCU
  * and configures all queue-specific parameters.
  */
-int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+int
+ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
 {
        struct ath5k_txq_info *tq = &ah->ah_txq[queue];
 
@@ -491,10 +553,9 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
 \**************************/
 
 /**
- * ath5k_hw_set_ifs_intervals  - Set global inter-frame spaces on DCU
- *
- * @ah The &struct ath5k_hw
- * @slot_time Slot time in us
+ * ath5k_hw_set_ifs_intervals()  - Set global inter-frame spaces on DCU
+ * @ah: The &struct ath5k_hw
+ * @slot_time: Slot time in us
  *
  * Sets the global IFS intervals on DCU (also works on AR5210) for
  * the given slot time and the current bwmode.
@@ -597,7 +658,15 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
 }
 
 
-int ath5k_hw_init_queues(struct ath5k_hw *ah)
+/**
+ * ath5k_hw_init_queues() - Initialize tx queues
+ * @ah: The &struct ath5k_hw
+ *
+ * Initializes all tx queues based on information on
+ * ah->ah_txq* set by the driver
+ */
+int
+ath5k_hw_init_queues(struct ath5k_hw *ah)
 {
        int i, ret;
 
index f5c1000..0ea1608 100644 (file)
  * 5211/5212 we have one primary and 4 secondary registers.
  * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212.
  * Most of these bits are common for all chipsets.
+ *
+ * NOTE: On 5211+ TXOK, TXDESC, TXERR, TXEOL and TXURN contain
+ * the logical OR from per-queue interrupt bits found on SISR registers
+ * (see below).
  */
 #define AR5K_ISR               0x001c                  /* Register Address [5210] */
 #define AR5K_PISR              0x0080                  /* Register Address [5211+] */
 #define AR5K_ISR_TXOK          0x00000040      /* Frame successfully transmitted */
 #define AR5K_ISR_TXDESC                0x00000080      /* TX descriptor request */
 #define AR5K_ISR_TXERR         0x00000100      /* Transmit error */
-#define AR5K_ISR_TXNOFRM       0x00000200      /* No frame transmitted (transmit timeout) */
+#define AR5K_ISR_TXNOFRM       0x00000200      /* No frame transmitted (transmit timeout)
+                                                * NOTE: We don't have per-queue info for this
+                                                * one, but we can enable it per-queue through
+                                                * TXNOFRM_QCU field on TXNOFRM register */
 #define AR5K_ISR_TXEOL         0x00000400      /* Empty TX descriptor */
 #define AR5K_ISR_TXURN         0x00000800      /* Transmit FIFO underrun */
 #define AR5K_ISR_MIB           0x00001000      /* Update MIB counters */
 #define AR5K_ISR_SWBA          0x00010000      /* Software beacon alert */
 #define AR5K_ISR_BRSSI         0x00020000      /* Beacon rssi below threshold (?) */
 #define AR5K_ISR_BMISS         0x00040000      /* Beacon missed */
-#define AR5K_ISR_HIUERR                0x00080000      /* Host Interface Unit error [5211+] */
+#define AR5K_ISR_HIUERR                0x00080000      /* Host Interface Unit error [5211+]
+                                                * 'or' of MCABT, SSERR, DPERR from SISR2 */
 #define AR5K_ISR_BNR           0x00100000      /* Beacon not ready [5211+] */
 #define AR5K_ISR_MCABT         0x00100000      /* Master Cycle Abort [5210] */
 #define AR5K_ISR_RXCHIRP       0x00200000      /* CHIRP Received [5212+] */
 #define AR5K_ISR_SSERR         0x00200000      /* Signaled System Error [5210] */
-#define AR5K_ISR_DPERR         0x00400000      /* Det par Error (?) [5210] */
+#define AR5K_ISR_DPERR         0x00400000      /* Bus parity error [5210] */
 #define AR5K_ISR_RXDOPPLER     0x00400000      /* Doppler chirp received [5212+] */
 #define AR5K_ISR_TIM           0x00800000      /* [5211+] */
-#define AR5K_ISR_BCNMISC       0x00800000      /* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
-                                               CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
+#define AR5K_ISR_BCNMISC       0x00800000      /* Misc beacon related interrupt
+                                                * 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
+                                                * CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
 #define AR5K_ISR_GPIO          0x01000000      /* GPIO (rf kill) */
 #define AR5K_ISR_QCBRORN       0x02000000      /* QCU CBR overrun [5211+] */
 #define AR5K_ISR_QCBRURN       0x04000000      /* QCU CBR underrun [5211+] */
 #define AR5K_ISR_QTRIG         0x08000000      /* QCU scheduling trigger [5211+] */
 
+#define        AR5K_ISR_BITS_FROM_SISRS        (AR5K_ISR_TXOK | AR5K_ISR_TXDESC |\
+                                       AR5K_ISR_TXERR | AR5K_ISR_TXEOL |\
+                                       AR5K_ISR_TXURN | AR5K_ISR_HIUERR |\
+                                       AR5K_ISR_BCNMISC | AR5K_ISR_QCBRORN |\
+                                       AR5K_ISR_QCBRURN | AR5K_ISR_QTRIG)
+
 /*
  * Secondary status registers [5211+] (0 - 4)
  *
 #define        AR5K_SISR2_BCN_TIMEOUT  0x08000000      /* Beacon Timeout [5212+] */
 #define        AR5K_SISR2_CAB_TIMEOUT  0x10000000      /* CAB Timeout [5212+] */
 #define        AR5K_SISR2_DTIM         0x20000000      /* [5212+] */
-#define        AR5K_SISR2_TSFOOR       0x80000000      /* TSF OOR (?) */
+#define        AR5K_SISR2_TSFOOR       0x80000000      /* TSF Out of range */
 
 #define AR5K_SISR3             0x0090                  /* Register Address [5211+] */
 #define AR5K_SISR3_QCBRORN     0x000003ff      /* Mask for QCBRORN */
index 2abac25..4aed3a3 100644 (file)
@@ -19,9 +19,9 @@
  *
  */
 
-/*****************************\
-  Reset functions and helpers
-\*****************************/
+/****************************\
+  Reset function and helpers
+\****************************/
 
 #include <asm/unaligned.h>
 
 #include "debug.h"
 
 
+/**
+ * DOC: Reset function and helpers
+ *
+ * Here we implement the main reset routine, used to bring the card
+ * to a working state and ready to receive. We also handle routines
+ * that don't fit on other places such as clock, sleep and power control
+ */
+
+
 /******************\
 * Helper functions *
 \******************/
 
-/*
- * Check if a register write has been completed
+/**
+ * ath5k_hw_register_timeout() - Poll a register for a flag/field change
+ * @ah: The &struct ath5k_hw
+ * @reg: The register to read
+ * @flag: The flag/field to check on the register
+ * @val: The field value we expect (if we check a field)
+ * @is_set: Instead of checking if the flag got cleared, check if it got set
+ *
+ * Some registers contain flags that indicate that an operation is
+ * running. We use this function to poll these registers and check
+ * if these flags get cleared. We also use it to poll a register
+ * field (containing multiple flags) until it gets a specific value.
+ *
+ * Returns -EAGAIN if we exceeded AR5K_TUNE_REGISTER_TIMEOUT * 15us or 0
  */
-int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
+int
+ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
                              bool is_set)
 {
        int i;
@@ -64,35 +86,48 @@ int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
 \*************************/
 
 /**
- * ath5k_hw_htoclock - Translate usec to hw clock units
- *
+ * ath5k_hw_htoclock() - Translate usec to hw clock units
  * @ah: The &struct ath5k_hw
  * @usec: value in microseconds
+ *
+ * Translate usecs to hw clock units based on the current
+ * hw clock rate.
+ *
+ * Returns number of clock units
  */
-unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
+unsigned int
+ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
 {
        struct ath_common *common = ath5k_hw_common(ah);
        return usec * common->clockrate;
 }
 
 /**
- * ath5k_hw_clocktoh - Translate hw clock units to usec
+ * ath5k_hw_clocktoh() - Translate hw clock units to usec
+ * @ah: The &struct ath5k_hw
  * @clock: value in hw clock units
+ *
+ * Translate hw clock units to usecs based on the current
+ * hw clock rate.
+ *
+ * Returns number of usecs
  */
-unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
+unsigned int
+ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
 {
        struct ath_common *common = ath5k_hw_common(ah);
        return clock / common->clockrate;
 }
 
 /**
- * ath5k_hw_init_core_clock - Initialize core clock
- *
- * @ah The &struct ath5k_hw
+ * ath5k_hw_init_core_clock() - Initialize core clock
+ * @ah: The &struct ath5k_hw
  *
- * Initialize core clock parameters (usec, usec32, latencies etc).
+ * Initialize core clock parameters (usec, usec32, latencies etc),
+ * based on current bwmode and chipset properties.
  */
-static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
+static void
+ath5k_hw_init_core_clock(struct ath5k_hw *ah)
 {
        struct ieee80211_channel *channel = ah->ah_current_channel;
        struct ath_common *common = ath5k_hw_common(ah);
@@ -227,16 +262,21 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
        }
 }
 
-/*
+/**
+ * ath5k_hw_set_sleep_clock() - Setup sleep clock operation
+ * @ah: The &struct ath5k_hw
+ * @enable: Enable sleep clock operation (false to disable)
+ *
  * If there is an external 32KHz crystal available, use it
  * as ref. clock instead of 32/40MHz clock and baseband clocks
  * to save power during sleep or restore normal 32/40MHz
  * operation.
  *
- * XXX: When operating on 32KHz certain PHY registers (27 - 31,
- *     123 - 127) require delay on access.
+ * NOTE: When operating on 32KHz certain PHY registers (27 - 31,
+ * 123 - 127) require delay on access.
  */
-static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
+static void
+ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
 {
        struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
        u32 scal, spending, sclock;
@@ -340,10 +380,19 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
 * Reset/Sleep control *
 \*********************/
 
-/*
- * Reset chipset
+/**
+ * ath5k_hw_nic_reset() - Reset the various chipset units
+ * @ah: The &struct ath5k_hw
+ * @val: Mask to indicate what units to reset
+ *
+ * To reset the various chipset units we need to write
+ * the mask to AR5K_RESET_CTL and poll the register until
+ * all flags are cleared.
+ *
+ * Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout)
  */
-static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
+static int
+ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
 {
        int ret;
        u32 mask = val ? val : ~0U;
@@ -357,7 +406,7 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
        ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
 
        /* Wait at least 128 PCI clocks */
-       udelay(15);
+       usleep_range(15, 20);
 
        if (ah->ah_version == AR5K_AR5210) {
                val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
@@ -382,12 +431,17 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
        return ret;
 }
 
-/*
- * Reset AHB chipset
- * AR5K_RESET_CTL_PCU flag resets WMAC
- * AR5K_RESET_CTL_BASEBAND flag resets WBB
+/**
+ * ath5k_hw_wisoc_reset() -  Reset AHB chipset
+ * @ah: The &struct ath5k_hw
+ * @flags: Mask to indicate what units to reset
+ *
+ * Same as ath5k_hw_nic_reset but for AHB based devices
+ *
+ * Returns 0 if we are O.K. or -EAGAIN (from athk5_hw_register_timeout)
  */
-static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
+static int
+ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
 {
        u32 mask = flags ? flags : ~0U;
        u32 __iomem *reg;
@@ -422,7 +476,7 @@ static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
        regval = __raw_readl(reg);
        __raw_writel(regval | val, reg);
        regval = __raw_readl(reg);
-       udelay(100);
+       usleep_range(100, 150);
 
        /* Bring BB/MAC out of reset */
        __raw_writel(regval & ~val, reg);
@@ -439,11 +493,23 @@ static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
        return 0;
 }
 
-
-/*
- * Sleep control
+/**
+ * ath5k_hw_set_power_mode() - Set power mode
+ * @ah: The &struct ath5k_hw
+ * @mode: One of enum ath5k_power_mode
+ * @set_chip: Set to true to write sleep control register
+ * @sleep_duration: How much time the device is allowed to sleep
+ * when sleep logic is enabled (in 128 microsecond increments).
+ *
+ * This function is used to configure sleep policy and allowed
+ * sleep modes. For more information check out the sleep control
+ * register on reg.h and STA_ID1.
+ *
+ * Returns 0 on success, -EIO if chip didn't wake up or -EINVAL if an invalid
+ * mode is requested.
  */
-static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
+static int
+ath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode,
                              bool set_chip, u16 sleep_duration)
 {
        unsigned int i;
@@ -493,7 +559,7 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
 
                ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
                                                        AR5K_SLEEP_CTL);
-               udelay(15);
+               usleep_range(15, 20);
 
                for (i = 200; i > 0; i--) {
                        /* Check if the chip did wake up */
@@ -502,7 +568,7 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
                                break;
 
                        /* Wait a bit and retry */
-                       udelay(50);
+                       usleep_range(50, 75);
                        ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
                                                        AR5K_SLEEP_CTL);
                }
@@ -523,17 +589,20 @@ commit:
        return 0;
 }
 
-/*
- * Put device on hold
+/**
+ * ath5k_hw_on_hold() - Put device on hold
+ * @ah: The &struct ath5k_hw
  *
- * Put MAC and Baseband on warm reset and
- * keep that state (don't clean sleep control
- * register). After this MAC and Baseband are
- * disabled and a full reset is needed to come
- * back. This way we save as much power as possible
+ * Put MAC and Baseband on warm reset and keep that state
+ * (don't clean sleep control register). After this MAC
+ * and Baseband are disabled and a full reset is needed
+ * to come back. This way we save as much power as possible
  * without putting the card on full sleep.
+ *
+ * Returns 0 on success or -EIO on error
  */
-int ath5k_hw_on_hold(struct ath5k_hw *ah)
+int
+ath5k_hw_on_hold(struct ath5k_hw *ah)
 {
        struct pci_dev *pdev = ah->pdev;
        u32 bus_flags;
@@ -543,7 +612,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
                return 0;
 
        /* Make sure device is awake */
-       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+       ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
        if (ret) {
                ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n");
                return ret;
@@ -563,7 +632,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
                ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
                        AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
                        AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
-                       mdelay(2);
+                       usleep_range(2000, 2500);
        } else {
                ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
                        AR5K_RESET_CTL_BASEBAND | bus_flags);
@@ -575,7 +644,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
        }
 
        /* ...wakeup again!*/
-       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+       ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
        if (ret) {
                ATH5K_ERR(ah, "failed to put device on hold\n");
                return ret;
@@ -584,11 +653,18 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
        return ret;
 }
 
-/*
+/**
+ * ath5k_hw_nic_wakeup() - Force card out of sleep
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
  * Bring up MAC + PHY Chips and program PLL
- * Channel is NULL for the initial wakeup.
+ * NOTE: Channel is NULL for the initial wakeup.
+ *
+ * Returns 0 on success, -EIO on hw failure or -EINVAL for false channel infos
  */
-int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
+int
+ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
 {
        struct pci_dev *pdev = ah->pdev;
        u32 turbo, mode, clock, bus_flags;
@@ -600,7 +676,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
 
        if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) {
                /* Wakeup the device */
-               ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+               ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
                if (ret) {
                        ATH5K_ERR(ah, "failed to wakeup the MAC Chip\n");
                        return ret;
@@ -621,7 +697,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
                ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
                        AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
                        AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
-                       mdelay(2);
+                       usleep_range(2000, 2500);
        } else {
                if (ath5k_get_bus_type(ah) == ATH_AHB)
                        ret = ath5k_hw_wisoc_reset(ah, AR5K_RESET_CTL_PCU |
@@ -637,7 +713,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
        }
 
        /* ...wakeup again!...*/
-       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+       ret = ath5k_hw_set_power_mode(ah, AR5K_PM_AWAKE, true, 0);
        if (ret) {
                ATH5K_ERR(ah, "failed to resume the MAC Chip\n");
                return ret;
@@ -739,7 +815,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
                /* ...update PLL if needed */
                if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) {
                        ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
-                       udelay(300);
+                       usleep_range(300, 350);
                }
 
                /* ...set the PHY operating mode */
@@ -755,8 +831,19 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
 * Post-initvals register modifications *
 \**************************************/
 
-/* TODO: Half/Quarter rate */
-static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
+/**
+ * ath5k_hw_tweak_initval_settings() - Tweak initial settings
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
+ * Some settings are not handled on initvals, e.g. bwmode
+ * settings, some phy settings, workarounds etc that in general
+ * don't fit anywhere else or are too small to introduce a separate
+ * function for each one. So we have this function to handle
+ * them all during reset and complete card's initialization.
+ */
+static void
+ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
                                struct ieee80211_channel *channel)
 {
        if (ah->ah_version == AR5K_AR5212 &&
@@ -875,7 +962,16 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
        }
 }
 
-static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
+/**
+ * ath5k_hw_commit_eeprom_settings() - Commit settings from EEPROM
+ * @ah: The &struct ath5k_hw
+ * @channel: The &struct ieee80211_channel
+ *
+ * Use settings stored on EEPROM to properly initialize the card
+ * based on various infos and per-mode calibration data.
+ */
+static void
+ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
                struct ieee80211_channel *channel)
 {
        struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
@@ -1029,7 +1125,23 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
 * Main reset function *
 \*********************/
 
-int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+/**
+ * ath5k_hw_reset() - The main reset function
+ * @ah: The &struct ath5k_hw
+ * @op_mode: One of enum nl80211_iftype
+ * @channel: The &struct ieee80211_channel
+ * @fast: Enable fast channel switching
+ * @skip_pcu: Skip pcu initialization
+ *
+ * This is the function we call each time we want to (re)initialize the
+ * card and pass new settings to hw. We also call it when hw runs into
+ * trouble to make it come back to a working state.
+ *
+ * Returns 0 on success, -EINVAL on false op_mode or channel infos, or -EIO
+ * on failure.
+ */
+int
+ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                struct ieee80211_channel *channel, bool fast, bool skip_pcu)
 {
        u32 s_seq[10], s_led[3], tsf_up, tsf_lo;
@@ -1242,7 +1354,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        /*
         * Initialize PCU
         */
-       ath5k_hw_pcu_init(ah, op_mode, mode);
+       ath5k_hw_pcu_init(ah, op_mode);
 
        /*
         * Initialize PHY
index 5d11c23..aed34d9 100644 (file)
@@ -18,7 +18,9 @@
  */
 
 
-/*
+/**
+ * DOC: RF Buffer registers
+ *
  * There are some special registers on the RF chip
  * that control various operation settings related mostly to
  * the analog parts (channel, gain adjustment etc).
  */
 
 
-/*
+/**
+ * struct ath5k_ini_rfbuffer - Initial RF Buffer settings
+ * @rfb_bank: RF Bank number
+ * @rfb_ctrl_register: RF Buffer control register
+ * @rfb_mode_data: RF Buffer data for each mode
+ *
  * Struct to hold default mode specific RF
- * register values (RF Banks)
+ * register values (RF Banks) for each chip.
  */
 struct ath5k_ini_rfbuffer {
-       u8      rfb_bank;               /* RF Bank number */
-       u16     rfb_ctrl_register;      /* RF Buffer control register */
-       u32     rfb_mode_data[3];       /* RF Buffer data for each mode */
+       u8      rfb_bank;
+       u16     rfb_ctrl_register;
+       u32     rfb_mode_data[3];
 };
 
-/*
+/**
+ * struct ath5k_rfb_field - An RF Buffer field (register/value)
+ * @len: Field length
+ * @pos: Offset on the raw packet
+ * @col: Used for shifting
+ *
  * Struct to hold RF Buffer field
  * infos used to access certain RF
  * analog registers
  */
 struct ath5k_rfb_field {
-       u8      len;    /* Field length */
-       u16     pos;    /* Offset on the raw packet */
-       u8      col;    /* Column -used for shifting */
+       u8      len;
+       u16     pos;
+       u8      col;
 };
 
-/*
- * RF analog register definition
+/**
+ * struct ath5k_rf_reg - RF analog register definition
+ * @bank: RF Buffer Bank number
+ * @index: Register's index on ath5k_rf_regx_idx
+ * @field: The &struct ath5k_rfb_field
+ *
+ * We use this struct to define the set of RF registers
+ * on each chip that we want to tweak. Some RF registers
+ * are common between different chip versions so this saves
+ * us space and complexity because we can refer to an rf
+ * register by it's index no matter what chip we work with
+ * as long as it has that register.
  */
 struct ath5k_rf_reg {
-       u8                      bank;   /* RF Buffer Bank number */
-       u8                      index;  /* Register's index on rf_regs_idx */
-       struct ath5k_rfb_field  field;  /* RF Buffer field for this register */
+       u8                      bank;
+       u8                      index;
+       struct ath5k_rfb_field  field;
 };
 
-/* Map RF registers to indexes
+/**
+ * enum ath5k_rf_regs_idx - Map RF registers to indexes
+ *
  * We do this to handle common bits and make our
  * life easier by using an index for each register
- * instead of a full rfb_field */
+ * instead of a full rfb_field
+ */
 enum ath5k_rf_regs_idx {
        /* BANK 2 */
        AR5K_RF_TURBO = 0,
index ebfae05..4d21df0 100644 (file)
  *
  */
 
-/*
+/**
+ * struct ath5k_ini_rfgain - RF Gain table
+ * @rfg_register: RF Gain register address
+ * @rfg_value: Register value for 5 and 2GHz
+ *
  * Mode-specific RF Gain table (64bytes) for RF5111/5112
  * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
  * RF Gain values are included in AR5K_AR5210_INI)
  */
 struct ath5k_ini_rfgain {
-       u16     rfg_register;   /* RF Gain register address */
+       u16     rfg_register;
        u32     rfg_value[2];   /* [freq (see below)] */
 };
 
@@ -455,18 +459,31 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = {
 #define AR5K_GAIN_CHECK_ADJUST(_g)             \
        ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
 
+/**
+ * struct ath5k_gain_opt_step - An RF gain optimization step
+ * @gos_param: Set of parameters
+ * @gos_gain: Gain
+ */
 struct ath5k_gain_opt_step {
        s8                              gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
        s8                              gos_gain;
 };
 
+/**
+ * struct ath5k_gain_opt - RF Gain optimization ladder
+ * @go_default: The default step
+ * @go_steps_count: How many optimization steps
+ * @go_step: Array of &struct ath5k_gain_opt_step
+ */
 struct ath5k_gain_opt {
        u8                              go_default;
        u8                              go_steps_count;
        const struct ath5k_gain_opt_step        go_step[AR5K_GAIN_STEP_COUNT];
 };
 
+
 /*
+ * RF5111
  * Parameters on gos_param:
  * 1) Tx clip PHY register
  * 2) PWD 90 RF register
@@ -490,6 +507,7 @@ static const struct ath5k_gain_opt rfgain_opt_5111 = {
 };
 
 /*
+ * RF5112
  * Parameters on gos_param:
  * 1) Mixgain ovr RF register
  * 2) PWD 138 RF register
index 49d3f25..390797d 100644 (file)
@@ -34,7 +34,8 @@ ath9k_hw-y:=  \
                ar9002_mac.o \
                ar9003_mac.o \
                ar9003_eeprom.o \
-               ar9003_paprd.o
+               ar9003_paprd.o \
+               ar9003_mci.o
 
 obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
 
index 12a730d..ddeba86 100644 (file)
@@ -18,6 +18,7 @@
 #include "hw-ops.h"
 #include "ar9003_phy.h"
 #include "ar9003_rtt.h"
+#include "ar9003_mci.h"
 
 #define MAX_MEASUREMENT        MAX_IQCAL_MEASUREMENT
 #define MAX_MAG_DELTA  11
@@ -824,7 +825,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
                                                chan_info_tab[i] + offset);
 
                                ath_dbg(common, ATH_DBG_CALIBRATE,
-                                       "IQ RES[%d]=0x%x"
+                                       "IQ_RES[%d]=0x%x "
                                        "IQ_RES[%d]=0x%x\n",
                                        idx, iq_res[idx], idx + 1,
                                        iq_res[idx + 1]);
@@ -934,10 +935,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_cal_data *caldata = ah->caldata;
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        bool txiqcal_done = false, txclcal_done = false;
        bool is_reusable = true, status = true;
        bool run_rtt_cal = false, run_agc_cal;
        bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
+       bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
        u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
                                          AR_PHY_AGC_CONTROL_FLTR_CAL   |
                                          AR_PHY_AGC_CONTROL_PKDET_CAL;
@@ -1005,6 +1008,31 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
        } else if (caldata && !caldata->done_txiqcal_once)
                run_agc_cal = true;
 
+       if (mci && IS_CHAN_2GHZ(chan) &&
+           (mci_hw->bt_state  == MCI_BT_AWAKE) &&
+           run_agc_cal &&
+           !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
+
+               u32 pld[4] = {0, 0, 0, 0};
+
+               /* send CAL_REQ only when BT is AWAKE. */
+               ath_dbg(common, ATH_DBG_MCI, "MCI send WLAN_CAL_REQ 0x%x\n",
+                       mci_hw->wlan_cal_seq);
+               MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);
+               pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;
+               ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
+
+               /* Wait BT_CAL_GRANT for 50ms */
+               ath_dbg(common, ATH_DBG_MCI, "MCI wait for BT_CAL_GRANT");
+
+               if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000))
+                       ath_dbg(common, ATH_DBG_MCI, "MCI got BT_CAL_GRANT");
+               else {
+                       is_reusable = false;
+                       ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is not responding");
+               }
+       }
+
        txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
        REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
        udelay(5);
@@ -1022,6 +1050,21 @@ skip_tx_iqcal:
                                       AR_PHY_AGC_CONTROL_CAL,
                                       0, AH_WAIT_TIMEOUT);
        }
+
+       if (mci && IS_CHAN_2GHZ(chan) &&
+           (mci_hw->bt_state  == MCI_BT_AWAKE) &&
+           run_agc_cal &&
+           !(mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) {
+
+               u32 pld[4] = {0, 0, 0, 0};
+
+               ath_dbg(common, ATH_DBG_MCI, "MCI Send WLAN_CAL_DONE 0x%x\n",
+                       mci_hw->wlan_cal_done);
+               MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);
+               pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;
+               ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
+       }
+
        if (rtt && !run_rtt_cal) {
                agc_ctrl |= agc_supp_cals;
                REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
index a93bd63..4ba6f52 100644 (file)
@@ -4779,7 +4779,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep;
-       u16 twiceMaxEdgePower = MAX_RATE_POWER;
+       u16 twiceMaxEdgePower;
        int i;
        u16 scaledPower = 0, minCtlPower;
        static const u16 ctlModesFor11a[] = {
@@ -4880,6 +4880,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
                        ctlNum = AR9300_NUM_CTLS_5G;
                }
 
+               twiceMaxEdgePower = MAX_RATE_POWER;
                for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) {
                        ath_dbg(common, ATH_DBG_REGULATORY,
                                "LOOP-Ctlidx %d: cfgCtl 0x%2.2x pCtlMode 0x%2.2x ctlIndex 0x%2.2x chan %d\n",
index ccde784..95587e3 100644 (file)
@@ -175,15 +175,47 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
        u32 isr = 0;
        u32 mask2 = 0;
        struct ath9k_hw_capabilities *pCap = &ah->caps;
-       u32 sync_cause = 0;
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 sync_cause = 0, async_cause;
 
-       if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
+       async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
+
+       if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) {
                if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
                                == AR_RTC_STATUS_ON)
                        isr = REG_READ(ah, AR_ISR);
        }
 
+       if (async_cause & AR_INTR_ASYNC_MASK_MCI) {
+               u32 raw_intr, rx_msg_intr;
+
+               rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
+               raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);
+
+               if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef))
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI gets 0xdeadbeef during MCI int processing"
+                               "new raw_intr=0x%08x, new rx_msg_raw=0x%08x, "
+                               "raw_intr=0x%08x, rx_msg_raw=0x%08x\n",
+                               raw_intr, rx_msg_intr, mci->raw_intr,
+                               mci->rx_msg_intr);
+               else {
+                       mci->rx_msg_intr |= rx_msg_intr;
+                       mci->raw_intr |= raw_intr;
+                       *masked |= ATH9K_INT_MCI;
+
+                       if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)
+                               mci->cont_status =
+                                       REG_READ(ah, AR_MCI_CONT_STATUS);
+
+                       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);
+                       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);
+                       ath_dbg(common, ATH_DBG_MCI, "AR_INTR_SYNC_MCI\n");
+
+               }
+       }
+
        sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT;
 
        *masked = 0;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
new file mode 100644 (file)
index 0000000..8599822
--- /dev/null
@@ -0,0 +1,1464 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include "hw.h"
+#include "ar9003_phy.h"
+#include "ar9003_mci.h"
+
+static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah)
+{
+       if (!AR_SREV_9462_20(ah))
+               return;
+
+       REG_RMW_FIELD(ah, AR_MCI_COMMAND2,
+                     AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1);
+       udelay(1);
+       REG_RMW_FIELD(ah, AR_MCI_COMMAND2,
+                     AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 0);
+}
+
+static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,
+                                       u32 bit_position, int time_out)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       while (time_out) {
+
+               if (REG_READ(ah, address) & bit_position) {
+
+                       REG_WRITE(ah, address, bit_position);
+
+                       if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) {
+
+                               if (bit_position &
+                                   AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
+                                       ar9003_mci_reset_req_wakeup(ah);
+
+                               if (bit_position &
+                                   (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
+                                    AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
+                                       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+                                       AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
+
+                               REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+                                         AR_MCI_INTERRUPT_RX_MSG);
+                       }
+                       break;
+               }
+
+               udelay(10);
+               time_out -= 10;
+
+               if (time_out < 0)
+                       break;
+       }
+
+       if (time_out <= 0) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Wait for Reg 0x%08x = 0x%08x timeout.\n",
+                       address, bit_position);
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI INT_RAW = 0x%08x, RX_MSG_RAW = 0x%08x",
+                       REG_READ(ah, AR_MCI_INTERRUPT_RAW),
+                       REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW));
+               time_out = 0;
+       }
+
+       return time_out;
+}
+
+void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done)
+{
+       u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00};
+
+       ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16,
+                               wait_done, false);
+       udelay(5);
+}
+
+void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done)
+{
+       u32 payload = 0x00000000;
+
+       ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1,
+                               wait_done, false);
+}
+
+static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done)
+{
+       ar9003_mci_send_message(ah, MCI_REQ_WAKE, MCI_FLAG_DISABLE_TIMESTAMP,
+                               NULL, 0, wait_done, false);
+       udelay(5);
+}
+
+void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done)
+{
+       ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP,
+                               NULL, 0, wait_done, false);
+}
+
+static void ar9003_mci_send_lna_take(struct ath_hw *ah, bool wait_done)
+{
+       u32 payload = 0x70000000;
+
+       ar9003_mci_send_message(ah, MCI_LNA_TAKE, 0, &payload, 1,
+                               wait_done, false);
+}
+
+static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done)
+{
+       ar9003_mci_send_message(ah, MCI_SYS_SLEEPING,
+                               MCI_FLAG_DISABLE_TIMESTAMP,
+                               NULL, 0, wait_done, false);
+}
+
+static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,
+                                              bool wait_done)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 payload[4] = {0, 0, 0, 0};
+
+       if (!mci->bt_version_known &&
+                       (mci->bt_state != MCI_BT_SLEEP)) {
+               ath_dbg(common, ATH_DBG_MCI, "MCI Send Coex version query\n");
+               MCI_GPM_SET_TYPE_OPCODE(payload,
+                               MCI_GPM_COEX_AGENT, MCI_GPM_COEX_VERSION_QUERY);
+               ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
+                               wait_done, true);
+       }
+}
+
+static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
+                                                    bool wait_done)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 payload[4] = {0, 0, 0, 0};
+
+       ath_dbg(common, ATH_DBG_MCI, "MCI Send Coex version response\n");
+       MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+                       MCI_GPM_COEX_VERSION_RESPONSE);
+       *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) =
+               mci->wlan_ver_major;
+       *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) =
+               mci->wlan_ver_minor;
+       ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
+}
+
+static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
+                                                 bool wait_done)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 *payload = &mci->wlan_channels[0];
+
+       if ((mci->wlan_channels_update == true) &&
+                       (mci->bt_state != MCI_BT_SLEEP)) {
+               MCI_GPM_SET_TYPE_OPCODE(payload,
+               MCI_GPM_COEX_AGENT, MCI_GPM_COEX_WLAN_CHANNELS);
+               ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
+                                       wait_done, true);
+               MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
+       }
+}
+
+static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
+                                               bool wait_done, u8 query_type)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 payload[4] = {0, 0, 0, 0};
+       bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
+                                            MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
+
+       if (mci->bt_state != MCI_BT_SLEEP) {
+
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Send Coex BT Status Query 0x%02X\n", query_type);
+
+               MCI_GPM_SET_TYPE_OPCODE(payload,
+                               MCI_GPM_COEX_AGENT, MCI_GPM_COEX_STATUS_QUERY);
+
+               *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
+               /*
+                * If bt_status_query message is  not sent successfully,
+                * then need_flush_btinfo should be set again.
+                */
+               if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
+                                            wait_done, true)) {
+                       if (query_btinfo) {
+                               mci->need_flush_btinfo = true;
+
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI send bt_status_query fail, "
+                                       "set flush flag again\n");
+                       }
+               }
+
+               if (query_btinfo)
+                       mci->query_bt = false;
+       }
+}
+
+void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
+                                     bool wait_done)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 payload[4] = {0, 0, 0, 0};
+
+       ath_dbg(common, ATH_DBG_MCI, "MCI Send Coex %s BT GPM.\n",
+               (halt) ? "halt" : "unhalt");
+
+       MCI_GPM_SET_TYPE_OPCODE(payload,
+                               MCI_GPM_COEX_AGENT, MCI_GPM_COEX_HALT_BT_GPM);
+
+       if (halt) {
+               mci->query_bt = true;
+               /* Send next unhalt no matter halt sent or not */
+               mci->unhalt_bt_gpm = true;
+               mci->need_flush_btinfo = true;
+               *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) =
+                       MCI_GPM_COEX_BT_GPM_HALT;
+       } else
+               *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) =
+                       MCI_GPM_COEX_BT_GPM_UNHALT;
+
+       ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
+}
+
+
+static void ar9003_mci_prep_interface(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 saved_mci_int_en;
+       u32 mci_timeout = 150;
+
+       mci->bt_state = MCI_BT_SLEEP;
+       saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);
+
+       REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                 REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW));
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+                 REG_READ(ah, AR_MCI_INTERRUPT_RAW));
+
+       /* Remote Reset */
+       ath_dbg(common, ATH_DBG_MCI, "MCI Reset sequence start\n");
+       ath_dbg(common, ATH_DBG_MCI, "MCI send REMOTE_RESET\n");
+       ar9003_mci_remote_reset(ah, true);
+
+       /*
+        * This delay is required for the reset delay worst case value 255 in
+        * MCI_COMMAND2 register
+        */
+
+       if (AR_SREV_9462_10(ah))
+               udelay(252);
+
+       ath_dbg(common, ATH_DBG_MCI, "MCI Send REQ_WAKE to remoter(BT)\n");
+       ar9003_mci_send_req_wake(ah, true);
+
+       if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                               AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
+
+               ath_dbg(common, ATH_DBG_MCI,
+                               "MCI SYS_WAKING from remote(BT)\n");
+               mci->bt_state = MCI_BT_AWAKE;
+
+               if (AR_SREV_9462_10(ah))
+                       udelay(10);
+               /*
+                * we don't need to send more remote_reset at this moment.
+                * If BT receive first remote_reset, then BT HW will
+                * be cleaned up and will be able to receive req_wake
+                * and BT HW will respond sys_waking.
+                * In this case, WLAN will receive BT's HW sys_waking.
+                * Otherwise, if BT SW missed initial remote_reset,
+                * that remote_reset will still clean up BT MCI RX,
+                * and the req_wake will wake BT up,
+                * and BT SW will respond this req_wake with a remote_reset and
+                * sys_waking. In this case, WLAN will receive BT's SW
+                * sys_waking. In either case, BT's RX is cleaned up. So we
+                * don't need to reply BT's remote_reset now, if any.
+                * Similarly, if in any case, WLAN can receive BT's sys_waking,
+                * that means WLAN's RX is also fine.
+                */
+
+               /* Send SYS_WAKING to BT */
+
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI send SW SYS_WAKING to remote BT\n");
+
+               ar9003_mci_send_sys_waking(ah, true);
+               udelay(10);
+
+               /*
+                * Set BT priority interrupt value to be 0xff to
+                * avoid having too many BT PRIORITY interrupts.
+                */
+
+               REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
+               REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
+               REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
+               REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
+               REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
+
+               /*
+                * A contention reset will be received after send out
+                * sys_waking. Also BT priority interrupt bits will be set.
+                * Clear those bits before the next step.
+                */
+
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                         AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+                         AR_MCI_INTERRUPT_BT_PRI);
+
+               if (AR_SREV_9462_10(ah) || mci->is_2g) {
+                       /* Send LNA_TRANS */
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI send LNA_TRANS to BT\n");
+                       ar9003_mci_send_lna_transfer(ah, true);
+                       udelay(5);
+               }
+
+               if (AR_SREV_9462_10(ah) || (mci->is_2g &&
+                                           !mci->update_2g5g)) {
+                       if (ar9003_mci_wait_for_interrupt(ah,
+                               AR_MCI_INTERRUPT_RX_MSG_RAW,
+                               AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
+                               mci_timeout))
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI WLAN has control over the LNA & "
+                                       "BT obeys it\n");
+                       else
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI BT didn't respond to"
+                                       "LNA_TRANS\n");
+               }
+
+               if (AR_SREV_9462_10(ah)) {
+                       /* Send another remote_reset to deassert BT clk_req. */
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI another remote_reset to "
+                               "deassert clk_req\n");
+                       ar9003_mci_remote_reset(ah, true);
+                       udelay(252);
+               }
+       }
+
+       /* Clear the extra redundant SYS_WAKING from BT */
+       if ((mci->bt_state == MCI_BT_AWAKE) &&
+               (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                               AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
+               (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                               AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
+
+                       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                                 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING);
+                       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+                                 AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
+       }
+
+       REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
+}
+
+void ar9003_mci_disable_interrupt(struct ath_hw *ah)
+{
+       REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
+}
+
+void ar9003_mci_enable_interrupt(struct ath_hw *ah)
+{
+
+       REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT);
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
+                 AR_MCI_INTERRUPT_RX_MSG_DEFAULT);
+}
+
+bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints)
+{
+       u32 intr;
+
+       intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
+       return ((intr & ints) == ints);
+}
+
+void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
+                             u32 *rx_msg_intr)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       *raw_intr = mci->raw_intr;
+       *rx_msg_intr = mci->rx_msg_intr;
+
+       /* Clean int bits after the values are read. */
+       mci->raw_intr = 0;
+       mci->rx_msg_intr = 0;
+}
+EXPORT_SYMBOL(ar9003_mci_get_interrupt);
+
+void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+       if (!mci->update_2g5g &&
+           (mci->is_2g != is_2g))
+               mci->update_2g5g = true;
+
+       mci->is_2g = is_2g;
+}
+
+static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 *payload;
+       u32 recv_type, offset;
+
+       if (msg_index == MCI_GPM_INVALID)
+               return false;
+
+       offset = msg_index << 4;
+
+       payload = (u32 *)(mci->gpm_buf + offset);
+       recv_type = MCI_GPM_TYPE(payload);
+
+       if (recv_type == MCI_GPM_RSVD_PATTERN) {
+               ath_dbg(common, ATH_DBG_MCI, "MCI Skip RSVD GPM\n");
+               return false;
+       }
+
+       return true;
+}
+
+static void ar9003_mci_observation_set_up(struct ath_hw *ah)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) {
+
+               ath9k_hw_cfg_output(ah, 3,
+                                       AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);
+               ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK);
+               ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
+               ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
+
+       } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) {
+
+               ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX);
+               ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX);
+               ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
+               ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
+               ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+
+       } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) {
+
+               ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
+               ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
+               ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
+               ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
+
+       } else
+               return;
+
+       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
+
+       if (AR_SREV_9462_20_OR_LATER(ah)) {
+               REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
+                             AR_GLB_DS_JTAG_DISABLE, 1);
+               REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
+                             AR_GLB_WLAN_UART_INTF_EN, 0);
+               REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL,
+                           ATH_MCI_CONFIG_MCI_OBS_GPIO);
+       }
+
+       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0);
+       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1);
+       REG_WRITE(ah, AR_OBS, 0x4b);
+       REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03);
+       REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01);
+       REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02);
+       REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03);
+       REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS,
+                     AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07);
+}
+
+static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done,
+                                               u8 opcode, u32 bt_flags)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 pld[4] = {0, 0, 0, 0};
+
+       MCI_GPM_SET_TYPE_OPCODE(pld,
+                       MCI_GPM_COEX_AGENT, MCI_GPM_COEX_BT_UPDATE_FLAGS);
+
+       *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP)  = opcode;
+       *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF;
+       *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 1) = (bt_flags >> 8) & 0xFF;
+       *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF;
+       *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF;
+
+       ath_dbg(common, ATH_DBG_MCI,
+               "MCI BT_MCI_FLAGS: Send Coex BT Update Flags %s 0x%08x\n",
+               (opcode == MCI_GPM_COEX_BT_FLAGS_READ) ? "READ" :
+               ((opcode == MCI_GPM_COEX_BT_FLAGS_SET) ? "SET" : "CLEAR"),
+                                                               bt_flags);
+
+       return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16,
+                                                       wait_done, true);
+}
+
+void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
+                     bool is_full_sleep)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 regval, thresh;
+
+       ath_dbg(common, ATH_DBG_MCI, "MCI full_sleep = %d, is_2g = %d\n",
+               is_full_sleep, is_2g);
+
+       /*
+        * GPM buffer and scheduling message buffer are not allocated
+        */
+
+       if (!mci->gpm_addr && !mci->sched_addr) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI GPM and schedule buffers are not allocated");
+               return;
+       }
+
+       if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI it's deadbeef, quit mci_reset\n");
+               return;
+       }
+
+       /* Program MCI DMA related registers */
+       REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr);
+       REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len);
+       REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr);
+
+       /*
+       * To avoid MCI state machine be affected by incoming remote MCI msgs,
+       * MCI mode will be enabled later, right before reset the MCI TX and RX.
+       */
+
+       regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |
+                SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |
+                SM(1, AR_BTCOEX_CTRL_PA_SHARED) |
+                SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |
+                SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
+                SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |
+                SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |
+                SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |
+                SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+
+       if (is_2g && (AR_SREV_9462_20(ah)) &&
+               !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
+
+               regval |= SM(1, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+               ath_dbg(common, ATH_DBG_MCI,
+                               "MCI sched one step look ahead\n");
+
+               if (!(mci->config &
+                     ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
+
+                       thresh = MS(mci->config,
+                                   ATH_MCI_CONFIG_AGGR_THRESH);
+                       thresh &= 7;
+                       regval |= SM(1,
+                                    AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN);
+                       regval |= SM(thresh, AR_BTCOEX_CTRL_AGGR_THRESH);
+
+                       REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
+                                     AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
+                       REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
+                                     AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
+
+               } else
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI sched aggr thresh: off\n");
+       } else
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI SCHED one step look ahead off\n");
+
+       if (AR_SREV_9462_10(ah))
+               regval |= SM(1, AR_BTCOEX_CTRL_SPDT_ENABLE_10);
+
+       REG_WRITE(ah, AR_BTCOEX_CTRL, regval);
+
+       if (AR_SREV_9462_20(ah)) {
+               REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
+                           AR_BTCOEX_CTRL_SPDT_ENABLE);
+               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,
+                             AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20);
+       }
+
+       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1);
+       REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
+
+       thresh = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);
+       REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, thresh);
+       REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN);
+
+       /* Resetting the Rx and Tx paths of MCI */
+       regval = REG_READ(ah, AR_MCI_COMMAND2);
+       regval |= SM(1, AR_MCI_COMMAND2_RESET_TX);
+       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+
+       udelay(1);
+
+       regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX);
+       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+
+       if (is_full_sleep) {
+               ar9003_mci_mute_bt(ah);
+               udelay(100);
+       }
+
+       regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
+       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+       udelay(1);
+       regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
+       REG_WRITE(ah, AR_MCI_COMMAND2, regval);
+
+       ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+       REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
+                 (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
+                  SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM)));
+
+       REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+                       AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+
+       if (AR_SREV_9462_20_OR_LATER(ah))
+               ar9003_mci_observation_set_up(ah);
+
+       mci->ready = true;
+       ar9003_mci_prep_interface(ah);
+
+       if (en_int)
+               ar9003_mci_enable_interrupt(ah);
+}
+
+void ar9003_mci_mute_bt(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       /* disable all MCI messages */
+       REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);
+       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);
+       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);
+       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);
+       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);
+       REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+
+       /* wait pending HW messages to flush out */
+       udelay(10);
+
+       /*
+        * Send LNA_TAKE and SYS_SLEEPING when
+        * 1. reset not after resuming from full sleep
+        * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment
+        */
+
+       ath_dbg(common, ATH_DBG_MCI, "MCI Send LNA take\n");
+       ar9003_mci_send_lna_take(ah, true);
+
+       udelay(5);
+
+       ath_dbg(common, ATH_DBG_MCI, "MCI Send sys sleeping\n");
+       ar9003_mci_send_sys_sleeping(ah, true);
+}
+
+void ar9003_mci_sync_bt_state(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 cur_bt_state;
+
+       cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL);
+
+       if (mci->bt_state != cur_bt_state) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI BT state mismatches. old: %d, new: %d\n",
+                       mci->bt_state, cur_bt_state);
+               mci->bt_state = cur_bt_state;
+       }
+
+       if (mci->bt_state != MCI_BT_SLEEP) {
+
+               ar9003_mci_send_coex_version_query(ah, true);
+               ar9003_mci_send_coex_wlan_channels(ah, true);
+
+               if (mci->unhalt_bt_gpm == true) {
+                       ath_dbg(common, ATH_DBG_MCI, "MCI unhalt BT GPM");
+                       ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
+               }
+       }
+}
+
+static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 new_flags, to_set, to_clear;
+
+       if (AR_SREV_9462_20(ah) &&
+           mci->update_2g5g &&
+           (mci->bt_state != MCI_BT_SLEEP)) {
+
+               if (mci->is_2g) {
+                       new_flags = MCI_2G_FLAGS;
+                       to_clear = MCI_2G_FLAGS_CLEAR_MASK;
+                       to_set = MCI_2G_FLAGS_SET_MASK;
+               } else {
+                       new_flags = MCI_5G_FLAGS;
+                       to_clear = MCI_5G_FLAGS_CLEAR_MASK;
+                       to_set = MCI_5G_FLAGS_SET_MASK;
+               }
+
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI BT_MCI_FLAGS: %s 0x%08x clr=0x%08x, set=0x%08x\n",
+               mci->is_2g ? "2G" : "5G", new_flags, to_clear, to_set);
+
+               if (to_clear)
+                       ar9003_mci_send_coex_bt_flags(ah, wait_done,
+                                       MCI_GPM_COEX_BT_FLAGS_CLEAR, to_clear);
+
+               if (to_set)
+                       ar9003_mci_send_coex_bt_flags(ah, wait_done,
+                                       MCI_GPM_COEX_BT_FLAGS_SET, to_set);
+       }
+
+       if (AR_SREV_9462_10(ah) && (mci->bt_state != MCI_BT_SLEEP))
+               mci->update_2g5g = false;
+}
+
+static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
+                                       u32 *payload, bool queue)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u8 type, opcode;
+
+       if (queue) {
+
+               if (payload)
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI ERROR: Send fail: %02x: %02x %02x %02x\n",
+                               header,
+                               *(((u8 *)payload) + 4),
+                               *(((u8 *)payload) + 5),
+                               *(((u8 *)payload) + 6));
+               else
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI ERROR: Send fail: %02x\n", header);
+       }
+
+       /* check if the message is to be queued */
+       if (header != MCI_GPM)
+               return;
+
+       type = MCI_GPM_TYPE(payload);
+       opcode = MCI_GPM_OPCODE(payload);
+
+       if (type != MCI_GPM_COEX_AGENT)
+               return;
+
+       switch (opcode) {
+       case MCI_GPM_COEX_BT_UPDATE_FLAGS:
+
+               if (AR_SREV_9462_10(ah))
+                       break;
+
+               if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) ==
+                               MCI_GPM_COEX_BT_FLAGS_READ)
+                       break;
+
+               mci->update_2g5g = queue;
+
+               if (queue)
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI BT_MCI_FLAGS: 2G5G status <queued> %s.\n",
+                               mci->is_2g ? "2G" : "5G");
+               else
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI BT_MCI_FLAGS: 2G5G status <sent> %s.\n",
+                               mci->is_2g ? "2G" : "5G");
+
+               break;
+
+       case MCI_GPM_COEX_WLAN_CHANNELS:
+
+               mci->wlan_channels_update = queue;
+               if (queue)
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI WLAN channel map <queued>\n");
+               else
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI WLAN channel map <sent>\n");
+               break;
+
+       case MCI_GPM_COEX_HALT_BT_GPM:
+
+               if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
+                               MCI_GPM_COEX_BT_GPM_UNHALT) {
+
+                       mci->unhalt_bt_gpm = queue;
+
+                       if (queue)
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI UNHALT BT GPM <queued>\n");
+                       else {
+                               mci->halted_bt_gpm = false;
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI UNHALT BT GPM <sent>\n");
+                       }
+               }
+
+               if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
+                               MCI_GPM_COEX_BT_GPM_HALT) {
+
+                       mci->halted_bt_gpm = !queue;
+
+                       if (queue)
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI HALT BT GPM <not sent>\n");
+                       else
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI UNHALT BT GPM <sent>\n");
+               }
+
+               break;
+       default:
+               break;
+       }
+}
+
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+       if (mci->update_2g5g) {
+               if (mci->is_2g) {
+
+                       ar9003_mci_send_2g5g_status(ah, true);
+                       ath_dbg(common, ATH_DBG_MCI, "MCI Send LNA trans\n");
+                       ar9003_mci_send_lna_transfer(ah, true);
+                       udelay(5);
+
+                       REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+                                   AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+
+                       if (AR_SREV_9462_20(ah)) {
+                               REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
+                                           AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+                               if (!(mci->config &
+                                     ATH_MCI_CONFIG_DISABLE_OSLA)) {
+                                       REG_SET_BIT(ah, AR_BTCOEX_CTRL,
+                                       AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+                               }
+                       }
+               } else {
+                       ath_dbg(common, ATH_DBG_MCI, "MCI Send LNA take\n");
+                       ar9003_mci_send_lna_take(ah, true);
+                       udelay(5);
+
+                       REG_SET_BIT(ah, AR_MCI_TX_CTRL,
+                                   AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+
+                       if (AR_SREV_9462_20(ah)) {
+                               REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
+                                           AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+                               REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
+                                       AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+                       }
+
+                       ar9003_mci_send_2g5g_status(ah, true);
+               }
+       }
+}
+
+bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
+                            u32 *payload, u8 len, bool wait_done,
+                            bool check_bt)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       bool msg_sent = false;
+       u32 regval;
+       u32 saved_mci_int_en;
+       int i;
+
+       saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);
+       regval = REG_READ(ah, AR_BTCOEX_CTRL);
+
+       if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) {
+
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Not sending 0x%x. MCI is not enabled. "
+                       "full_sleep = %d\n", header,
+                       (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0);
+
+               ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
+               return false;
+
+       } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) {
+
+               ath_dbg(common, ATH_DBG_MCI,
+               "MCI Don't send message 0x%x. BT is in sleep state\n", header);
+
+               ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
+               return false;
+       }
+
+       if (wait_done)
+               REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
+
+       /* Need to clear SW_MSG_DONE raw bit before wait */
+
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+                 (AR_MCI_INTERRUPT_SW_MSG_DONE |
+                  AR_MCI_INTERRUPT_MSG_FAIL_MASK));
+
+       if (payload) {
+               for (i = 0; (i * 4) < len; i++)
+                       REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4),
+                                 *(payload + i));
+       }
+
+       REG_WRITE(ah, AR_MCI_COMMAND0,
+                 (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP),
+                     AR_MCI_COMMAND0_DISABLE_TIMESTAMP) |
+                  SM(len, AR_MCI_COMMAND0_LEN) |
+                  SM(header, AR_MCI_COMMAND0_HEADER)));
+
+       if (wait_done &&
+           !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW,
+                                       AR_MCI_INTERRUPT_SW_MSG_DONE, 500)))
+               ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
+       else {
+               ar9003_mci_queue_unsent_gpm(ah, header, payload, false);
+               msg_sent = true;
+       }
+
+       if (wait_done)
+               REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
+
+       return msg_sent;
+}
+EXPORT_SYMBOL(ar9003_mci_send_message);
+
+void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
+                     u16 len, u32 sched_addr)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       void *sched_buf = (void *)((char *) gpm_buf + (sched_addr - gpm_addr));
+
+       mci->gpm_addr = gpm_addr;
+       mci->gpm_buf = gpm_buf;
+       mci->gpm_len = len;
+       mci->sched_addr = sched_addr;
+       mci->sched_buf = sched_buf;
+
+       ar9003_mci_reset(ah, true, true, true);
+}
+EXPORT_SYMBOL(ar9003_mci_setup);
+
+void ar9003_mci_cleanup(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       /* Turn off MCI and Jupiter mode. */
+       REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00);
+       ath_dbg(common, ATH_DBG_MCI, "MCI ar9003_mci_cleanup\n");
+       ar9003_mci_disable_interrupt(ah);
+}
+EXPORT_SYMBOL(ar9003_mci_cleanup);
+
+static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type,
+                                        u8 gpm_opcode, u32 *p_gpm)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u8 *p_data = (u8 *) p_gpm;
+
+       if (gpm_type != MCI_GPM_COEX_AGENT)
+               return;
+
+       switch (gpm_opcode) {
+       case MCI_GPM_COEX_VERSION_QUERY:
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM COEX Version Query\n");
+               ar9003_mci_send_coex_version_response(ah, true);
+               break;
+       case MCI_GPM_COEX_VERSION_RESPONSE:
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM COEX Version Response\n");
+               mci->bt_ver_major =
+                       *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION);
+               mci->bt_ver_minor =
+                       *(p_data + MCI_GPM_COEX_B_MINOR_VERSION);
+               mci->bt_version_known = true;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI BT Coex version: %d.%d\n",
+                       mci->bt_ver_major,
+                       mci->bt_ver_minor);
+               break;
+       case MCI_GPM_COEX_STATUS_QUERY:
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM COEX Status Query = 0x%02X.\n",
+                       *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP));
+               mci->wlan_channels_update = true;
+               ar9003_mci_send_coex_wlan_channels(ah, true);
+               break;
+       case MCI_GPM_COEX_BT_PROFILE_INFO:
+               mci->query_bt = true;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM COEX BT_Profile_Info\n");
+               break;
+       case MCI_GPM_COEX_BT_STATUS_UPDATE:
+               mci->query_bt = true;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM COEX BT_Status_Update "
+                       "SEQ=%d (drop&query)\n", *(p_gpm + 3));
+               break;
+       default:
+               break;
+       }
+}
+
+u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
+                           u8 gpm_opcode, int time_out)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 *p_gpm = NULL, mismatch = 0, more_data;
+       u32 offset;
+       u8 recv_type = 0, recv_opcode = 0;
+       bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE);
+
+       more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE;
+
+       while (time_out > 0) {
+               if (p_gpm) {
+                       MCI_GPM_RECYCLE(p_gpm);
+                       p_gpm = NULL;
+               }
+
+               if (more_data != MCI_GPM_MORE)
+                       time_out = ar9003_mci_wait_for_interrupt(ah,
+                                       AR_MCI_INTERRUPT_RX_MSG_RAW,
+                                       AR_MCI_INTERRUPT_RX_MSG_GPM,
+                                       time_out);
+
+               if (!time_out)
+                       break;
+
+               offset = ar9003_mci_state(ah,
+                               MCI_STATE_NEXT_GPM_OFFSET, &more_data);
+
+               if (offset == MCI_GPM_INVALID)
+                       continue;
+
+               p_gpm = (u32 *) (mci->gpm_buf + offset);
+               recv_type = MCI_GPM_TYPE(p_gpm);
+               recv_opcode = MCI_GPM_OPCODE(p_gpm);
+
+               if (MCI_GPM_IS_CAL_TYPE(recv_type)) {
+
+                       if (recv_type == gpm_type) {
+
+                               if ((gpm_type == MCI_GPM_BT_CAL_DONE) &&
+                                   !b_is_bt_cal_done) {
+                                       gpm_type = MCI_GPM_BT_CAL_GRANT;
+                                       ath_dbg(common, ATH_DBG_MCI,
+                                               "MCI Recv BT_CAL_DONE"
+                                               "wait BT_CAL_GRANT\n");
+                                       continue;
+                               }
+
+                               break;
+                       }
+               } else if ((recv_type == gpm_type) &&
+                          (recv_opcode == gpm_opcode))
+                       break;
+
+               /* not expected message */
+
+               /*
+                * check if it's cal_grant
+                *
+                * When we're waiting for cal_grant in reset routine,
+                * it's possible that BT sends out cal_request at the
+                * same time. Since BT's calibration doesn't happen
+                * that often, we'll let BT completes calibration then
+                * we continue to wait for cal_grant from BT.
+                * Orginal: Wait BT_CAL_GRANT.
+                * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait
+                * BT_CAL_DONE -> Wait BT_CAL_GRANT.
+                */
+
+               if ((gpm_type == MCI_GPM_BT_CAL_GRANT) &&
+                   (recv_type == MCI_GPM_BT_CAL_REQ)) {
+
+                       u32 payload[4] = {0, 0, 0, 0};
+
+                       gpm_type = MCI_GPM_BT_CAL_DONE;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI Rcv BT_CAL_REQ, send WLAN_CAL_GRANT\n");
+
+                       MCI_GPM_SET_CAL_TYPE(payload,
+                                       MCI_GPM_WLAN_CAL_GRANT);
+
+                       ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
+                                               false, false);
+
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI now wait for BT_CAL_DONE\n");
+
+                       continue;
+               } else {
+                       ath_dbg(common, ATH_DBG_MCI, "MCI GPM subtype"
+                                       "not match 0x%x\n", *(p_gpm + 1));
+                       mismatch++;
+                       ar9003_mci_process_gpm_extra(ah, recv_type,
+                                       recv_opcode, p_gpm);
+               }
+       }
+       if (p_gpm) {
+               MCI_GPM_RECYCLE(p_gpm);
+               p_gpm = NULL;
+       }
+
+       if (time_out <= 0) {
+               time_out = 0;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI GPM received timeout, mismatch = %d\n", mismatch);
+       } else
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Receive GPM type=0x%x, code=0x%x\n",
+                       gpm_type, gpm_opcode);
+
+       while (more_data == MCI_GPM_MORE) {
+
+               ath_dbg(common, ATH_DBG_MCI, "MCI discard remaining GPM\n");
+               offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
+                                         &more_data);
+
+               if (offset == MCI_GPM_INVALID)
+                       break;
+
+               p_gpm = (u32 *) (mci->gpm_buf + offset);
+               recv_type = MCI_GPM_TYPE(p_gpm);
+               recv_opcode = MCI_GPM_OPCODE(p_gpm);
+
+               if (!MCI_GPM_IS_CAL_TYPE(recv_type))
+                       ar9003_mci_process_gpm_extra(ah, recv_type,
+                                                    recv_opcode, p_gpm);
+
+               MCI_GPM_RECYCLE(p_gpm);
+       }
+
+       return time_out;
+}
+
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 value = 0, more_gpm = 0, gpm_ptr;
+       u8 query_type;
+
+       switch (state_type) {
+       case MCI_STATE_ENABLE:
+               if (mci->ready) {
+
+                       value = REG_READ(ah, AR_BTCOEX_CTRL);
+
+                       if ((value == 0xdeadbeef) || (value == 0xffffffff))
+                               value = 0;
+               }
+               value &= AR_BTCOEX_CTRL_MCI_MODE_EN;
+               break;
+       case MCI_STATE_INIT_GPM_OFFSET:
+               value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI GPM initial WRITE_PTR=%d\n", value);
+               mci->gpm_idx = value;
+               break;
+       case MCI_STATE_NEXT_GPM_OFFSET:
+       case MCI_STATE_LAST_GPM_OFFSET:
+               /*
+               * This could be useful to avoid new GPM message interrupt which
+               * may lead to spurious interrupt after power sleep, or multiple
+               * entry of ath_mci_intr().
+               * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
+               * alleviate this effect, but clearing GPM RX interrupt bit is
+               * safe, because whether this is called from hw or driver code
+               * there must be an interrupt bit set/triggered initially
+               */
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                         AR_MCI_INTERRUPT_RX_MSG_GPM);
+
+               gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+               value = gpm_ptr;
+
+               if (value == 0)
+                       value = mci->gpm_len - 1;
+               else if (value >= mci->gpm_len) {
+                       if (value != 0xFFFF) {
+                               value = 0;
+                               ath_dbg(common, ATH_DBG_MCI, "MCI GPM offset"
+                                       "out of range\n");
+                       }
+               } else
+                       value--;
+
+               if (value == 0xFFFF) {
+                       value = MCI_GPM_INVALID;
+                       more_gpm = MCI_GPM_NOMORE;
+                       ath_dbg(common, ATH_DBG_MCI, "MCI GPM ptr invalid"
+                               "@ptr=%d, offset=%d, more=GPM_NOMORE\n",
+                               gpm_ptr, value);
+               } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) {
+
+                       if (gpm_ptr == mci->gpm_idx) {
+                               value = MCI_GPM_INVALID;
+                               more_gpm = MCI_GPM_NOMORE;
+
+                               ath_dbg(common, ATH_DBG_MCI, "MCI GPM message"
+                                       "not available @ptr=%d, @offset=%d,"
+                                       "more=GPM_NOMORE\n", gpm_ptr, value);
+                       } else {
+                               for (;;) {
+
+                                       u32 temp_index;
+
+                                       /* skip reserved GPM if any */
+
+                                       if (value != mci->gpm_idx)
+                                               more_gpm = MCI_GPM_MORE;
+                                       else
+                                               more_gpm = MCI_GPM_NOMORE;
+
+                                       temp_index = mci->gpm_idx;
+                                       mci->gpm_idx++;
+
+                                       if (mci->gpm_idx >=
+                                           mci->gpm_len)
+                                               mci->gpm_idx = 0;
+
+                                       ath_dbg(common, ATH_DBG_MCI,
+                                               "MCI GPM message got ptr=%d,"
+                                               "@offset=%d, more=%d\n",
+                                               gpm_ptr, temp_index,
+                                               (more_gpm == MCI_GPM_MORE));
+
+                                       if (ar9003_mci_is_gpm_valid(ah,
+                                                               temp_index)) {
+                                               value = temp_index;
+                                               break;
+                                       }
+
+                                       if (more_gpm == MCI_GPM_NOMORE) {
+                                               value = MCI_GPM_INVALID;
+                                               break;
+                                       }
+                               }
+                       }
+                       if (p_data)
+                               *p_data = more_gpm;
+                       }
+
+                       if (value != MCI_GPM_INVALID)
+                               value <<= 4;
+
+                       break;
+       case MCI_STATE_LAST_SCHD_MSG_OFFSET:
+               value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
+                                   AR_MCI_RX_LAST_SCHD_MSG_INDEX);
+               /* Make it in bytes */
+               value <<= 4;
+               break;
+
+       case MCI_STATE_REMOTE_SLEEP:
+               value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
+                          AR_MCI_RX_REMOTE_SLEEP) ?
+                       MCI_BT_SLEEP : MCI_BT_AWAKE;
+               break;
+
+       case MCI_STATE_CONT_RSSI_POWER:
+               value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER);
+                       break;
+
+       case MCI_STATE_CONT_PRIORITY:
+               value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY);
+               break;
+
+       case MCI_STATE_CONT_TXRX:
+               value = MS(mci->cont_status, AR_MCI_CONT_TXRX);
+               break;
+
+       case MCI_STATE_BT:
+               value = mci->bt_state;
+               break;
+
+       case MCI_STATE_SET_BT_SLEEP:
+               mci->bt_state = MCI_BT_SLEEP;
+               break;
+
+       case MCI_STATE_SET_BT_AWAKE:
+               mci->bt_state = MCI_BT_AWAKE;
+               ar9003_mci_send_coex_version_query(ah, true);
+               ar9003_mci_send_coex_wlan_channels(ah, true);
+
+               if (mci->unhalt_bt_gpm) {
+
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI unhalt BT GPM\n");
+                       ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
+               }
+
+               ar9003_mci_2g5g_switch(ah, true);
+               break;
+
+       case MCI_STATE_SET_BT_CAL_START:
+               mci->bt_state = MCI_BT_CAL_START;
+               break;
+
+       case MCI_STATE_SET_BT_CAL:
+               mci->bt_state = MCI_BT_CAL;
+               break;
+
+       case MCI_STATE_RESET_REQ_WAKE:
+               ar9003_mci_reset_req_wakeup(ah);
+               mci->update_2g5g = true;
+
+               if ((AR_SREV_9462_20_OR_LATER(ah)) &&
+                   (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK)) {
+                       /* Check if we still have control of the GPIOs */
+                       if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) &
+                                     ATH_MCI_CONFIG_MCI_OBS_GPIO) !=
+                                       ATH_MCI_CONFIG_MCI_OBS_GPIO) {
+
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI reconfigure observation");
+                               ar9003_mci_observation_set_up(ah);
+                       }
+               }
+               break;
+
+       case MCI_STATE_SEND_WLAN_COEX_VERSION:
+               ar9003_mci_send_coex_version_response(ah, true);
+               break;
+
+       case MCI_STATE_SET_BT_COEX_VERSION:
+
+               if (!p_data)
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI Set BT Coex version with NULL data!!\n");
+               else {
+                       mci->bt_ver_major = (*p_data >> 8) & 0xff;
+                       mci->bt_ver_minor = (*p_data) & 0xff;
+                       mci->bt_version_known = true;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI BT version set: %d.%d\n",
+                               mci->bt_ver_major,
+                               mci->bt_ver_minor);
+               }
+               break;
+
+       case MCI_STATE_SEND_WLAN_CHANNELS:
+               if (p_data) {
+                       if (((mci->wlan_channels[1] & 0xffff0000) ==
+                            (*(p_data + 1) & 0xffff0000)) &&
+                           (mci->wlan_channels[2] == *(p_data + 2)) &&
+                           (mci->wlan_channels[3] == *(p_data + 3)))
+                               break;
+
+                       mci->wlan_channels[0] = *p_data++;
+                       mci->wlan_channels[1] = *p_data++;
+                       mci->wlan_channels[2] = *p_data++;
+                       mci->wlan_channels[3] = *p_data++;
+               }
+               mci->wlan_channels_update = true;
+               ar9003_mci_send_coex_wlan_channels(ah, true);
+               break;
+
+       case MCI_STATE_SEND_VERSION_QUERY:
+               ar9003_mci_send_coex_version_query(ah, true);
+               break;
+
+       case MCI_STATE_SEND_STATUS_QUERY:
+               query_type = (AR_SREV_9462_10(ah)) ?
+                               MCI_GPM_COEX_QUERY_BT_ALL_INFO :
+                               MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
+
+               ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
+               break;
+
+       case MCI_STATE_NEED_FLUSH_BT_INFO:
+                       /*
+                        * btcoex_hw.mci.unhalt_bt_gpm means whether it's
+                        * needed to send UNHALT message. It's set whenever
+                        * there's a request to send HALT message.
+                        * mci_halted_bt_gpm means whether HALT message is sent
+                        * out successfully.
+                        *
+                        * Checking (mci_unhalt_bt_gpm == false) instead of
+                        * checking (ah->mci_halted_bt_gpm == false) will make
+                        * sure currently is in UNHALT-ed mode and BT can
+                        * respond to status query.
+                        */
+                       value = (!mci->unhalt_bt_gpm &&
+                                mci->need_flush_btinfo) ? 1 : 0;
+                       if (p_data)
+                               mci->need_flush_btinfo =
+                                       (*p_data != 0) ? true : false;
+                       break;
+
+       case MCI_STATE_RECOVER_RX:
+
+               ath_dbg(common, ATH_DBG_MCI, "MCI hw RECOVER_RX\n");
+               ar9003_mci_prep_interface(ah);
+               mci->query_bt = true;
+               mci->need_flush_btinfo = true;
+               ar9003_mci_send_coex_wlan_channels(ah, true);
+               ar9003_mci_2g5g_switch(ah, true);
+               break;
+
+       case MCI_STATE_NEED_FTP_STOMP:
+               value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
+               break;
+
+       case MCI_STATE_NEED_TUNING:
+               value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
+               break;
+
+       default:
+               break;
+
+       }
+
+       return value;
+}
+EXPORT_SYMBOL(ar9003_mci_state);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
new file mode 100644 (file)
index 0000000..798da11
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2010-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.
+ */
+
+#ifndef AR9003_MCI_H
+#define AR9003_MCI_H
+
+#define MCI_FLAG_DISABLE_TIMESTAMP      0x00000001      /* Disable time stamp */
+
+/* Default remote BT device MCI COEX version */
+#define MCI_GPM_COEX_MAJOR_VERSION_DEFAULT  3
+#define MCI_GPM_COEX_MINOR_VERSION_DEFAULT  0
+
+/* Local WLAN MCI COEX version */
+#define MCI_GPM_COEX_MAJOR_VERSION_WLAN     3
+#define MCI_GPM_COEX_MINOR_VERSION_WLAN     0
+
+enum mci_gpm_coex_query_type {
+       MCI_GPM_COEX_QUERY_BT_ALL_INFO      = BIT(0),
+       MCI_GPM_COEX_QUERY_BT_TOPOLOGY      = BIT(1),
+       MCI_GPM_COEX_QUERY_BT_DEBUG         = BIT(2),
+};
+
+enum mci_gpm_coex_halt_bt_gpm {
+       MCI_GPM_COEX_BT_GPM_UNHALT,
+       MCI_GPM_COEX_BT_GPM_HALT
+};
+
+enum mci_gpm_coex_bt_update_flags_op {
+       MCI_GPM_COEX_BT_FLAGS_READ,
+       MCI_GPM_COEX_BT_FLAGS_SET,
+       MCI_GPM_COEX_BT_FLAGS_CLEAR
+};
+
+#define MCI_NUM_BT_CHANNELS     79
+
+#define MCI_BT_MCI_FLAGS_UPDATE_CORR          0x00000002
+#define MCI_BT_MCI_FLAGS_UPDATE_HDR           0x00000004
+#define MCI_BT_MCI_FLAGS_UPDATE_PLD           0x00000008
+#define MCI_BT_MCI_FLAGS_LNA_CTRL             0x00000010
+#define MCI_BT_MCI_FLAGS_DEBUG                0x00000020
+#define MCI_BT_MCI_FLAGS_SCHED_MSG            0x00000040
+#define MCI_BT_MCI_FLAGS_CONT_MSG             0x00000080
+#define MCI_BT_MCI_FLAGS_COEX_GPM             0x00000100
+#define MCI_BT_MCI_FLAGS_CPU_INT_MSG          0x00000200
+#define MCI_BT_MCI_FLAGS_MCI_MODE             0x00000400
+#define MCI_BT_MCI_FLAGS_AR9462_MODE          0x00001000
+#define MCI_BT_MCI_FLAGS_OTHER                0x00010000
+
+#define MCI_DEFAULT_BT_MCI_FLAGS              0x00011dde
+
+#define MCI_TOGGLE_BT_MCI_FLAGS  (MCI_BT_MCI_FLAGS_UPDATE_CORR | \
+                                 MCI_BT_MCI_FLAGS_UPDATE_HDR  | \
+                                 MCI_BT_MCI_FLAGS_UPDATE_PLD  | \
+                                 MCI_BT_MCI_FLAGS_MCI_MODE)
+
+#define MCI_2G_FLAGS_CLEAR_MASK   0x00000000
+#define MCI_2G_FLAGS_SET_MASK     MCI_TOGGLE_BT_MCI_FLAGS
+#define MCI_2G_FLAGS              MCI_DEFAULT_BT_MCI_FLAGS
+
+#define MCI_5G_FLAGS_CLEAR_MASK   MCI_TOGGLE_BT_MCI_FLAGS
+#define MCI_5G_FLAGS_SET_MASK     0x00000000
+#define MCI_5G_FLAGS              (MCI_DEFAULT_BT_MCI_FLAGS & \
+                                  ~MCI_TOGGLE_BT_MCI_FLAGS)
+
+/*
+ * Default value for AR9462 is 0x00002201
+ */
+#define ATH_MCI_CONFIG_CONCUR_TX            0x00000003
+#define ATH_MCI_CONFIG_MCI_OBS_MCI          0x00000004
+#define ATH_MCI_CONFIG_MCI_OBS_TXRX         0x00000008
+#define ATH_MCI_CONFIG_MCI_OBS_BT           0x00000010
+#define ATH_MCI_CONFIG_DISABLE_MCI_CAL      0x00000020
+#define ATH_MCI_CONFIG_DISABLE_OSLA         0x00000040
+#define ATH_MCI_CONFIG_DISABLE_FTP_STOMP    0x00000080
+#define ATH_MCI_CONFIG_AGGR_THRESH          0x00000700
+#define ATH_MCI_CONFIG_AGGR_THRESH_S        8
+#define ATH_MCI_CONFIG_DISABLE_AGGR_THRESH  0x00000800
+#define ATH_MCI_CONFIG_CLK_DIV              0x00003000
+#define ATH_MCI_CONFIG_CLK_DIV_S            12
+#define ATH_MCI_CONFIG_DISABLE_TUNING       0x00004000
+#define ATH_MCI_CONFIG_MCI_WEIGHT_DBG       0x40000000
+#define ATH_MCI_CONFIG_DISABLE_MCI          0x80000000
+
+#define ATH_MCI_CONFIG_MCI_OBS_MASK     (ATH_MCI_CONFIG_MCI_OBS_MCI  | \
+                                        ATH_MCI_CONFIG_MCI_OBS_TXRX | \
+                                        ATH_MCI_CONFIG_MCI_OBS_BT)
+#define ATH_MCI_CONFIG_MCI_OBS_GPIO     0x0000002F
+
+#endif
index 497d746..ed64114 100644 (file)
 #define AR_PHY_TEST_CTL_TSTADC_EN_S       8
 #define AR_PHY_TEST_CTL_RX_OBS_SEL        0x3C00
 #define AR_PHY_TEST_CTL_RX_OBS_SEL_S      10
+#define AR_PHY_TEST_CTL_DEBUGPORT_SEL    0xe0000000
+#define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S          29
 
 
 #define AR_PHY_TSTDAC            (AR_SM_BASE + 0x168)
 
 /* GLB Registers */
 #define AR_GLB_BASE    0x20000
+#define AR_GLB_GPIO_CONTROL    (AR_GLB_BASE)
 #define AR_PHY_GLB_CONTROL     (AR_GLB_BASE + 0x44)
 #define AR_GLB_SCRATCH(_ah)    (AR_GLB_BASE + \
                                        (AR_SREV_9462_20(_ah) ? 0x4c : 0x50))
index 93b45b4..afc156a 100644 (file)
@@ -462,7 +462,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);
 #define ATH_LED_PIN_9287               8
 #define ATH_LED_PIN_9300               10
 #define ATH_LED_PIN_9485               6
-#define ATH_LED_PIN_9462               0
+#define ATH_LED_PIN_9462               4
 
 #ifdef CONFIG_MAC80211_LEDS
 void ath_init_leds(struct ath_softc *sc);
@@ -647,6 +647,7 @@ struct ath_softc {
        struct delayed_work tx_complete_work;
        struct delayed_work hw_pll_work;
        struct ath_btcoex btcoex;
+       struct ath_mci_coex mci_coex;
 
        struct ath_descdma txsdma;
 
index 9ac28d9..bbb2081 100644 (file)
@@ -21,7 +21,7 @@ enum ath_bt_mode {
        ATH_BT_COEX_MODE_LEGACY,        /* legacy rx_clear mode */
        ATH_BT_COEX_MODE_UNSLOTTED,     /* untimed/unslotted mode */
        ATH_BT_COEX_MODE_SLOTTED,       /* slotted mode */
-       ATH_BT_COEX_MODE_DISALBED,      /* coexistence disabled */
+       ATH_BT_COEX_MODE_DISABLED,      /* coexistence disabled */
 };
 
 struct ath_btcoex_config {
index d5e5db1..278361c 100644 (file)
@@ -54,8 +54,39 @@ enum ath_btcoex_scheme {
        ATH_BTCOEX_CFG_MCI,
 };
 
+struct ath9k_hw_mci {
+       u32 raw_intr;
+       u32 rx_msg_intr;
+       u32 cont_status;
+       u32 gpm_addr;
+       u32 gpm_len;
+       u32 gpm_idx;
+       u32 sched_addr;
+       u32 wlan_channels[4];
+       u32 wlan_cal_seq;
+       u32 wlan_cal_done;
+       u32 config;
+       u8 *gpm_buf;
+       u8 *sched_buf;
+       bool ready;
+       bool update_2g5g;
+       bool is_2g;
+       bool query_bt;
+       bool unhalt_bt_gpm; /* need send UNHALT */
+       bool halted_bt_gpm; /* HALT sent */
+       bool need_flush_btinfo;
+       bool bt_version_known;
+       bool wlan_channels_update;
+       u8 wlan_ver_major;
+       u8 wlan_ver_minor;
+       u8 bt_ver_major;
+       u8 bt_ver_minor;
+       u8 bt_state;
+};
+
 struct ath_btcoex_hw {
        enum ath_btcoex_scheme scheme;
+       struct ath9k_hw_mci mci;
        bool enabled;
        u8 wlanactive_gpio;
        u8 btactive_gpio;
index 9a7520f..61fcab0 100644 (file)
@@ -473,7 +473,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
 
        int i;
        u16 twiceMinEdgePower;
-       u16 twiceMaxEdgePower = MAX_RATE_POWER;
+       u16 twiceMaxEdgePower;
        u16 scaledPower = 0, minCtlPower;
        u16 numCtlModes;
        const u16 *pCtlMode;
@@ -542,9 +542,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
                else
                        freq = centers.ctl_center;
 
-               if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
-                   ah->eep_ops->get_eeprom_rev(ah) <= 2)
-                       twiceMaxEdgePower = MAX_RATE_POWER;
+               twiceMaxEdgePower = MAX_RATE_POWER;
 
                for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) &&
                             pEepData->ctlIndex[i]; i++) {
index 4f5c50a..0981c07 100644 (file)
@@ -569,7 +569,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
 #define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6
 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10
 
-       u16 twiceMaxEdgePower = MAX_RATE_POWER;
+       u16 twiceMaxEdgePower;
        int i;
        struct cal_ctl_data_ar9287 *rep;
        struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
@@ -669,6 +669,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
                else
                        freq = centers.ctl_center;
 
+               twiceMaxEdgePower = MAX_RATE_POWER;
                /* Walk through the CTL indices stored in EEPROM */
                for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
                        struct cal_ctl_edges *pRdEdgesPower;
index 81e6296..55a21d3 100644 (file)
@@ -1000,7 +1000,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN   9 /* 10*log10(3)*2 */
 
        struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
-       u16 twiceMaxEdgePower = MAX_RATE_POWER;
+       u16 twiceMaxEdgePower;
        int i;
        struct cal_ctl_data *rep;
        struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
@@ -1121,9 +1121,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
                else
                        freq = centers.ctl_center;
 
-               if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
-                   ah->eep_ops->get_eeprom_rev(ah) <= 2)
-                       twiceMaxEdgePower = MAX_RATE_POWER;
+               twiceMaxEdgePower = MAX_RATE_POWER;
 
                for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
                        if ((((cfgCtl & ~CTL_MODE_M) |
index 662ab7e..6ceb2e1 100644 (file)
@@ -1350,6 +1350,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 {
+       bool ret = false;
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                REG_WRITE(ah, AR_WA, ah->WARegVal);
@@ -1361,13 +1362,20 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
 
        switch (type) {
        case ATH9K_RESET_POWER_ON:
-               return ath9k_hw_set_reset_power_on(ah);
+               ret = ath9k_hw_set_reset_power_on(ah);
+               break;
        case ATH9K_RESET_WARM:
        case ATH9K_RESET_COLD:
-               return ath9k_hw_set_reset(ah, type);
+               ret = ath9k_hw_set_reset(ah, type);
+               break;
        default:
-               return false;
+               break;
        }
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+               REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+
+       return ret;
 }
 
 static bool ath9k_hw_chip_reset(struct ath_hw *ah,
@@ -1506,6 +1514,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                   struct ath9k_hw_cal_data *caldata, bool bChannelChange)
 {
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        u32 saveLedState;
        struct ath9k_channel *curchan = ah->curchan;
        u32 saveDefAntenna;
@@ -1513,6 +1522,53 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        u64 tsf = 0;
        int i, r;
        bool allow_fbs = false;
+       bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
+       bool save_fullsleep = ah->chip_fullsleep;
+
+       if (mci) {
+
+               ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
+
+               if (mci_hw->bt_state == MCI_BT_CAL_START) {
+                       u32 payload[4] = {0, 0, 0, 0};
+
+                       ath_dbg(common, ATH_DBG_MCI, "MCI stop rx for BT CAL");
+
+                       mci_hw->bt_state = MCI_BT_CAL;
+
+                       /*
+                        * MCI FIX: disable mci interrupt here. This is to avoid
+                        * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and
+                        * lead to mci_intr reentry.
+                        */
+
+                       ar9003_mci_disable_interrupt(ah);
+
+                       ath_dbg(common, ATH_DBG_MCI, "send WLAN_CAL_GRANT");
+                       MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
+                       ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
+                                               16, true, false);
+
+                       ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is calibrating");
+
+                       /* Wait BT calibration to be completed for 25ms */
+
+                       if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,
+                                                                 0, 25000))
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI got BT_CAL_DONE\n");
+                       else
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI ### BT cal takes to long, force"
+                                       "bt_state to be bt_awake\n");
+                       mci_hw->bt_state = MCI_BT_AWAKE;
+                       /* MCI FIX: enable mci interrupt here */
+                       ar9003_mci_enable_interrupt(ah);
+
+                       return true;
+               }
+       }
+
 
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
@@ -1550,12 +1606,29 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                if (ath9k_hw_channel_change(ah, chan)) {
                        ath9k_hw_loadnf(ah, ah->curchan);
                        ath9k_hw_start_nfcal(ah, true);
+                       if (mci && mci_hw->ready)
+                               ar9003_mci_2g5g_switch(ah, true);
+
                        if (AR_SREV_9271(ah))
                                ar9002_hw_load_ani_reg(ah, chan);
                        return 0;
                }
        }
 
+       if (mci) {
+               ar9003_mci_disable_interrupt(ah);
+
+               if (mci_hw->ready && !save_fullsleep) {
+                       ar9003_mci_mute_bt(ah);
+                       udelay(20);
+                       REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
+               }
+
+               mci_hw->bt_state = MCI_BT_SLEEP;
+               mci_hw->ready = false;
+       }
+
+
        saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
        if (saveDefAntenna == 0)
                saveDefAntenna = 1;
@@ -1611,6 +1684,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (r)
                return r;
 
+       if (mci)
+               ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
+
        /*
         * Some AR91xx SoC devices frequently fail to accept TSF writes
         * right after the chip reset. When that happens, write a new
@@ -1728,6 +1804,55 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_loadnf(ah, chan);
        ath9k_hw_start_nfcal(ah, true);
 
+       if (mci && mci_hw->ready) {
+
+               if (IS_CHAN_2GHZ(chan) &&
+                   (mci_hw->bt_state == MCI_BT_SLEEP)) {
+
+                       if (ar9003_mci_check_int(ah,
+                           AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
+                           ar9003_mci_check_int(ah,
+                           AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
+
+                               /*
+                                * BT is sleeping. Check if BT wakes up during
+                                * WLAN calibration. If BT wakes up during
+                                * WLAN calibration, need to go through all
+                                * message exchanges again and recal.
+                                */
+
+                               ath_dbg(common, ATH_DBG_MCI, "MCI BT wakes up"
+                                       "during WLAN calibration\n");
+
+                               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                                         AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
+                                         AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
+                               ath_dbg(common, ATH_DBG_MCI, "MCI send"
+                                       "REMOTE_RESET\n");
+                               ar9003_mci_remote_reset(ah, true);
+                               ar9003_mci_send_sys_waking(ah, true);
+                               udelay(1);
+                               if (IS_CHAN_2GHZ(chan))
+                                       ar9003_mci_send_lna_transfer(ah, true);
+
+                               mci_hw->bt_state = MCI_BT_AWAKE;
+
+                               ath_dbg(common, ATH_DBG_MCI, "MCI re-cal\n");
+
+                               if (caldata) {
+                                       caldata->done_txiqcal_once = false;
+                                       caldata->done_txclcal_once = false;
+                                       caldata->rtt_hist.num_readings = 0;
+                               }
+
+                               if (!ath9k_hw_init_cal(ah, chan))
+                                       return -EIO;
+
+                       }
+               }
+               ar9003_mci_enable_interrupt(ah);
+       }
+
        ENABLE_REGWRITE_BUFFER(ah);
 
        ath9k_hw_restore_chainmask(ah);
@@ -1770,6 +1895,21 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (ah->btcoex_hw.enabled)
                ath9k_hw_btcoex_enable(ah);
 
+       if (mci && mci_hw->ready) {
+               /*
+                * check BT state again to make
+                * sure it's not changed.
+                */
+
+               ar9003_mci_sync_bt_state(ah);
+               ar9003_mci_2g5g_switch(ah, true);
+
+               if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
+                               (mci_hw->query_bt == true)) {
+                       mci_hw->need_flush_btinfo = true;
+               }
+       }
+
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ar9003_hw_bb_watchdog_config(ah);
 
@@ -1933,6 +2073,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 {
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        int status = true, setChip = true;
        static const char *modes[] = {
                "AWAKE",
@@ -1950,12 +2091,35 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
        switch (mode) {
        case ATH9K_PM_AWAKE:
                status = ath9k_hw_set_power_awake(ah, setChip);
+
+               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+                       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+
                break;
        case ATH9K_PM_FULL_SLEEP:
+
+               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
+                       if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
+                               (mci->bt_state != MCI_BT_SLEEP) &&
+                               !mci->halted_bt_gpm) {
+                               ath_dbg(common, ATH_DBG_MCI, "MCI halt BT GPM"
+                                               "(full_sleep)");
+                               ar9003_mci_send_coex_halt_bt_gpm(ah,
+                                                                true, true);
+                       }
+
+                       mci->ready = false;
+                       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+               }
+
                ath9k_set_power_sleep(ah, setChip);
                ah->chip_fullsleep = true;
                break;
        case ATH9K_PM_NETWORK_SLEEP:
+
+               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+                       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
+
                ath9k_set_power_network_sleep(ah, setChip);
                break;
        default:
@@ -2148,6 +2312,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 
        if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah))
                chip_chainmask = 1;
+       else if (AR_SREV_9462(ah))
+               chip_chainmask = 3;
        else if (!AR_SREV_9280_20_OR_LATER(ah))
                chip_chainmask = 7;
        else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah))
@@ -2233,7 +2399,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
        if (common->btcoex_enabled) {
-               if (AR_SREV_9300_20_OR_LATER(ah)) {
+               if (AR_SREV_9462(ah))
+                       btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
+               else if (AR_SREV_9300_20_OR_LATER(ah)) {
                        btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
                        btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
                        btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
@@ -2331,7 +2499,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ah->enabled_cals |= TX_IQ_CAL;
-               if (!AR_SREV_9330(ah))
+               if (AR_SREV_9485_OR_LATER(ah))
                        ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
        }
        if (AR_SREV_9462(ah))
index 3cb878c..c9c3b18 100644 (file)
 #define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL  4
 #define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    5
 #define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      6
+#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA      0x16
+#define AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK       0x17
+#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA        0x18
+#define AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK         0x19
+#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX           0x14
+#define AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX           0x13
+#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX           9
+#define AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX           8
+#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_STROBE      0x1d
+#define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA        0x1e
 
 #define AR_GPIOD_MASK               0x00001FFF
 #define AR_GPIO_BIT(_gpio)          (1 << (_gpio))
@@ -266,6 +276,7 @@ enum ath9k_int {
        ATH9K_INT_TX = 0x00000040,
        ATH9K_INT_TXDESC = 0x00000080,
        ATH9K_INT_TIM_TIMER = 0x00000100,
+       ATH9K_INT_MCI = 0x00000200,
        ATH9K_INT_BB_WATCHDOG = 0x00000400,
        ATH9K_INT_TXURN = 0x00000800,
        ATH9K_INT_MIB = 0x00001000,
@@ -417,6 +428,25 @@ enum ath9k_rx_qtype {
        ATH9K_RX_QUEUE_MAX,
 };
 
+enum mci_message_header {              /* length of payload */
+       MCI_LNA_CTRL     = 0x10,        /* len = 0 */
+       MCI_CONT_NACK    = 0x20,        /* len = 0 */
+       MCI_CONT_INFO    = 0x30,        /* len = 4 */
+       MCI_CONT_RST     = 0x40,        /* len = 0 */
+       MCI_SCHD_INFO    = 0x50,        /* len = 16 */
+       MCI_CPU_INT      = 0x60,        /* len = 4 */
+       MCI_SYS_WAKING   = 0x70,        /* len = 0 */
+       MCI_GPM          = 0x80,        /* len = 16 */
+       MCI_LNA_INFO     = 0x90,        /* len = 1 */
+       MCI_LNA_STATE    = 0x94,
+       MCI_LNA_TAKE     = 0x98,
+       MCI_LNA_TRANS    = 0x9c,
+       MCI_SYS_SLEEPING = 0xa0,        /* len = 0 */
+       MCI_REQ_WAKE     = 0xc0,        /* len = 0 */
+       MCI_DEBUG_16     = 0xfe,        /* len = 2 */
+       MCI_REMOTE_RESET = 0xff         /* len = 16 */
+};
+
 enum ath_mci_gpm_coex_profile_type {
        MCI_GPM_COEX_PROFILE_UNKNOWN,
        MCI_GPM_COEX_PROFILE_RFCOMM,
@@ -427,6 +457,132 @@ enum ath_mci_gpm_coex_profile_type {
        MCI_GPM_COEX_PROFILE_MAX
 };
 
+/* MCI GPM/Coex opcode/type definitions */
+enum {
+       MCI_GPM_COEX_W_GPM_PAYLOAD      = 1,
+       MCI_GPM_COEX_B_GPM_TYPE         = 4,
+       MCI_GPM_COEX_B_GPM_OPCODE       = 5,
+       /* MCI_GPM_WLAN_CAL_REQ, MCI_GPM_WLAN_CAL_DONE */
+       MCI_GPM_WLAN_CAL_W_SEQUENCE     = 2,
+
+       /* MCI_GPM_COEX_VERSION_QUERY */
+       /* MCI_GPM_COEX_VERSION_RESPONSE */
+       MCI_GPM_COEX_B_MAJOR_VERSION    = 6,
+       MCI_GPM_COEX_B_MINOR_VERSION    = 7,
+       /* MCI_GPM_COEX_STATUS_QUERY */
+       MCI_GPM_COEX_B_BT_BITMAP        = 6,
+       MCI_GPM_COEX_B_WLAN_BITMAP      = 7,
+       /* MCI_GPM_COEX_HALT_BT_GPM */
+       MCI_GPM_COEX_B_HALT_STATE       = 6,
+       /* MCI_GPM_COEX_WLAN_CHANNELS */
+       MCI_GPM_COEX_B_CHANNEL_MAP      = 6,
+       /* MCI_GPM_COEX_BT_PROFILE_INFO */
+       MCI_GPM_COEX_B_PROFILE_TYPE     = 6,
+       MCI_GPM_COEX_B_PROFILE_LINKID   = 7,
+       MCI_GPM_COEX_B_PROFILE_STATE    = 8,
+       MCI_GPM_COEX_B_PROFILE_ROLE     = 9,
+       MCI_GPM_COEX_B_PROFILE_RATE     = 10,
+       MCI_GPM_COEX_B_PROFILE_VOTYPE   = 11,
+       MCI_GPM_COEX_H_PROFILE_T        = 12,
+       MCI_GPM_COEX_B_PROFILE_W        = 14,
+       MCI_GPM_COEX_B_PROFILE_A        = 15,
+       /* MCI_GPM_COEX_BT_STATUS_UPDATE */
+       MCI_GPM_COEX_B_STATUS_TYPE      = 6,
+       MCI_GPM_COEX_B_STATUS_LINKID    = 7,
+       MCI_GPM_COEX_B_STATUS_STATE     = 8,
+       /* MCI_GPM_COEX_BT_UPDATE_FLAGS */
+       MCI_GPM_COEX_W_BT_FLAGS         = 6,
+       MCI_GPM_COEX_B_BT_FLAGS_OP      = 10
+};
+
+enum mci_gpm_subtype {
+       MCI_GPM_BT_CAL_REQ      = 0,
+       MCI_GPM_BT_CAL_GRANT    = 1,
+       MCI_GPM_BT_CAL_DONE     = 2,
+       MCI_GPM_WLAN_CAL_REQ    = 3,
+       MCI_GPM_WLAN_CAL_GRANT  = 4,
+       MCI_GPM_WLAN_CAL_DONE   = 5,
+       MCI_GPM_COEX_AGENT      = 0x0c,
+       MCI_GPM_RSVD_PATTERN    = 0xfe,
+       MCI_GPM_RSVD_PATTERN32  = 0xfefefefe,
+       MCI_GPM_BT_DEBUG        = 0xff
+};
+
+enum mci_bt_state {
+       MCI_BT_SLEEP,
+       MCI_BT_AWAKE,
+       MCI_BT_CAL_START,
+       MCI_BT_CAL
+};
+
+/* Type of state query */
+enum mci_state_type {
+       MCI_STATE_ENABLE,
+       MCI_STATE_INIT_GPM_OFFSET,
+       MCI_STATE_NEXT_GPM_OFFSET,
+       MCI_STATE_LAST_GPM_OFFSET,
+       MCI_STATE_BT,
+       MCI_STATE_SET_BT_SLEEP,
+       MCI_STATE_SET_BT_AWAKE,
+       MCI_STATE_SET_BT_CAL_START,
+       MCI_STATE_SET_BT_CAL,
+       MCI_STATE_LAST_SCHD_MSG_OFFSET,
+       MCI_STATE_REMOTE_SLEEP,
+       MCI_STATE_CONT_RSSI_POWER,
+       MCI_STATE_CONT_PRIORITY,
+       MCI_STATE_CONT_TXRX,
+       MCI_STATE_RESET_REQ_WAKE,
+       MCI_STATE_SEND_WLAN_COEX_VERSION,
+       MCI_STATE_SET_BT_COEX_VERSION,
+       MCI_STATE_SEND_WLAN_CHANNELS,
+       MCI_STATE_SEND_VERSION_QUERY,
+       MCI_STATE_SEND_STATUS_QUERY,
+       MCI_STATE_NEED_FLUSH_BT_INFO,
+       MCI_STATE_SET_CONCUR_TX_PRI,
+       MCI_STATE_RECOVER_RX,
+       MCI_STATE_NEED_FTP_STOMP,
+       MCI_STATE_NEED_TUNING,
+       MCI_STATE_DEBUG,
+       MCI_STATE_MAX
+};
+
+enum mci_gpm_coex_opcode {
+       MCI_GPM_COEX_VERSION_QUERY,
+       MCI_GPM_COEX_VERSION_RESPONSE,
+       MCI_GPM_COEX_STATUS_QUERY,
+       MCI_GPM_COEX_HALT_BT_GPM,
+       MCI_GPM_COEX_WLAN_CHANNELS,
+       MCI_GPM_COEX_BT_PROFILE_INFO,
+       MCI_GPM_COEX_BT_STATUS_UPDATE,
+       MCI_GPM_COEX_BT_UPDATE_FLAGS
+};
+
+#define MCI_GPM_NOMORE  0
+#define MCI_GPM_MORE    1
+#define MCI_GPM_INVALID 0xffffffff
+
+#define MCI_GPM_RECYCLE(_p_gpm)        do {                      \
+       *(((u32 *)_p_gpm) + MCI_GPM_COEX_W_GPM_PAYLOAD) = \
+                               MCI_GPM_RSVD_PATTERN32;   \
+} while (0)
+
+#define MCI_GPM_TYPE(_p_gpm)   \
+       (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) & 0xff)
+
+#define MCI_GPM_OPCODE(_p_gpm) \
+       (*(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) & 0xff)
+
+#define MCI_GPM_SET_CAL_TYPE(_p_gpm, _cal_type)        do {                       \
+       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_cal_type) & 0xff;\
+} while (0)
+
+#define MCI_GPM_SET_TYPE_OPCODE(_p_gpm, _type, _opcode) do {              \
+       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_TYPE) = (_type) & 0xff;    \
+       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_GPM_OPCODE) = (_opcode) & 0xff;\
+} while (0)
+
+#define MCI_GPM_IS_CAL_TYPE(_type) ((_type) <= MCI_GPM_WLAN_CAL_DONE)
+
 struct ath9k_beacon_state {
        u32 bs_nexttbtt;
        u32 bs_nextdtim;
@@ -1047,6 +1203,32 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
 void ath9k_hw_proc_mib_event(struct ath_hw *ah);
 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
 
+bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
+                            u32 *payload, u8 len, bool wait_done,
+                            bool check_bt);
+void ar9003_mci_mute_bt(struct ath_hw *ah);
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
+void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
+                     u16 len, u32 sched_addr);
+void ar9003_mci_cleanup(struct ath_hw *ah);
+void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
+                                     bool wait_done);
+u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
+                           u8 gpm_opcode, int time_out);
+void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g);
+void ar9003_mci_disable_interrupt(struct ath_hw *ah);
+void ar9003_mci_enable_interrupt(struct ath_hw *ah);
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
+                     bool is_full_sleep);
+bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints);
+void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_sync_bt_state(struct ath_hw *ah);
+void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
+                             u32 *rx_msg_intr);
+
 #define ATH9K_CLOCK_RATE_CCK           22
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM     40
 #define ATH9K_CLOCK_RATE_2GHZ_OFDM     44
index e046de9..e9711e2 100644 (file)
@@ -408,6 +408,7 @@ fail:
 static int ath9k_init_btcoex(struct ath_softc *sc)
 {
        struct ath_txq *txq;
+       struct ath_hw *ah = sc->sc_ah;
        int r;
 
        switch (sc->sc_ah->btcoex_hw.scheme) {
@@ -423,9 +424,38 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
                        return -1;
                txq = sc->tx.txq_map[WME_AC_BE];
                ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
+               sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               break;
+       case ATH_BTCOEX_CFG_MCI:
                sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
                sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
                INIT_LIST_HEAD(&sc->btcoex.mci.info);
+
+               r = ath_mci_setup(sc);
+               if (r)
+                       return r;
+
+               if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
+                       ah->btcoex_hw.mci.ready = false;
+                       ah->btcoex_hw.mci.bt_state = 0;
+                       ah->btcoex_hw.mci.bt_ver_major = 3;
+                       ah->btcoex_hw.mci.bt_ver_minor = 0;
+                       ah->btcoex_hw.mci.bt_version_known = false;
+                       ah->btcoex_hw.mci.update_2g5g = true;
+                       ah->btcoex_hw.mci.is_2g = true;
+                       ah->btcoex_hw.mci.wlan_channels_update = false;
+                       ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
+                       ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
+                       ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
+                       ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
+                       ah->btcoex_hw.mci.query_bt = true;
+                       ah->btcoex_hw.mci.unhalt_bt_gpm = true;
+                       ah->btcoex_hw.mci.halted_bt_gpm = false;
+                       ah->btcoex_hw.mci.need_flush_btinfo = false;
+                       ah->btcoex_hw.mci.wlan_cal_seq = 0;
+                       ah->btcoex_hw.mci.wlan_cal_done = 0;
+                       ah->btcoex_hw.mci.config = 0x2201;
+               }
                break;
        default:
                WARN_ON(1);
@@ -839,6 +869,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
            sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
                ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
 
+       if (sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_MCI)
+               ath_mci_cleanup(sc);
+
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
                if (ATH_TXQ_SETUP(sc, i))
                        ath_tx_cleanupq(sc, &sc->tx.txq[i]);
index ecdb6fd..0e4fbb3 100644 (file)
@@ -760,7 +760,10 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
                return true;
 
        host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
-       if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS))
+
+       if (((host_isr & AR_INTR_MAC_IRQ) ||
+            (host_isr & AR_INTR_ASYNC_MASK_MCI)) &&
+           (host_isr != AR_INTR_SPURIOUS))
                return true;
 
        host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
@@ -798,6 +801,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        u32 sync_default = AR_INTR_SYNC_DEFAULT;
+       u32 async_mask;
 
        if (!(ah->imask & ATH9K_INT_GLOBAL))
                return;
@@ -812,13 +816,16 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
        if (AR_SREV_9340(ah))
                sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
 
+       async_mask = AR_INTR_MAC_IRQ;
+
+       if (ah->imask & ATH9K_INT_MCI)
+               async_mask |= AR_INTR_ASYNC_MASK_MCI;
+
        ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n");
        REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
        if (!AR_SREV_9100(ah)) {
-               REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
-                         AR_INTR_MAC_IRQ);
-               REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
-
+               REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, async_mask);
+               REG_WRITE(ah, AR_INTR_ASYNC_MASK, async_mask);
 
                REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
                REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default);
index e43c41c..fd59c1f 100644 (file)
@@ -742,6 +742,9 @@ void ath9k_tasklet(unsigned long data)
                if (status & ATH9K_INT_GENTIMER)
                        ath_gen_timer_isr(sc->sc_ah);
 
+       if (status & ATH9K_INT_MCI)
+               ath_mci_intr(sc);
+
 out:
        /* re-enable hardware interrupt */
        ath9k_hw_enable_interrupts(ah);
@@ -764,7 +767,8 @@ irqreturn_t ath_isr(int irq, void *dev)
                ATH9K_INT_BMISS |               \
                ATH9K_INT_CST |                 \
                ATH9K_INT_TSFOOR |              \
-               ATH9K_INT_GENTIMER)
+               ATH9K_INT_GENTIMER |            \
+               ATH9K_INT_MCI)
 
        struct ath_softc *sc = dev;
        struct ath_hw *ah = sc->sc_ah;
@@ -1119,6 +1123,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
        if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
                ah->imask |= ATH9K_INT_CST;
 
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+               ah->imask |= ATH9K_INT_MCI;
+
        sc->sc_flags &= ~SC_OP_INVALID;
        sc->sc_ah->is_monitoring = false;
 
index 0fbb141..d678040 100644 (file)
@@ -14,6 +14,9 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
 #include "ath9k.h"
 #include "mci.h"
 
@@ -181,6 +184,56 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
        ath9k_btcoex_timer_resume(sc);
 }
 
+
+static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 payload[4] = {0, 0, 0, 0};
+
+       switch (opcode) {
+       case MCI_GPM_BT_CAL_REQ:
+
+               ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_REQ\n");
+
+               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
+                       ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL);
+                       ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+               } else
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI State mismatches: %d\n",
+                               ar9003_mci_state(ah, MCI_STATE_BT, NULL));
+
+               break;
+
+       case MCI_GPM_BT_CAL_DONE:
+
+               ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_DONE\n");
+
+               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_CAL)
+                       ath_dbg(common, ATH_DBG_MCI, "MCI error illegal!\n");
+               else
+                       ath_dbg(common, ATH_DBG_MCI, "MCI BT not in CAL state\n");
+
+               break;
+
+       case MCI_GPM_BT_CAL_GRANT:
+
+               ath_dbg(common, ATH_DBG_MCI, "MCI received BT_CAL_GRANT\n");
+
+               /* Send WLAN_CAL_DONE for now */
+               ath_dbg(common, ATH_DBG_MCI, "MCI send WLAN_CAL_DONE\n");
+               MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
+               ar9003_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload,
+                                       16, false, true);
+               break;
+
+       default:
+               ath_dbg(common, ATH_DBG_MCI, "MCI Unknown GPM CAL message\n");
+               break;
+       }
+}
+
 void ath_mci_process_profile(struct ath_softc *sc,
                             struct ath_mci_profile_info *info)
 {
@@ -252,3 +305,369 @@ void ath_mci_process_status(struct ath_softc *sc,
        if (old_num_mgmt != mci->num_mgmt)
                ath_mci_update_scheme(sc);
 }
+
+static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_mci_profile_info profile_info;
+       struct ath_mci_profile_status profile_status;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       u32 version;
+       u8 major;
+       u8 minor;
+       u32 seq_num;
+
+       switch (opcode) {
+
+       case MCI_GPM_COEX_VERSION_QUERY:
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM COEX Version Query.\n");
+               version = ar9003_mci_state(ah,
+                               MCI_STATE_SEND_WLAN_COEX_VERSION, NULL);
+               break;
+
+       case MCI_GPM_COEX_VERSION_RESPONSE:
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM COEX Version Response.\n");
+               major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION);
+               minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION);
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI BT Coex version: %d.%d\n", major, minor);
+               version = (major << 8) + minor;
+               version = ar9003_mci_state(ah,
+                         MCI_STATE_SET_BT_COEX_VERSION, &version);
+               break;
+
+       case MCI_GPM_COEX_STATUS_QUERY:
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM COEX Status Query = 0x%02x.\n",
+                       *(rx_payload + MCI_GPM_COEX_B_WLAN_BITMAP));
+               ar9003_mci_state(ah,
+               MCI_STATE_SEND_WLAN_CHANNELS, NULL);
+               break;
+
+       case MCI_GPM_COEX_BT_PROFILE_INFO:
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM Coex BT profile info\n");
+               memcpy(&profile_info,
+                      (rx_payload + MCI_GPM_COEX_B_PROFILE_TYPE), 10);
+
+               if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN)
+                   || (profile_info.type >=
+                                           MCI_GPM_COEX_PROFILE_MAX)) {
+
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "illegal profile type = %d,"
+                               "state = %d\n", profile_info.type,
+                               profile_info.start);
+                       break;
+               }
+
+               ath_mci_process_profile(sc, &profile_info);
+               break;
+
+       case MCI_GPM_COEX_BT_STATUS_UPDATE:
+               profile_status.is_link = *(rx_payload +
+                                          MCI_GPM_COEX_B_STATUS_TYPE);
+               profile_status.conn_handle = *(rx_payload +
+                                              MCI_GPM_COEX_B_STATUS_LINKID);
+               profile_status.is_critical = *(rx_payload +
+                                              MCI_GPM_COEX_B_STATUS_STATE);
+
+               seq_num = *((u32 *)(rx_payload + 12));
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI Recv GPM COEX BT_Status_Update: "
+                       "is_link=%d, linkId=%d, state=%d, SEQ=%d\n",
+                       profile_status.is_link, profile_status.conn_handle,
+                       profile_status.is_critical, seq_num);
+
+               ath_mci_process_status(sc, &profile_status);
+               break;
+
+       default:
+               ath_dbg(common, ATH_DBG_MCI,
+               "MCI Unknown GPM COEX message = 0x%02x\n", opcode);
+               break;
+       }
+}
+
+static int ath_mci_buf_alloc(struct ath_softc *sc, struct ath_mci_buf *buf)
+{
+       int error = 0;
+
+       buf->bf_addr = dma_alloc_coherent(sc->dev, buf->bf_len,
+                                         &buf->bf_paddr, GFP_KERNEL);
+
+       if (buf->bf_addr == NULL) {
+               error = -ENOMEM;
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       memset(buf, 0, sizeof(*buf));
+       return error;
+}
+
+static void ath_mci_buf_free(struct ath_softc *sc, struct ath_mci_buf *buf)
+{
+       if (buf->bf_addr) {
+               dma_free_coherent(sc->dev, buf->bf_len, buf->bf_addr,
+                                                       buf->bf_paddr);
+               memset(buf, 0, sizeof(*buf));
+       }
+}
+
+int ath_mci_setup(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_mci_coex *mci = &sc->mci_coex;
+       int error = 0;
+
+       mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE;
+
+       if (ath_mci_buf_alloc(sc, &mci->sched_buf)) {
+               ath_dbg(common, ATH_DBG_FATAL, "MCI buffer alloc failed\n");
+               error = -ENOMEM;
+               goto fail;
+       }
+
+       mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE;
+
+       memset(mci->sched_buf.bf_addr, MCI_GPM_RSVD_PATTERN,
+                                               mci->sched_buf.bf_len);
+
+       mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE;
+       mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr +
+                                                       mci->sched_buf.bf_len;
+       mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len;
+
+       /* initialize the buffer */
+       memset(mci->gpm_buf.bf_addr, MCI_GPM_RSVD_PATTERN, mci->gpm_buf.bf_len);
+
+       ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr,
+                        mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
+                        mci->sched_buf.bf_paddr);
+fail:
+       return error;
+}
+
+void ath_mci_cleanup(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_mci_coex *mci = &sc->mci_coex;
+
+       /*
+        * both schedule and gpm buffers will be released
+        */
+       ath_mci_buf_free(sc, &mci->sched_buf);
+       ar9003_mci_cleanup(ah);
+}
+
+void ath_mci_intr(struct ath_softc *sc)
+{
+       struct ath_mci_coex *mci = &sc->mci_coex;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 mci_int, mci_int_rxmsg;
+       u32 offset, subtype, opcode;
+       u32 *pgpm;
+       u32 more_data = MCI_GPM_MORE;
+       bool skip_gpm = false;
+
+       ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg);
+
+       if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) {
+
+               ar9003_mci_state(sc->sc_ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI interrupt but MCI disabled\n");
+
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI interrupt: intr = 0x%x, intr_rxmsg = 0x%x\n",
+                       mci_int, mci_int_rxmsg);
+               return;
+       }
+
+       if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) {
+               u32 payload[4] = { 0xffffffff, 0xffffffff,
+                                  0xffffffff, 0xffffff00};
+
+               /*
+                * The following REMOTE_RESET and SYS_WAKING used to sent
+                * only when BT wake up. Now they are always sent, as a
+                * recovery method to reset BT MCI's RX alignment.
+                */
+               ath_dbg(common, ATH_DBG_MCI, "MCI interrupt send REMOTE_RESET\n");
+
+               ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0,
+                                       payload, 16, true, false);
+               ath_dbg(common, ATH_DBG_MCI, "MCI interrupt send SYS_WAKING\n");
+               ar9003_mci_send_message(ah, MCI_SYS_WAKING, 0,
+                                       NULL, 0, true, false);
+
+               mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE;
+               ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE, NULL);
+
+               /*
+                * always do this for recovery and 2G/5G toggling and LNA_TRANS
+                */
+               ath_dbg(common, ATH_DBG_MCI, "MCI Set BT state to AWAKE.\n");
+               ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL);
+       }
+
+       /* Processing SYS_WAKING/SYS_SLEEPING */
+       if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) {
+               mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING;
+
+               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) {
+
+                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL)
+                                       == MCI_BT_SLEEP)
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI BT stays in sleep mode\n");
+                       else {
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI Set BT state to AWAKE.\n");
+                               ar9003_mci_state(ah,
+                                                MCI_STATE_SET_BT_AWAKE, NULL);
+                       }
+               } else
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI BT stays in AWAKE mode.\n");
+       }
+
+       if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) {
+
+               mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING;
+
+               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
+
+                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL)
+                                       == MCI_BT_AWAKE)
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI BT stays in AWAKE mode.\n");
+                       else {
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI SetBT state to SLEEP\n");
+                               ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP,
+                                                NULL);
+                       }
+               } else
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "MCI BT stays in SLEEP mode\n");
+       }
+
+       if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
+           (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
+
+               ath_dbg(common, ATH_DBG_MCI, "MCI RX broken, skip GPM msgs\n");
+               ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL);
+               skip_gpm = true;
+       }
+
+       if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) {
+
+               mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO;
+               offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET,
+                                         NULL);
+       }
+
+       if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) {
+
+               mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM;
+
+               while (more_data == MCI_GPM_MORE) {
+
+                       pgpm = mci->gpm_buf.bf_addr;
+                       offset = ar9003_mci_state(ah,
+                                       MCI_STATE_NEXT_GPM_OFFSET, &more_data);
+
+                       if (offset == MCI_GPM_INVALID)
+                               break;
+
+                       pgpm += (offset >> 2);
+
+                       /*
+                        * The first dword is timer.
+                        * The real data starts from 2nd dword.
+                        */
+
+                       subtype = MCI_GPM_TYPE(pgpm);
+                       opcode = MCI_GPM_OPCODE(pgpm);
+
+                       if (!skip_gpm) {
+
+                               if (MCI_GPM_IS_CAL_TYPE(subtype))
+                                       ath_mci_cal_msg(sc, subtype,
+                                                       (u8 *) pgpm);
+                               else {
+                                       switch (subtype) {
+                                       case MCI_GPM_COEX_AGENT:
+                                               ath_mci_msg(sc, opcode,
+                                                           (u8 *) pgpm);
+                                               break;
+                                       default:
+                                               break;
+                                       }
+                               }
+                       }
+                       MCI_GPM_RECYCLE(pgpm);
+               }
+       }
+
+       if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_HW_MSG_MASK) {
+
+               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL)
+                       mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL;
+
+               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO) {
+                       mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO;
+                       ath_dbg(common, ATH_DBG_MCI, "MCI LNA_INFO\n");
+               }
+
+               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) {
+
+                       int value_dbm = ar9003_mci_state(ah,
+                                       MCI_STATE_CONT_RSSI_POWER, NULL);
+
+                       mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO;
+
+                       if (ar9003_mci_state(ah, MCI_STATE_CONT_TXRX, NULL))
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI CONT_INFO: "
+                                       "(tx) pri = %d, pwr = %d dBm\n",
+                                       ar9003_mci_state(ah,
+                                               MCI_STATE_CONT_PRIORITY, NULL),
+                                       value_dbm);
+                       else
+                               ath_dbg(common, ATH_DBG_MCI,
+                                       "MCI CONT_INFO:"
+                                       "(rx) pri = %d,pwr = %d dBm\n",
+                                       ar9003_mci_state(ah,
+                                               MCI_STATE_CONT_PRIORITY, NULL),
+                                       value_dbm);
+               }
+
+               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) {
+                       mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_NACK;
+                       ath_dbg(common, ATH_DBG_MCI, "MCI CONT_NACK\n");
+               }
+
+               if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST) {
+                       mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_RST;
+                       ath_dbg(common, ATH_DBG_MCI, "MCI CONT_RST\n");
+               }
+       }
+
+       if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
+           (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT))
+               mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
+                            AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
+
+       if (mci_int_rxmsg & 0xfffffffe)
+               ath_dbg(common, ATH_DBG_MCI,
+                       "MCI not processed mci_int_rxmsg = 0x%x\n",
+                       mci_int_rxmsg);
+}
index 9590c61..b71bded 100644 (file)
@@ -17,6 +17,9 @@
 #ifndef MCI_H
 #define MCI_H
 
+#define ATH_MCI_SCHED_BUF_SIZE         (16 * 16) /* 16 entries, 4 dword each */
+#define ATH_MCI_GPM_MAX_ENTRY          16
+#define ATH_MCI_GPM_BUF_SIZE           (ATH_MCI_GPM_MAX_ENTRY * 16)
 #define ATH_MCI_DEF_BT_PERIOD          40
 #define ATH_MCI_BDR_DUTY_CYCLE         20
 #define ATH_MCI_MAX_DUTY_CYCLE         90
@@ -110,9 +113,26 @@ struct ath_mci_profile {
        u8 num_bdr;
 };
 
+
+struct ath_mci_buf {
+       void *bf_addr;          /* virtual addr of desc */
+       dma_addr_t bf_paddr;    /* physical addr of buffer */
+       u32 bf_len;             /* len of data */
+};
+
+struct ath_mci_coex {
+       atomic_t mci_cal_flag;
+       struct ath_mci_buf sched_buf;
+       struct ath_mci_buf gpm_buf;
+       u32 bt_cal_start;
+};
+
 void ath_mci_flush_profile(struct ath_mci_profile *mci);
 void ath_mci_process_profile(struct ath_softc *sc,
                             struct ath_mci_profile_info *info);
 void ath_mci_process_status(struct ath_softc *sc,
                            struct ath_mci_profile_status *status);
+int ath_mci_setup(struct ath_softc *sc);
+void ath_mci_cleanup(struct ath_softc *sc);
+void ath_mci_intr(struct ath_softc *sc);
 #endif
index 4c8e296..e031841 100644 (file)
@@ -475,7 +475,6 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
 
        return rfilt;
 
-#undef RX_FILTER_PRESERVE
 }
 
 int ath_startrecv(struct ath_softc *sc)
@@ -1923,15 +1922,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                        skb = hdr_skb;
                }
 
-               /*
-                * change the default rx antenna if rx diversity chooses the
-                * other antenna 3 times in a row.
-                */
-               if (sc->rx.defant != rs.rs_antenna) {
-                       if (++sc->rx.rxotherant >= 3)
-                               ath_setdefantenna(sc, rs.rs_antenna);
-               } else {
-                       sc->rx.rxotherant = 0;
+
+               if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
+
+                       /*
+                        * change the default rx antenna if rx diversity
+                        * chooses the other antenna 3 times in a row.
+                        */
+                       if (sc->rx.defant != rs.rs_antenna) {
+                               if (++sc->rx.rxotherant >= 3)
+                                       ath_setdefantenna(sc, rs.rs_antenna);
+                       } else {
+                               sc->rx.rxotherant = 0;
+                       }
+
                }
 
                if (rxs->flag & RX_FLAG_MMIC_STRIPPED)
index 4591097..6e2f188 100644 (file)
@@ -1006,6 +1006,8 @@ enum {
 #define AR_INTR_ASYNC_MASK                       (AR_SREV_9340(ah) ? 0x4018 : 0x4030)
 #define AR_INTR_ASYNC_MASK_GPIO                  0xFFFC0000
 #define AR_INTR_ASYNC_MASK_GPIO_S                18
+#define AR_INTR_ASYNC_MASK_MCI                   0x00000080
+#define AR_INTR_ASYNC_MASK_MCI_S                 7
 
 #define AR_INTR_SYNC_MASK                        (AR_SREV_9340(ah) ? 0x401c : 0x4034)
 #define AR_INTR_SYNC_MASK_GPIO                   0xFFFC0000
@@ -1013,6 +1015,14 @@ enum {
 
 #define AR_INTR_ASYNC_CAUSE_CLR                  (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
 #define AR_INTR_ASYNC_CAUSE                      (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
+#define AR_INTR_ASYNC_CAUSE_MCI                         0x00000080
+#define AR_INTR_ASYNC_USED                      (AR_INTR_MAC_IRQ | \
+                                                 AR_INTR_ASYNC_CAUSE_MCI)
+
+/* Asynchronous Interrupt Enable Register */
+#define AR_INTR_ASYNC_ENABLE_MCI         0x00000080
+#define AR_INTR_ASYNC_ENABLE_MCI_S       7
+
 
 #define AR_INTR_ASYNC_ENABLE                     (AR_SREV_9340(ah) ? 0x4024 : 0x403c)
 #define AR_INTR_ASYNC_ENABLE_GPIO                0xFFFC0000
@@ -1269,6 +1279,8 @@ enum {
 #define AR_RTC_INTR_MASK \
        ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058)
 
+#define AR_RTC_KEEP_AWAKE      0x7034
+
 /* RTC_DERIVED_* - only for AR9100 */
 
 #define AR_RTC_DERIVED_CLK \
@@ -1555,6 +1567,8 @@ enum {
 #define AR_DIAG_FRAME_NV0           0x00020000
 #define AR_DIAG_OBS_PT_SEL1         0x000C0000
 #define AR_DIAG_OBS_PT_SEL1_S       18
+#define AR_DIAG_OBS_PT_SEL2         0x08000000
+#define AR_DIAG_OBS_PT_SEL2_S       27
 #define AR_DIAG_FORCE_RX_CLEAR      0x00100000 /* force rx_clear high */
 #define AR_DIAG_IGNORE_VIRT_CS      0x00200000
 #define AR_DIAG_FORCE_CH_IDLE_HIGH  0x00400000
@@ -1929,37 +1943,277 @@ enum {
 #define AR_PHY_AGC_CONTROL_YCOK_MAX_S          6
 
 /* MCI Registers */
-#define AR_MCI_INTERRUPT_RX_MSG_EN             0x183c
-#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET    0x00000001
-#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S  0
-#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL     0x00000002
-#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S   1
-#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK       0x00000004
-#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S     2
-#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO       0x00000008
-#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S     3
-#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST        0x00000010
-#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S      4
-#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO       0x00000020
-#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S     5
-#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT         0x00000040
-#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S       6
-#define AR_MCI_INTERRUPT_RX_MSG_GPM             0x00000100
-#define AR_MCI_INTERRUPT_RX_MSG_GPM_S           8
-#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO        0x00000200
-#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S      9
-#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING    0x00000400
-#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S  10
-#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING      0x00000800
-#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S    11
-#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE        0x00001000
-#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S      12
-#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK        (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO  | \
+
+#define AR_MCI_COMMAND0                                0x1800
+#define AR_MCI_COMMAND0_HEADER                 0xFF
+#define AR_MCI_COMMAND0_HEADER_S               0
+#define AR_MCI_COMMAND0_LEN                    0x1f00
+#define AR_MCI_COMMAND0_LEN_S                  8
+#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP      0x2000
+#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP_S    13
+
+#define AR_MCI_COMMAND1                                0x1804
+
+#define AR_MCI_COMMAND2                                0x1808
+#define AR_MCI_COMMAND2_RESET_TX               0x01
+#define AR_MCI_COMMAND2_RESET_TX_S             0
+#define AR_MCI_COMMAND2_RESET_RX               0x02
+#define AR_MCI_COMMAND2_RESET_RX_S             1
+#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES     0x3FC
+#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES_S   2
+#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP        0x400
+#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP_S      10
+
+#define AR_MCI_RX_CTRL                         0x180c
+
+#define AR_MCI_TX_CTRL                         0x1810
+/* 0 = no division, 1 = divide by 2, 2 = divide by 4, 3 = divide by 8 */
+#define AR_MCI_TX_CTRL_CLK_DIV                 0x03
+#define AR_MCI_TX_CTRL_CLK_DIV_S               0
+#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE      0x04
+#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE_S    2
+#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ                0xFFFFF8
+#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ_S      3
+#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM         0xF000000
+#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM_S       24
+
+#define AR_MCI_MSG_ATTRIBUTES_TABLE                    0x1814
+#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM           0xFFFF
+#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM_S         0
+#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR                0xFFFF0000
+#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR_S      16
+
+#define AR_MCI_SCHD_TABLE_0                            0x1818
+#define AR_MCI_SCHD_TABLE_1                            0x181c
+#define AR_MCI_GPM_0                                   0x1820
+#define AR_MCI_GPM_1                                   0x1824
+#define AR_MCI_GPM_WRITE_PTR                           0xFFFF0000
+#define AR_MCI_GPM_WRITE_PTR_S                         16
+#define AR_MCI_GPM_BUF_LEN                             0x0000FFFF
+#define AR_MCI_GPM_BUF_LEN_S                           0
+
+#define AR_MCI_INTERRUPT_RAW                           0x1828
+#define AR_MCI_INTERRUPT_EN                            0x182c
+#define AR_MCI_INTERRUPT_SW_MSG_DONE                   0x00000001
+#define AR_MCI_INTERRUPT_SW_MSG_DONE_S                 0
+#define AR_MCI_INTERRUPT_CPU_INT_MSG                   0x00000002
+#define AR_MCI_INTERRUPT_CPU_INT_MSG_S                 1
+#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL                 0x00000004
+#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL_S               2
+#define AR_MCI_INTERRUPT_RX_INVALID_HDR                        0x00000008
+#define AR_MCI_INTERRUPT_RX_INVALID_HDR_S              3
+#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL                        0x00000010
+#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL_S              4
+#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL                        0x00000020
+#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL_S              5
+#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL                        0x00000080
+#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL_S              7
+#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL                        0x00000100
+#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL_S              8
+#define AR_MCI_INTERRUPT_RX_MSG                                0x00000200
+#define AR_MCI_INTERRUPT_RX_MSG_S                      9
+#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE           0x00000400
+#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE_S         10
+#define AR_MCI_INTERRUPT_BT_PRI                                0x07fff800
+#define AR_MCI_INTERRUPT_BT_PRI_S                      11
+#define AR_MCI_INTERRUPT_BT_PRI_THRESH                 0x08000000
+#define AR_MCI_INTERRUPT_BT_PRI_THRESH_S               27
+#define AR_MCI_INTERRUPT_BT_FREQ                       0x10000000
+#define AR_MCI_INTERRUPT_BT_FREQ_S                     28
+#define AR_MCI_INTERRUPT_BT_STOMP                      0x20000000
+#define AR_MCI_INTERRUPT_BT_STOMP_S                    29
+#define AR_MCI_INTERRUPT_BB_AIC_IRQ                    0x40000000
+#define AR_MCI_INTERRUPT_BB_AIC_IRQ_S                  30
+#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT             0x80000000
+#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT_S           31
+
+#define AR_MCI_INTERRUPT_DEFAULT    (AR_MCI_INTERRUPT_SW_MSG_DONE        | \
+                                    AR_MCI_INTERRUPT_RX_INVALID_HDR      | \
+                                    AR_MCI_INTERRUPT_RX_HW_MSG_FAIL      | \
+                                    AR_MCI_INTERRUPT_RX_SW_MSG_FAIL      | \
+                                    AR_MCI_INTERRUPT_TX_HW_MSG_FAIL      | \
+                                    AR_MCI_INTERRUPT_TX_SW_MSG_FAIL      | \
+                                    AR_MCI_INTERRUPT_RX_MSG              | \
+                                    AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE | \
+                                    AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)
+
+#define AR_MCI_INTERRUPT_MSG_FAIL_MASK (AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \
+                                       AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \
+                                       AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \
+                                       AR_MCI_INTERRUPT_TX_SW_MSG_FAIL)
+
+#define AR_MCI_REMOTE_CPU_INT                          0x1830
+#define AR_MCI_REMOTE_CPU_INT_EN                       0x1834
+#define AR_MCI_INTERRUPT_RX_MSG_RAW                    0x1838
+#define AR_MCI_INTERRUPT_RX_MSG_EN                     0x183c
+#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET           0x00000001
+#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S         0
+#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL            0x00000002
+#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S          1
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK              0x00000004
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S            2
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO              0x00000008
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S            3
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST               0x00000010
+#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S             4
+#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO              0x00000020
+#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S            5
+#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT                        0x00000040
+#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S              6
+#define AR_MCI_INTERRUPT_RX_MSG_GPM                    0x00000100
+#define AR_MCI_INTERRUPT_RX_MSG_GPM_S                  8
+#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO               0x00000200
+#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S             9
+#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING           0x00000400
+#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S         10
+#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING             0x00000800
+#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S           11
+#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE               0x00001000
+#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S             12
+#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK         (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO  | \
                                          AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL| \
                                          AR_MCI_INTERRUPT_RX_MSG_LNA_INFO   | \
                                          AR_MCI_INTERRUPT_RX_MSG_CONT_NACK  | \
                                          AR_MCI_INTERRUPT_RX_MSG_CONT_INFO  | \
                                          AR_MCI_INTERRUPT_RX_MSG_CONT_RST)
 
+#define AR_MCI_INTERRUPT_RX_MSG_DEFAULT (AR_MCI_INTERRUPT_RX_MSG_GPM    | \
+                                        AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET| \
+                                        AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING  | \
+                                        AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING| \
+                                        AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO   | \
+                                        AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL | \
+                                        AR_MCI_INTERRUPT_RX_MSG_LNA_INFO    | \
+                                        AR_MCI_INTERRUPT_RX_MSG_CONT_NACK   | \
+                                        AR_MCI_INTERRUPT_RX_MSG_CONT_INFO   | \
+                                        AR_MCI_INTERRUPT_RX_MSG_CONT_RST    | \
+                                        AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
+
+#define AR_MCI_CPU_INT                                 0x1840
+
+#define AR_MCI_RX_STATUS                       0x1844
+#define AR_MCI_RX_LAST_SCHD_MSG_INDEX          0x00000F00
+#define AR_MCI_RX_LAST_SCHD_MSG_INDEX_S                8
+#define AR_MCI_RX_REMOTE_SLEEP                 0x00001000
+#define AR_MCI_RX_REMOTE_SLEEP_S               12
+#define AR_MCI_RX_MCI_CLK_REQ                  0x00002000
+#define AR_MCI_RX_MCI_CLK_REQ_S                        13
+
+#define AR_MCI_CONT_STATUS                     0x1848
+#define AR_MCI_CONT_RSSI_POWER                 0x000000FF
+#define AR_MCI_CONT_RSSI_POWER_S               0
+#define AR_MCI_CONT_RRIORITY                   0x0000FF00
+#define AR_MCI_CONT_RRIORITY_S                 8
+#define AR_MCI_CONT_TXRX                       0x00010000
+#define AR_MCI_CONT_TXRX_S                     16
+
+#define AR_MCI_BT_PRI0                         0x184c
+#define AR_MCI_BT_PRI1                         0x1850
+#define AR_MCI_BT_PRI2                         0x1854
+#define AR_MCI_BT_PRI3                         0x1858
+#define AR_MCI_BT_PRI                          0x185c
+#define AR_MCI_WL_FREQ0                                0x1860
+#define AR_MCI_WL_FREQ1                                0x1864
+#define AR_MCI_WL_FREQ2                                0x1868
+#define AR_MCI_GAIN                            0x186c
+#define AR_MCI_WBTIMER1                                0x1870
+#define AR_MCI_WBTIMER2                                0x1874
+#define AR_MCI_WBTIMER3                                0x1878
+#define AR_MCI_WBTIMER4                                0x187c
+#define AR_MCI_MAXGAIN                         0x1880
+#define AR_MCI_HW_SCHD_TBL_CTL                 0x1884
+#define AR_MCI_HW_SCHD_TBL_D0                  0x1888
+#define AR_MCI_HW_SCHD_TBL_D1                  0x188c
+#define AR_MCI_HW_SCHD_TBL_D2                  0x1890
+#define AR_MCI_HW_SCHD_TBL_D3                  0x1894
+#define AR_MCI_TX_PAYLOAD0                     0x1898
+#define AR_MCI_TX_PAYLOAD1                     0x189c
+#define AR_MCI_TX_PAYLOAD2                     0x18a0
+#define AR_MCI_TX_PAYLOAD3                     0x18a4
+#define AR_BTCOEX_WBTIMER                      0x18a8
+
+#define AR_BTCOEX_CTRL                                 0x18ac
+#define AR_BTCOEX_CTRL_AR9462_MODE                     0x00000001
+#define AR_BTCOEX_CTRL_AR9462_MODE_S                   0
+#define AR_BTCOEX_CTRL_WBTIMER_EN                      0x00000002
+#define AR_BTCOEX_CTRL_WBTIMER_EN_S                    1
+#define AR_BTCOEX_CTRL_MCI_MODE_EN                     0x00000004
+#define AR_BTCOEX_CTRL_MCI_MODE_EN_S                   2
+#define AR_BTCOEX_CTRL_LNA_SHARED                      0x00000008
+#define AR_BTCOEX_CTRL_LNA_SHARED_S                    3
+#define AR_BTCOEX_CTRL_PA_SHARED                       0x00000010
+#define AR_BTCOEX_CTRL_PA_SHARED_S                     4
+#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN          0x00000020
+#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN_S                5
+#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN       0x00000040
+#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN_S     6
+#define AR_BTCOEX_CTRL_NUM_ANTENNAS                    0x00000180
+#define AR_BTCOEX_CTRL_NUM_ANTENNAS_S                  7
+#define AR_BTCOEX_CTRL_RX_CHAIN_MASK                   0x00000E00
+#define AR_BTCOEX_CTRL_RX_CHAIN_MASK_S                 9
+#define AR_BTCOEX_CTRL_AGGR_THRESH                     0x00007000
+#define AR_BTCOEX_CTRL_AGGR_THRESH_S                   12
+#define AR_BTCOEX_CTRL_1_CHAIN_BCN                     0x00080000
+#define AR_BTCOEX_CTRL_1_CHAIN_BCN_S                   19
+#define AR_BTCOEX_CTRL_1_CHAIN_ACK                     0x00100000
+#define AR_BTCOEX_CTRL_1_CHAIN_ACK_S                   20
+#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN                  0x1FE00000
+#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN_S                        28
+#define AR_BTCOEX_CTRL_REDUCE_TXPWR                    0x20000000
+#define AR_BTCOEX_CTRL_REDUCE_TXPWR_S                  29
+#define AR_BTCOEX_CTRL_SPDT_ENABLE_10                  0x40000000
+#define AR_BTCOEX_CTRL_SPDT_ENABLE_10_S                        30
+#define AR_BTCOEX_CTRL_SPDT_POLARITY                   0x80000000
+#define AR_BTCOEX_CTRL_SPDT_POLARITY_S                 31
+
+#define AR_BTCOEX_WL_WEIGHTS0                          0x18b0
+#define AR_BTCOEX_WL_WEIGHTS1                          0x18b4
+#define AR_BTCOEX_WL_WEIGHTS2                          0x18b8
+#define AR_BTCOEX_WL_WEIGHTS3                          0x18bc
+#define AR_BTCOEX_MAX_TXPWR(_x)                                (0x18c0 + ((_x) << 2))
+#define AR_BTCOEX_WL_LNA                               0x1940
+#define AR_BTCOEX_RFGAIN_CTRL                          0x1944
+
+#define AR_BTCOEX_CTRL2                                        0x1948
+#define AR_BTCOEX_CTRL2_TXPWR_THRESH                   0x0007F800
+#define AR_BTCOEX_CTRL2_TXPWR_THRESH_S                 11
+#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK                  0x00380000
+#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK_S                        19
+#define AR_BTCOEX_CTRL2_RX_DEWEIGHT                    0x00400000
+#define AR_BTCOEX_CTRL2_RX_DEWEIGHT_S                  22
+#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL                   0x00800000
+#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL_S                 23
+#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL                 0x01000000
+#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL_S               24
+#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE                0x02000000
+#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE_S      25
+
+#define AR_BTCOEX_CTRL_SPDT_ENABLE          0x00000001
+#define AR_BTCOEX_CTRL_SPDT_ENABLE_S        0
+#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL     0x00000002
+#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL_S   1
+#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT   0x00000004
+#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT_S 2
+#define AR_GLB_WLAN_UART_INTF_EN            0x00020000
+#define AR_GLB_WLAN_UART_INTF_EN_S          17
+#define AR_GLB_DS_JTAG_DISABLE              0x00040000
+#define AR_GLB_DS_JTAG_DISABLE_S            18
+
+#define AR_BTCOEX_RC                    0x194c
+#define AR_BTCOEX_MAX_RFGAIN(_x)        (0x1950 + ((_x) << 2))
+#define AR_BTCOEX_DBG                   0x1a50
+#define AR_MCI_LAST_HW_MSG_HDR          0x1a54
+#define AR_MCI_LAST_HW_MSG_BDY          0x1a58
+
+#define AR_MCI_SCHD_TABLE_2             0x1a5c
+#define AR_MCI_SCHD_TABLE_2_MEM_BASED   0x00000001
+#define AR_MCI_SCHD_TABLE_2_MEM_BASED_S 0
+#define AR_MCI_SCHD_TABLE_2_HW_BASED    0x00000002
+#define AR_MCI_SCHD_TABLE_2_HW_BASED_S  1
+
+#define AR_BTCOEX_CTRL3               0x1a60
+#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT      0x00000fff
+#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S    0
+
 
 #endif
index 55d077e..80639e3 100644 (file)
@@ -179,6 +179,11 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
                spin_lock_bh(&txq->axq_lock);
        }
 
+       if (tid->baw_head == tid->baw_tail) {
+               tid->state &= ~AGGR_ADDBA_COMPLETE;
+               tid->state &= ~AGGR_CLEANUP;
+       }
+
        spin_unlock_bh(&txq->axq_lock);
 }
 
@@ -556,15 +561,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                spin_unlock_bh(&txq->axq_lock);
        }
 
-       if (tid->state & AGGR_CLEANUP) {
+       if (tid->state & AGGR_CLEANUP)
                ath_tx_flush_tid(sc, tid);
 
-               if (tid->baw_head == tid->baw_tail) {
-                       tid->state &= ~AGGR_ADDBA_COMPLETE;
-                       tid->state &= ~AGGR_CLEANUP;
-               }
-       }
-
        rcu_read_unlock();
 
        if (needreset) {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h b/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h
deleted file mode 100644 (file)
index cecb5e5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2011 Broadcom Corporation
- *
- * 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.
- */
-
-#ifndef _bcmchip_h_
-#define _bcmchip_h_
-
-/* bcm4329 */
-/* firmware name */
-#define BCM4329_FW_NAME                        "brcm/bcm4329-fullmac-4.bin"
-#define BCM4329_NV_NAME                        "brcm/bcm4329-fullmac-4.txt"
-
-#endif                         /* _bcmchip_h_ */
index 89ff94d..74933dc 100644 (file)
@@ -40,7 +40,8 @@
 
 static void brcmf_sdioh_irqhandler(struct sdio_func *func)
 {
-       struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
+       struct brcmf_bus *bus_if = dev_get_drvdata(&func->card->dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
 
        brcmf_dbg(TRACE, "***IRQHandler\n");
 
@@ -222,19 +223,12 @@ bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
        return sdiodev->regfail;
 }
 
-int
-brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                     uint flags,
-                     u8 *buf, uint nbytes, struct sk_buff *pkt)
+static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,
+                                    uint flags, uint width, u32 *addr)
 {
-       int status;
-       uint incr_fix;
-       uint width;
-       uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+       uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;
        int err = 0;
 
-       brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes);
-
        /* Async not implemented yet */
        if (flags & SDIO_REQ_ASYNC)
                return -ENOTSUPP;
@@ -247,29 +241,114 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
                sdiodev->sbwad = bar0;
        }
 
-       addr &= SBSDIO_SB_OFT_ADDR_MASK;
+       *addr &= SBSDIO_SB_OFT_ADDR_MASK;
+
+       if (width == 4)
+               *addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+       return 0;
+}
+
+int
+brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+                     uint flags, u8 *buf, uint nbytes)
+{
+       struct sk_buff *mypkt;
+       int err;
+
+       mypkt = brcmu_pkt_buf_get_skb(nbytes);
+       if (!mypkt) {
+               brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
+                         nbytes);
+               return -EIO;
+       }
+
+       err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt);
+       if (!err)
+               memcpy(buf, mypkt->data, nbytes);
+
+       brcmu_pkt_buf_free_skb(mypkt);
+       return err;
+}
+
+int
+brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+                     uint flags, struct sk_buff *pkt)
+{
+       uint incr_fix;
+       uint width;
+       int err = 0;
+
+       brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
+                 fn, addr, pkt->len);
+
+       width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
+       err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
+       if (err)
+               return err;
 
        incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
+       err = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
+                                        fn, addr, pkt);
+
+       return err;
+}
+
+int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+                           uint flags, struct sk_buff_head *pktq)
+{
+       uint incr_fix;
+       uint width;
+       int err = 0;
+
+       brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
+                 fn, addr, pktq->qlen);
+
        width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
-       if (width == 4)
-               addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+       err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
+       if (err)
+               return err;
 
-       status = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
-                                           fn, addr, width, nbytes, buf, pkt);
+       incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
+       err = brcmf_sdioh_request_chain(sdiodev, incr_fix, SDIOH_READ, fn, addr,
+                                       pktq);
 
-       return status;
+       return err;
 }
 
 int
 brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                     uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt)
+                     uint flags, u8 *buf, uint nbytes)
+{
+       struct sk_buff *mypkt;
+       int err;
+
+       mypkt = brcmu_pkt_buf_get_skb(nbytes);
+       if (!mypkt) {
+               brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
+                         nbytes);
+               return -EIO;
+       }
+
+       memcpy(mypkt->data, buf, nbytes);
+       err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, mypkt);
+
+       brcmu_pkt_buf_free_skb(mypkt);
+       return err;
+
+}
+
+int
+brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+                     uint flags, struct sk_buff *pkt)
 {
        uint incr_fix;
        uint width;
        uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
        int err = 0;
 
-       brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes);
+       brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
+                 fn, addr, pkt->len);
 
        /* Async not implemented yet */
        if (flags & SDIO_REQ_ASYNC)
@@ -291,18 +370,39 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
                addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
 
        return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
-                                         addr, width, nbytes, buf, pkt);
+                                         addr, pkt);
 }
 
 int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
                        u8 *buf, uint nbytes)
 {
+       struct sk_buff *mypkt;
+       bool write = rw ? SDIOH_WRITE : SDIOH_READ;
+       int err;
+
        addr &= SBSDIO_SB_OFT_ADDR_MASK;
        addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
 
-       return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC,
-               (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
-               addr, 4, nbytes, buf, NULL);
+       mypkt = brcmu_pkt_buf_get_skb(nbytes);
+       if (!mypkt) {
+               brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
+                         nbytes);
+               return -EIO;
+       }
+
+       /* For a write, copy the buffer data into the packet. */
+       if (write)
+               memcpy(mypkt->data, buf, nbytes);
+
+       err = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, write,
+                                        SDIO_FUNC_1, addr, mypkt);
+
+       /* For a read, copy the packet data back to the buffer. */
+       if (!err && !write)
+               memcpy(buf, mypkt->data, nbytes);
+
+       brcmu_pkt_buf_free_skb(mypkt);
+       return err;
 }
 
 int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
@@ -333,7 +433,7 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
        sdiodev->sbwad = SI_ENUM_BASE;
 
        /* try to attach to the target device */
-       sdiodev->bus = brcmf_sdbrcm_probe(0, 0, 0, 0, regs, sdiodev);
+       sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
        if (!sdiodev->bus) {
                brcmf_dbg(ERROR, "device attach failed\n");
                ret = -ENODEV;
index bbaeb2d..b416e27 100644 (file)
@@ -204,62 +204,75 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
        return err_ret;
 }
 
+/* precondition: host controller is claimed */
 static int
-brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
-                          uint write, uint func, uint addr,
-                          struct sk_buff *pkt)
+brcmf_sdioh_request_data(struct brcmf_sdio_dev *sdiodev, uint write, bool fifo,
+                        uint func, uint addr, struct sk_buff *pkt, uint pktlen)
+{
+       int err_ret = 0;
+
+       if ((write) && (!fifo)) {
+               err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
+                                          ((u8 *) (pkt->data)), pktlen);
+       } else if (write) {
+               err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
+                                          ((u8 *) (pkt->data)), pktlen);
+       } else if (fifo) {
+               err_ret = sdio_readsb(sdiodev->func[func],
+                                     ((u8 *) (pkt->data)), addr, pktlen);
+       } else {
+               err_ret = sdio_memcpy_fromio(sdiodev->func[func],
+                                            ((u8 *) (pkt->data)),
+                                            addr, pktlen);
+       }
+
+       return err_ret;
+}
+
+/*
+ * This function takes a queue of packets. The packets on the queue
+ * are assumed to be properly aligned by the caller.
+ */
+int
+brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
+                         uint write, uint func, uint addr,
+                         struct sk_buff_head *pktq)
 {
        bool fifo = (fix_inc == SDIOH_DATA_FIX);
        u32 SGCount = 0;
        int err_ret = 0;
 
-       struct sk_buff *pnext;
+       struct sk_buff *pkt;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait);
+       brcmf_pm_resume_wait(sdiodev, &sdiodev->request_chain_wait);
        if (brcmf_pm_resume_error(sdiodev))
                return -EIO;
 
        /* Claim host controller */
        sdio_claim_host(sdiodev->func[func]);
-       for (pnext = pkt; pnext; pnext = pnext->next) {
-               uint pkt_len = pnext->len;
+
+       skb_queue_walk(pktq, pkt) {
+               uint pkt_len = pkt->len;
                pkt_len += 3;
                pkt_len &= 0xFFFFFFFC;
 
-               if ((write) && (!fifo)) {
-                       err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
-                                                  ((u8 *) (pnext->data)),
-                                                  pkt_len);
-               } else if (write) {
-                       err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
-                                                  ((u8 *) (pnext->data)),
-                                                  pkt_len);
-               } else if (fifo) {
-                       err_ret = sdio_readsb(sdiodev->func[func],
-                                             ((u8 *) (pnext->data)),
-                                             addr, pkt_len);
-               } else {
-                       err_ret = sdio_memcpy_fromio(sdiodev->func[func],
-                                                    ((u8 *) (pnext->data)),
-                                                    addr, pkt_len);
-               }
-
+               err_ret = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
+                                                  addr, pkt, pkt_len);
                if (err_ret) {
                        brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
-                                 write ? "TX" : "RX", pnext, SGCount, addr,
+                                 write ? "TX" : "RX", pkt, SGCount, addr,
                                  pkt_len, err_ret);
                } else {
                        brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
-                                 write ? "TX" : "RX", pnext, SGCount, addr,
+                                 write ? "TX" : "RX", pkt, SGCount, addr,
                                  pkt_len);
                }
-
                if (!fifo)
                        addr += pkt_len;
-               SGCount++;
 
+               SGCount++;
        }
 
        /* Release host controller */
@@ -270,91 +283,45 @@ brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
 }
 
 /*
- * This function takes a buffer or packet, and fixes everything up
- * so that in the end, a DMA-able packet is created.
- *
- * A buffer does not have an associated packet pointer,
- * and may or may not be aligned.
- * A packet may consist of a single packet, or a packet chain.
- * If it is a packet chain, then all the packets in the chain
- * must be properly aligned.
- *
- * If the packet data is not aligned, then there may only be
- * one packet, and in this case,  it is copied to a new
- * aligned packet.
- *
+ * This function takes a single DMA-able packet.
  */
 int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
                               uint fix_inc, uint write, uint func, uint addr,
-                              uint reg_width, uint buflen_u, u8 *buffer,
                               struct sk_buff *pkt)
 {
-       int Status;
-       struct sk_buff *mypkt = NULL;
+       int status;
+       uint pkt_len = pkt->len;
+       bool fifo = (fix_inc == SDIOH_DATA_FIX);
 
        brcmf_dbg(TRACE, "Enter\n");
 
+       if (pkt == NULL)
+               return -EINVAL;
+
        brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
        if (brcmf_pm_resume_error(sdiodev))
                return -EIO;
-       /* Case 1: we don't have a packet. */
-       if (pkt == NULL) {
-               brcmf_dbg(DATA, "Creating new %s Packet, len=%d\n",
-                         write ? "TX" : "RX", buflen_u);
-               mypkt = brcmu_pkt_buf_get_skb(buflen_u);
-               if (!mypkt) {
-                       brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
-                                 buflen_u);
-                       return -EIO;
-               }
-
-               /* For a write, copy the buffer data into the packet. */
-               if (write)
-                       memcpy(mypkt->data, buffer, buflen_u);
-
-               Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
-                                                   func, addr, mypkt);
-
-               /* For a read, copy the packet data back to the buffer. */
-               if (!write)
-                       memcpy(buffer, mypkt->data, buflen_u);
-
-               brcmu_pkt_buf_free_skb(mypkt);
-       } else if (((ulong) (pkt->data) & DMA_ALIGN_MASK) != 0) {
-               /*
-                * Case 2: We have a packet, but it is unaligned.
-                * In this case, we cannot have a chain (pkt->next == NULL)
-                */
-               brcmf_dbg(DATA, "Creating aligned %s Packet, len=%d\n",
-                         write ? "TX" : "RX", pkt->len);
-               mypkt = brcmu_pkt_buf_get_skb(pkt->len);
-               if (!mypkt) {
-                       brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
-                                 pkt->len);
-                       return -EIO;
-               }
-
-               /* For a write, copy the buffer data into the packet. */
-               if (write)
-                       memcpy(mypkt->data, pkt->data, pkt->len);
 
-               Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
-                                                   func, addr, mypkt);
+       /* Claim host controller */
+       sdio_claim_host(sdiodev->func[func]);
 
-               /* For a read, copy the packet data back to the buffer. */
-               if (!write)
-                       memcpy(pkt->data, mypkt->data, mypkt->len);
+       pkt_len += 3;
+       pkt_len &= (uint)~3;
 
-               brcmu_pkt_buf_free_skb(mypkt);
-       } else {                /* case 3: We have a packet and
-                                it is aligned. */
-               brcmf_dbg(DATA, "Aligned %s Packet, direct DMA\n",
-                         write ? "Tx" : "Rx");
-               Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
-                                                   func, addr, pkt);
+       status = brcmf_sdioh_request_data(sdiodev, write, fifo, func,
+                                          addr, pkt, pkt_len);
+       if (status) {
+               brcmf_dbg(ERROR, "%s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
+                         write ? "TX" : "RX", pkt, addr, pkt_len, status);
+       } else {
+               brcmf_dbg(TRACE, "%s xfr'd %p, addr=0x%05x, len=%d\n",
+                         write ? "TX" : "RX", pkt, addr, pkt_len);
        }
 
-       return Status;
+       /* Release host controller */
+       sdio_release_host(sdiodev->func[func]);
+
+       return status;
 }
 
 /* Read client card reg */
@@ -494,6 +461,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
 {
        int ret = 0;
        struct brcmf_sdio_dev *sdiodev;
+       struct brcmf_bus *bus_if;
        brcmf_dbg(TRACE, "Enter\n");
        brcmf_dbg(TRACE, "func->class=%x\n", func->class);
        brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor);
@@ -505,22 +473,31 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
                        brcmf_dbg(ERROR, "card private drvdata occupied\n");
                        return -ENXIO;
                }
+               bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
+               if (!bus_if)
+                       return -ENOMEM;
                sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
-               if (!sdiodev)
+               if (!sdiodev) {
+                       kfree(bus_if);
                        return -ENOMEM;
+               }
+               sdiodev->dev = &func->card->dev;
                sdiodev->func[0] = func->card->sdio_func[0];
                sdiodev->func[1] = func;
-               dev_set_drvdata(&func->card->dev, sdiodev);
+               bus_if->bus_priv = sdiodev;
+               bus_if->type = SDIO_BUS;
+               dev_set_drvdata(&func->card->dev, bus_if);
 
                atomic_set(&sdiodev->suspend, false);
                init_waitqueue_head(&sdiodev->request_byte_wait);
                init_waitqueue_head(&sdiodev->request_word_wait);
-               init_waitqueue_head(&sdiodev->request_packet_wait);
+               init_waitqueue_head(&sdiodev->request_chain_wait);
                init_waitqueue_head(&sdiodev->request_buffer_wait);
        }
 
        if (func->num == 2) {
-               sdiodev = dev_get_drvdata(&func->card->dev);
+               bus_if = dev_get_drvdata(&func->card->dev);
+               sdiodev = bus_if->bus_priv;
                if ((!sdiodev) || (sdiodev->func[1]->card != func->card))
                        return -ENODEV;
                sdiodev->func[2] = func;
@@ -534,6 +511,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
 
 static void brcmf_ops_sdio_remove(struct sdio_func *func)
 {
+       struct brcmf_bus *bus_if;
        struct brcmf_sdio_dev *sdiodev;
        brcmf_dbg(TRACE, "Enter\n");
        brcmf_dbg(INFO, "func->class=%x\n", func->class);
@@ -542,10 +520,12 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
        brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num);
 
        if (func->num == 2) {
-               sdiodev = dev_get_drvdata(&func->card->dev);
+               bus_if = dev_get_drvdata(&func->card->dev);
+               sdiodev = bus_if->bus_priv;
                brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
                brcmf_sdio_remove(sdiodev);
                dev_set_drvdata(&func->card->dev, NULL);
+               kfree(bus_if);
                kfree(sdiodev);
        }
 }
@@ -556,11 +536,12 @@ static int brcmf_sdio_suspend(struct device *dev)
        mmc_pm_flag_t sdio_flags;
        struct brcmf_sdio_dev *sdiodev;
        struct sdio_func *func = dev_to_sdio_func(dev);
+       struct brcmf_bus *bus_if = dev_get_drvdata(&func->card->dev);
        int ret = 0;
 
        brcmf_dbg(TRACE, "\n");
 
-       sdiodev = dev_get_drvdata(&func->card->dev);
+       sdiodev = bus_if->bus_priv;
 
        atomic_set(&sdiodev->suspend, true);
 
@@ -585,8 +566,9 @@ static int brcmf_sdio_resume(struct device *dev)
 {
        struct brcmf_sdio_dev *sdiodev;
        struct sdio_func *func = dev_to_sdio_func(dev);
+       struct brcmf_bus *bus_if = dev_get_drvdata(&func->card->dev);
 
-       sdiodev = dev_get_drvdata(&func->card->dev);
+       sdiodev = bus_if->bus_priv;
        brcmf_sdio_wdtmr_enable(sdiodev, true);
        atomic_set(&sdiodev->suspend, false);
        return 0;
@@ -610,17 +592,26 @@ static struct sdio_driver brcmf_sdmmc_driver = {
 #endif /* CONFIG_PM_SLEEP */
 };
 
-/* bus register interface */
-int brcmf_bus_register(void)
+static void __exit brcmf_sdio_exit(void)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
-       return sdio_register_driver(&brcmf_sdmmc_driver);
+       sdio_unregister_driver(&brcmf_sdmmc_driver);
 }
 
-void brcmf_bus_unregister(void)
+static int __init brcmf_sdio_init(void)
 {
+       int ret;
+
        brcmf_dbg(TRACE, "Enter\n");
 
-       sdio_unregister_driver(&brcmf_sdmmc_driver);
+       ret = sdio_register_driver(&brcmf_sdmmc_driver);
+
+       if (ret)
+               brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret);
+
+       return ret;
 }
+
+module_init(brcmf_sdio_init);
+module_exit(brcmf_sdio_exit);
index 6da519e..b68d136 100644 (file)
@@ -571,8 +571,14 @@ struct brcmf_dcmd {
        uint needed;            /* bytes needed (optional) */
 };
 
+struct brcmf_bus {
+       u8 type;                /* bus type */
+       void *bus_priv;         /* pointer to bus private structure */
+       enum brcmf_bus_state state;
+};
+
 /* Forward decls for struct brcmf_pub (see below) */
-struct brcmf_bus;              /* device bus info */
+struct brcmf_sdio;             /* device bus info */
 struct brcmf_proto;    /* device communication protocol info */
 struct brcmf_info;     /* device driver info */
 struct brcmf_cfg80211_dev; /* cfg80211 device info */
@@ -580,15 +586,16 @@ struct brcmf_cfg80211_dev; /* cfg80211 device info */
 /* Common structure for module and instance linkage */
 struct brcmf_pub {
        /* Linkage ponters */
-       struct brcmf_bus *bus;
+       struct brcmf_sdio *bus;
+       struct brcmf_bus *bus_if;
        struct brcmf_proto *prot;
        struct brcmf_info *info;
        struct brcmf_cfg80211_dev *config;
+       struct device *dev;             /* fullmac dongle device pointer */
 
        /* Internal brcmf items */
        bool up;                /* Driver up/down (to OS) */
        bool txoff;             /* Transmit flow-controlled */
-       enum brcmf_bus_state busstate;
        uint hdrlen;            /* Total BRCMF header length (proto + bus) */
        uint maxctl;            /* Max size rxctl request from proto to bus */
        uint rxsz;              /* Rx buffer size bus module should use */
@@ -656,7 +663,6 @@ struct brcmf_pub {
 
        u8 country_code[BRCM_CNTRY_BUF_SZ];
        char eventmask[BRCMF_EVENTING_MASK_LEN];
-
 };
 
 struct brcmf_if_event {
@@ -681,8 +687,8 @@ extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
  * Returned structure should have bus and prot pointers filled in.
  * bus_hdrlen specifies required headroom for bus module header.
  */
-extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus,
-                                     uint bus_hdrlen);
+extern struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus,
+                                     uint bus_hdrlen, struct device *dev);
 extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx);
 extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
 
@@ -699,7 +705,16 @@ extern bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q,
 
 /* Receive frame for delivery to OS.  Callee disposes of rxp. */
 extern void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx,
-                        struct sk_buff *rxp, int numpkt);
+                          struct sk_buff_head *rxlist);
+static inline void brcmf_rx_packet(struct brcmf_pub *drvr, int ifidx,
+                                  struct sk_buff *pkt)
+{
+       struct sk_buff_head q;
+
+       skb_queue_head_init(&q);
+       skb_queue_tail(&q, pkt);
+       brcmf_rx_frame(drvr, ifidx, &q);
+}
 
 /* Return pointer to interface name */
 extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
@@ -724,8 +739,6 @@ extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx,
                              void *pktdata, struct brcmf_event_msg *,
                              void **data_ptr);
 
-extern void brcmf_c_init(void);
-
 extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx,
                        char *name, u8 *mac_addr);
 extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx);
index a249407..1841f99 100644 (file)
  * Exported from brcmf bus module (brcmf_usb, brcmf_sdio)
  */
 
-/* Indicate (dis)interest in finding dongles. */
-extern int brcmf_bus_register(void);
-extern void brcmf_bus_unregister(void);
-
-/* obtain linux device object providing bus function */
-extern struct device *brcmf_bus_get_device(struct brcmf_bus *bus);
-
 /* Stop bus module: clear pending frames, disable data flow */
-extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus);
+extern void brcmf_sdbrcm_bus_stop(struct device *dev);
 
 /* Initialize bus module: prepare for communication w/dongle */
-extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr);
+extern int brcmf_sdbrcm_bus_init(struct device *dev);
 
 /* Send a data frame to the dongle.  Callee disposes of txp. */
-extern int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *txp);
+extern int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *txp);
 
 /* Send/receive a control message to/from the dongle.
  * Expects caller to enforce a single outstanding transaction.
  */
 extern int
-brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen);
+brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen);
 
 extern int
-brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen);
+brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen);
 
-extern void brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick);
+extern void brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick);
 
 #endif                         /* _BRCMF_BUS_H_ */
index e34c5c3..a527d5d 100644 (file)
@@ -116,7 +116,7 @@ static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
                len = CDC_MAX_MSG_SIZE;
 
        /* Send request */
-       return brcmf_sdbrcm_bus_txctl(drvr->bus, (unsigned char *)&prot->msg,
+       return brcmf_sdbrcm_bus_txctl(drvr->dev, (unsigned char *)&prot->msg,
                                      len);
 }
 
@@ -128,7 +128,7 @@ static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
        brcmf_dbg(TRACE, "Enter\n");
 
        do {
-               ret = brcmf_sdbrcm_bus_rxctl(drvr->bus,
+               ret = brcmf_sdbrcm_bus_rxctl(drvr->dev,
                                (unsigned char *)&prot->msg,
                                len + sizeof(struct brcmf_proto_cdc_dcmd));
                if (ret < 0)
@@ -280,7 +280,7 @@ brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd,
        struct brcmf_proto *prot = drvr->prot;
        int ret = -1;
 
-       if (drvr->busstate == BRCMF_BUS_DOWN) {
+       if (drvr->bus_if->state == BRCMF_BUS_DOWN) {
                brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
                return ret;
        }
index 40928e5..69f335a 100644 (file)
@@ -32,8 +32,6 @@
 #define PKTFILTER_BUF_SIZE             2048
 #define BRCMF_ARPOL_MODE               0xb     /* agent|snoop|peer_autoreply */
 
-int brcmf_msg_level;
-
 #define MSGTRACE_VERSION       1
 
 #define BRCMF_PKT_FILTER_FIXED_LEN     offsetof(struct brcmf_pkt_filter_le, u)
@@ -85,19 +83,6 @@ brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
        return len;
 }
 
-void brcmf_c_init(void)
-{
-       /* Init global variables at run-time, not as part of the declaration.
-        * This is required to support init/de-init of the driver.
-        * Initialization
-        * of globals as part of the declaration results in non-deterministic
-        * behaviour since the value of the globals may be different on the
-        * first time that the driver is initialized vs subsequent
-        * initializations.
-        */
-       brcmf_msg_level = BRCMF_ERROR_VAL;
-}
-
 bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q,
                      struct sk_buff *pkt, int prec)
 {
index 719fd93..58d92bc 100644 (file)
@@ -43,7 +43,6 @@
 #include "dhd_proto.h"
 #include "dhd_dbg.h"
 #include "wl_cfg80211.h"
-#include "bcmchip.h"
 
 MODULE_AUTHOR("Broadcom Corporation");
 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");
@@ -77,6 +76,7 @@ struct brcmf_info {
 };
 
 /* Error bits */
+int brcmf_msg_level = BRCMF_ERROR_VAL;
 module_param(brcmf_msg_level, int, 0);
 
 int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
@@ -292,7 +292,7 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
        struct brcmf_info *drvr_priv = drvr->info;
 
        /* Reject if down */
-       if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN))
+       if (!drvr->up || (drvr->bus_if->state == BRCMF_BUS_DOWN))
                return -ENODEV;
 
        /* Update multicast statistic */
@@ -310,7 +310,7 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
        brcmf_proto_hdrpush(drvr, ifidx, pktbuf);
 
        /* Use bus module to send data frame */
-       return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf);
+       return brcmf_sdbrcm_bus_txdata(drvr->dev, pktbuf);
 }
 
 static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
@@ -322,9 +322,11 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        brcmf_dbg(TRACE, "Enter\n");
 
        /* Reject if down */
-       if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) {
-               brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n",
-                         drvr_priv->pub.up, drvr_priv->pub.busstate);
+       if (!drvr_priv->pub.up ||
+           (drvr_priv->pub.bus_if->state == BRCMF_BUS_DOWN)) {
+               brcmf_dbg(ERROR, "xmit rejected pub.up=%d state=%d\n",
+                         drvr_priv->pub.up,
+                         drvr_priv->pub.bus_if->state);
                netif_stop_queue(ndev);
                return -ENODEV;
        }
@@ -397,26 +399,21 @@ static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx,
        return bcmerror;
 }
 
-void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
-                 int numpkt)
+void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx,
+                   struct sk_buff_head *skb_list)
 {
        struct brcmf_info *drvr_priv = drvr->info;
        unsigned char *eth;
        uint len;
        void *data;
-       struct sk_buff *pnext, *save_pktbuf;
-       int i;
+       struct sk_buff *skb, *pnext;
        struct brcmf_if *ifp;
        struct brcmf_event_msg event;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       save_pktbuf = skb;
-
-       for (i = 0; skb && i < numpkt; i++, skb = pnext) {
-
-               pnext = skb->next;
-               skb->next = NULL;
+       skb_queue_walk_safe(skb_list, skb, pnext) {
+               skb_unlink(skb, skb_list);
 
                /* Get the protocol, maintain skb around eth_type_trans()
                 * The main reason for this hack is for the limitation of
@@ -437,6 +434,12 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
                if (ifp == NULL)
                        ifp = drvr_priv->iflist[0];
 
+               if (!ifp || !ifp->ndev ||
+                   ifp->ndev->reg_state != NETREG_REGISTERED) {
+                       brcmu_pkt_buf_free_skb(skb);
+                       continue;
+               }
+
                skb->dev = ifp->ndev;
                skb->protocol = eth_type_trans(skb, skb->dev);
 
@@ -605,9 +608,7 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
 
        sprintf(info->driver, KBUILD_MODNAME);
        sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
-       sprintf(info->fw_version, "%s", BCM4329_FW_NAME);
-       sprintf(info->bus_info, "%s",
-               dev_name(brcmf_bus_get_device(drvr_priv->pub.bus)));
+       sprintf(info->bus_info, "%s", dev_name(drvr_priv->pub.dev));
 }
 
 static struct ethtool_ops brcmf_ethtool_ops = {
@@ -761,7 +762,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
                buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
 
        /* send to dongle (must be up, and wl) */
-       if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) {
+       if ((drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA)) {
                brcmf_dbg(ERROR, "DONGLE_DOWN\n");
                err = -EIO;
                goto done;
@@ -940,7 +941,8 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
        }
 }
 
-struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
+struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen,
+                              struct device *dev)
 {
        struct brcmf_info *drvr_priv = NULL;
 
@@ -959,6 +961,8 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
        /* Link to bus module */
        drvr_priv->pub.bus = bus;
        drvr_priv->pub.hdrlen = bus_hdrlen;
+       drvr_priv->pub.bus_if = dev_get_drvdata(dev);
+       drvr_priv->pub.dev = dev;
 
        /* Attach and link in the protocol */
        if (brcmf_proto_attach(&drvr_priv->pub) != 0) {
@@ -988,14 +992,14 @@ int brcmf_bus_start(struct brcmf_pub *drvr)
        brcmf_dbg(TRACE, "\n");
 
        /* Bring up the bus */
-       ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub);
+       ret = brcmf_sdbrcm_bus_init(drvr_priv->pub.dev);
        if (ret != 0) {
                brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret);
                return ret;
        }
 
        /* If bus is not ready, can't come up */
-       if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) {
+       if (drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA) {
                brcmf_dbg(ERROR, "failed bus is not ready\n");
                return -ENODEV;
        }
@@ -1077,10 +1081,7 @@ int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
 
        /* attach to cfg80211 for primary interface */
        if (!ifidx) {
-               drvr->config =
-                       brcmf_cfg80211_attach(ndev,
-                                             brcmf_bus_get_device(drvr->bus),
-                                             drvr);
+               drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr);
                if (drvr->config == NULL) {
                        brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
                        goto fail;
@@ -1114,7 +1115,7 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr)
                        brcmf_proto_stop(&drvr_priv->pub);
 
                        /* Stop the bus module */
-                       brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus);
+                       brcmf_sdbrcm_bus_stop(drvr_priv->pub.dev);
                }
        }
 }
@@ -1148,34 +1149,6 @@ void brcmf_detach(struct brcmf_pub *drvr)
        }
 }
 
-static void __exit brcmf_module_cleanup(void)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       brcmf_bus_unregister();
-}
-
-static int __init brcmf_module_init(void)
-{
-       int error;
-
-       brcmf_dbg(TRACE, "Enter\n");
-
-       error = brcmf_bus_register();
-
-       if (error) {
-               brcmf_dbg(ERROR, "brcmf_bus_register failed\n");
-               goto failed;
-       }
-       return 0;
-
-failed:
-       return -EINVAL;
-}
-
-module_init(brcmf_module_init);
-module_exit(brcmf_module_cleanup);
-
 int brcmf_os_proto_block(struct brcmf_pub *drvr)
 {
        struct brcmf_info *drvr_priv = drvr->info;
index 22913af..18597fe 100644 (file)
@@ -91,7 +91,6 @@ struct rte_console {
 #include "dhd_bus.h"
 #include "dhd_proto.h"
 #include "dhd_dbg.h"
-#include <bcmchip.h>
 
 #define TXQLEN         2048    /* bulk tx queue length */
 #define TXHI           (TXQLEN - 256)  /* turn on flow control above TXHI */
@@ -310,6 +309,11 @@ struct rte_console {
 /* Flags for SDH calls */
 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 
+#define BRCMFMAC_FW_NAME       "brcm/brcmfmac.bin"
+#define BRCMFMAC_NV_NAME       "brcm/brcmfmac.txt"
+MODULE_FIRMWARE(BRCMFMAC_FW_NAME);
+MODULE_FIRMWARE(BRCMFMAC_NV_NAME);
+
 /*
  * Conversion of 802.1D priority to precedence level
  */
@@ -445,7 +449,7 @@ struct sdpcm_shared_le {
 
 /* misc chip info needed by some of the routines */
 /* Private data for SDIO bus interaction */
-struct brcmf_bus {
+struct brcmf_sdio {
        struct brcmf_pub *drvr;
 
        struct brcmf_sdio_dev *sdiodev; /* sdio device handler */
@@ -562,9 +566,7 @@ struct brcmf_bus {
 
        struct semaphore sdsem;
 
-       const char *fw_name;
        const struct firmware *firmware;
-       const char *nv_name;
        u32 fw_ptr;
 };
 
@@ -602,7 +604,7 @@ static void pkt_align(struct sk_buff *p, int len, int align)
 }
 
 /* To check if there's window offered */
-static bool data_ok(struct brcmf_bus *bus)
+static bool data_ok(struct brcmf_sdio *bus)
 {
        return (u8)(bus->tx_max - bus->tx_seq) != 0 &&
               ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0;
@@ -613,7 +615,7 @@ static bool data_ok(struct brcmf_bus *bus)
  * adresses on the 32 bit backplane bus.
  */
 static void
-r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
+r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
 {
        u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        *retryvar = 0;
@@ -633,7 +635,7 @@ r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
 }
 
 static void
-w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)
+w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset, u32 *retryvar)
 {
        u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        *retryvar = 0;
@@ -658,14 +660,14 @@ w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)
 /* Packet free applicable unconditionally for sdio and sdspi.
  * Conditional if bufpool was present for gspi bus.
  */
-static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt)
+static void brcmf_sdbrcm_pktfree2(struct brcmf_sdio *bus, struct sk_buff *pkt)
 {
        if (bus->usebufpool)
                brcmu_pkt_buf_free_skb(pkt);
 }
 
 /* Turn backplane clock on or off */
-static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
+static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
 {
        int err;
        u8 clkctl, clkreq, devctl;
@@ -786,7 +788,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
 }
 
 /* Change idle/active SD state */
-static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on)
+static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -799,7 +801,7 @@ static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on)
 }
 
 /* Transition SD and backplane clock readiness */
-static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok)
+static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
 {
 #ifdef BCMDBG
        uint oldstate = bus->clkstate;
@@ -855,7 +857,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok)
        return 0;
 }
 
-static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
+static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
 {
        uint retries = 0;
 
@@ -927,13 +929,13 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
        return 0;
 }
 
-static void bus_wake(struct brcmf_bus *bus)
+static void bus_wake(struct brcmf_sdio *bus)
 {
        if (bus->sleeping)
                brcmf_sdbrcm_bussleep(bus, false);
 }
 
-static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus)
+static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
 {
        u32 intstatus = 0;
        u32 hmb_data;
@@ -1009,7 +1011,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus)
        return intstatus;
 }
 
-static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
+static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 {
        uint retries = 0;
        u16 lastrbc;
@@ -1066,11 +1068,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
 
        /* If we can't reach the device, signal failure */
        if (err || brcmf_sdcard_regfail(bus->sdiodev))
-               bus->drvr->busstate = BRCMF_BUS_DOWN;
+               bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
 }
 
 /* copy a buffer into a pkt buffer chain */
-static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len)
+static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_sdio *bus, uint len)
 {
        uint n, ret = 0;
        struct sk_buff *p;
@@ -1093,7 +1095,7 @@ static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len)
 }
 
 /* return total length of buffer chain */
-static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus)
+static uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus)
 {
        struct sk_buff *p;
        uint total;
@@ -1104,7 +1106,7 @@ static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus)
        return total;
 }
 
-static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus)
+static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
 {
        struct sk_buff *cur, *next;
 
@@ -1114,13 +1116,13 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus)
        }
 }
 
-static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
+static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 {
        u16 dlen, totlen;
        u8 *dptr, num = 0;
 
        u16 sublen, check;
-       struct sk_buff *pfirst, *plast, *pnext, *save_pfirst;
+       struct sk_buff *pfirst, *pnext;
 
        int errcode;
        u8 chan, seq, doff, sfdoff;
@@ -1137,7 +1139,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 
        /* If there's a descriptor, generate the packet chain */
        if (bus->glomd) {
-               pfirst = plast = pnext = NULL;
+               pfirst = pnext = NULL;
                dlen = (u16) (bus->glomd->len);
                dptr = bus->glomd->data;
                if (!dlen || (dlen & 1)) {
@@ -1228,17 +1230,14 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                 * packet and and copy into the chain.
                 */
                if (usechain) {
-                       errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
+                       errcode = brcmf_sdcard_recv_chain(bus->sdiodev,
                                        bus->sdiodev->sbwad,
-                                       SDIO_FUNC_2,
-                                       F2SYNC, (u8 *) pfirst->data, dlen,
-                                       pfirst);
+                                       SDIO_FUNC_2, F2SYNC, &bus->glom);
                } else if (bus->dataptr) {
                        errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
                                        bus->sdiodev->sbwad,
-                                       SDIO_FUNC_2,
-                                       F2SYNC, bus->dataptr, dlen,
-                                       NULL);
+                                       SDIO_FUNC_2, F2SYNC,
+                                       bus->dataptr, dlen);
                        sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen);
                        if (sublen != dlen) {
                                brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
@@ -1338,10 +1337,14 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                /* Remove superframe header, remember offset */
                skb_pull(pfirst, doff);
                sfdoff = doff;
+               num = 0;
 
                /* Validate all the subframe headers */
-               for (num = 0, pnext = pfirst; pnext && !errcode;
-                    num++, pnext = pnext->next) {
+               skb_queue_walk(&bus->glom, pnext) {
+                       /* leave when invalid subframe is found */
+                       if (errcode)
+                               break;
+
                        dptr = (u8 *) (pnext->data);
                        dlen = (u16) (pnext->len);
                        sublen = get_unaligned_le16(dptr);
@@ -1374,6 +1377,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                          num, doff, sublen, SDPCM_HDRLEN);
                                errcode = -1;
                        }
+                       /* increase the subframe count */
+                       num++;
                }
 
                if (errcode) {
@@ -1394,13 +1399,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                }
 
                /* Basic SD framing looks ok - process each packet (header) */
-               save_pfirst = pfirst;
-               plast = NULL;
-
-               for (num = 0; pfirst; rxseq++, pfirst = pnext) {
-                       pnext = pfirst->next;
-                       pfirst->next = NULL;
 
+               skb_queue_walk_safe(&bus->glom, pfirst, pnext) {
                        dptr = (u8 *) (pfirst->data);
                        sublen = get_unaligned_le16(dptr);
                        chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
@@ -1420,6 +1420,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                bus->rx_badseq++;
                                rxseq = seq;
                        }
+                       rxseq++;
+
 #ifdef BCMDBG
                        if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
                                printk(KERN_DEBUG "Rx Subframe Data:\n");
@@ -1432,36 +1434,22 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                        skb_pull(pfirst, doff);
 
                        if (pfirst->len == 0) {
+                               skb_unlink(pfirst, &bus->glom);
                                brcmu_pkt_buf_free_skb(pfirst);
-                               if (plast)
-                                       plast->next = pnext;
-                               else
-                                       save_pfirst = pnext;
-
                                continue;
                        } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx,
                                                       pfirst) != 0) {
                                brcmf_dbg(ERROR, "rx protocol error\n");
                                bus->drvr->rx_errors++;
+                               skb_unlink(pfirst, &bus->glom);
                                brcmu_pkt_buf_free_skb(pfirst);
-                               if (plast)
-                                       plast->next = pnext;
-                               else
-                                       save_pfirst = pnext;
-
                                continue;
                        }
 
-                       /* this packet will go up, link back into
-                                chain and count it */
-                       pfirst->next = pnext;
-                       plast = pfirst;
-                       num++;
-
 #ifdef BCMDBG
                        if (BRCMF_GLOM_ON()) {
                                brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n",
-                                         num, pfirst, pfirst->data,
+                                         bus->glom.qlen, pfirst, pfirst->data,
                                          pfirst->len, pfirst->next,
                                          pfirst->prev);
                                print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
@@ -1470,19 +1458,20 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                        }
 #endif                         /* BCMDBG */
                }
-               if (num) {
+               /* sent any remaining packets up */
+               if (bus->glom.qlen) {
                        up(&bus->sdsem);
-                       brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num);
+                       brcmf_rx_frame(bus->drvr, ifidx, &bus->glom);
                        down(&bus->sdsem);
                }
 
                bus->rxglomframes++;
-               bus->rxglompkts += num;
+               bus->rxglompkts += bus->glom.qlen;
        }
        return num;
 }
 
-static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition,
+static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
                                        bool *pending)
 {
        DECLARE_WAITQUEUE(wait, current);
@@ -1504,7 +1493,7 @@ static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition,
        return timeout;
 }
 
-static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus)
+static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus)
 {
        if (waitqueue_active(&bus->dcmd_resp_wait))
                wake_up_interruptible(&bus->dcmd_resp_wait);
@@ -1512,7 +1501,7 @@ static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus)
        return 0;
 }
 static void
-brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff)
+brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
 {
        uint rdlen, pad;
 
@@ -1570,8 +1559,7 @@ brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff)
        sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
                                bus->sdiodev->sbwad,
                                SDIO_FUNC_2,
-                               F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen,
-                               NULL);
+                               F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen);
        bus->f2rxdata++;
 
        /* Control frame failures need retransmission */
@@ -1602,7 +1590,7 @@ done:
 }
 
 /* Pad read to blocksize for efficiency */
-static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen)
+static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
 {
        if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {
                *pad = bus->blocksize - (*rdlen % bus->blocksize);
@@ -1615,7 +1603,7 @@ static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen)
 }
 
 static void
-brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen,
+brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen,
                         struct sk_buff **pkt, u8 **rxbuf)
 {
        int sdret;              /* Return code from calls */
@@ -1627,9 +1615,8 @@ brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen,
        pkt_align(*pkt, rdlen, BRCMF_SDALIGN);
        *rxbuf = (u8 *) ((*pkt)->data);
        /* Read the entire frame */
-       sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
-                                     SDIO_FUNC_2, F2SYNC,
-                                     *rxbuf, rdlen, *pkt);
+       sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
+                                     SDIO_FUNC_2, F2SYNC, *pkt);
        bus->f2rxdata++;
 
        if (sdret < 0) {
@@ -1648,7 +1635,7 @@ brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen,
 
 /* Checks the header */
 static int
-brcmf_check_rxbuf(struct brcmf_bus *bus, struct sk_buff *pkt, u8 *rxbuf,
+brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf,
                  u8 rxseq, u16 nextlen, u16 *len)
 {
        u16 check;
@@ -1704,7 +1691,7 @@ fail:
 
 /* Return true if there may be more frames to read */
 static uint
-brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
+brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 {
        u16 len, check; /* Extracted hardware header fields */
        u8 chan, seq, doff;     /* Extracted software header fields */
@@ -1727,7 +1714,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
        *finished = false;
 
        for (rxseq = bus->rx_seq, rxleft = maxframes;
-            !bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN;
+            !bus->rxskip && rxleft &&
+            bus->drvr->bus_if->state != BRCMF_BUS_DOWN;
             rxseq++, rxleft--) {
 
                /* Handle glomming separately */
@@ -1857,7 +1845,7 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
                /* Read frame header (hardware and software) */
                sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
                                              SDIO_FUNC_2, F2SYNC, bus->rxhdr,
-                                             BRCMF_FIRSTREAD, NULL);
+                                             BRCMF_FIRSTREAD);
                bus->f2rxhdrs++;
 
                if (sdret < 0) {
@@ -2006,9 +1994,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
                pkt_align(pkt, rdlen, BRCMF_SDALIGN);
 
                /* Read the remaining frame data */
-               sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
-                               SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)),
-                               rdlen, pkt);
+               sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
+                                             SDIO_FUNC_2, F2SYNC, pkt);
                bus->f2rxdata++;
 
                if (sdret < 0) {
@@ -2075,7 +2062,7 @@ deliver:
 
                /* Unlock during rx call */
                up(&bus->sdsem);
-               brcmf_rx_frame(bus->drvr, ifidx, pkt, 1);
+               brcmf_rx_packet(bus->drvr, ifidx, pkt);
                down(&bus->sdsem);
        }
        rxcount = maxframes - rxleft;
@@ -2095,16 +2082,8 @@ deliver:
        return rxcount;
 }
 
-static int
-brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags,
-                   u8 *buf, uint nbytes, struct sk_buff *pkt)
-{
-       return brcmf_sdcard_send_buf
-               (bus->sdiodev, addr, fn, flags, buf, nbytes, pkt);
-}
-
 static void
-brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar)
+brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar)
 {
        up(&bus->sdsem);
        wait_event_interruptible_timeout(bus->ctrl_wait,
@@ -2114,7 +2093,7 @@ brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar)
 }
 
 static void
-brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus)
+brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
 {
        if (waitqueue_active(&bus->ctrl_wait))
                wake_up_interruptible(&bus->ctrl_wait);
@@ -2123,7 +2102,7 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus)
 
 /* Writes a HW/SW header into the packet and sends it. */
 /* Assumes: (a) header space already there, (b) caller holds lock */
-static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt,
+static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
                              uint chan, bool free_pkt)
 {
        int ret;
@@ -2212,9 +2191,8 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt,
        if (len & (ALIGNMENT - 1))
                        len = roundup(len, ALIGNMENT);
 
-       ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
-                                   SDIO_FUNC_2, F2SYNC, frame,
-                                   len, pkt);
+       ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
+                                   SDIO_FUNC_2, F2SYNC, pkt);
        bus->f2txdata++;
 
        if (ret < 0) {
@@ -2261,7 +2239,7 @@ done:
        return ret;
 }
 
-static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes)
+static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 {
        struct sk_buff *pkt;
        u32 intstatus = 0;
@@ -2309,14 +2287,14 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes)
        }
 
        /* Deflow-control stack if needed */
-       if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) &&
+       if (drvr->up && (drvr->bus_if->state == BRCMF_BUS_DATA) &&
            drvr->txoff && (pktq_len(&bus->txq) < TXLOW))
                brcmf_txflowcontrol(drvr, 0, OFF);
 
        return cnt;
 }
 
-static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
+static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 {
        u32 intstatus, newstatus = 0;
        uint retries = 0;
@@ -2344,7 +2322,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
                                               SBSDIO_DEVICE_CTL, &err);
                if (err) {
                        brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
-                       bus->drvr->busstate = BRCMF_BUS_DOWN;
+                       bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
                }
 #endif                         /* BCMDBG */
 
@@ -2354,7 +2332,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
                if (err) {
                        brcmf_dbg(ERROR, "error reading CSR: %d\n",
                                  err);
-                       bus->drvr->busstate = BRCMF_BUS_DOWN;
+                       bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
                }
 
                brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
@@ -2367,7 +2345,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
                        if (err) {
                                brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
                                          err);
-                               bus->drvr->busstate = BRCMF_BUS_DOWN;
+                               bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
                        }
                        devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
                        brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
@@ -2375,7 +2353,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
                        if (err) {
                                brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
                                          err);
-                               bus->drvr->busstate = BRCMF_BUS_DOWN;
+                               bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
                        }
                        bus->clkstate = CLK_AVAIL;
                } else {
@@ -2477,9 +2455,9 @@ clkwait:
                (bus->clkstate == CLK_AVAIL)) {
                int ret, i;
 
-               ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
+               ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
                        SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf,
-                       (u32) bus->ctrl_frame_len, NULL);
+                       (u32) bus->ctrl_frame_len);
 
                if (ret < 0) {
                        /* On failure, abort the command and
@@ -2531,11 +2509,11 @@ clkwait:
                 else await next interrupt */
        /* On failed register access, all bets are off:
                 no resched or interrupts */
-       if ((bus->drvr->busstate == BRCMF_BUS_DOWN) ||
+       if ((bus->drvr->bus_if->state == BRCMF_BUS_DOWN) ||
            brcmf_sdcard_regfail(bus->sdiodev)) {
                brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n",
                          brcmf_sdcard_regfail(bus->sdiodev));
-               bus->drvr->busstate = BRCMF_BUS_DOWN;
+               bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
                bus->intstatus = 0;
        } else if (bus->clkstate == CLK_PENDING) {
                brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n");
@@ -2562,7 +2540,7 @@ clkwait:
 
 static int brcmf_sdbrcm_dpc_thread(void *data)
 {
-       struct brcmf_bus *bus = (struct brcmf_bus *) data;
+       struct brcmf_sdio *bus = (struct brcmf_sdio *) data;
 
        allow_signal(SIGTERM);
        /* Run until signal received */
@@ -2572,12 +2550,12 @@ static int brcmf_sdbrcm_dpc_thread(void *data)
                if (!wait_for_completion_interruptible(&bus->dpc_wait)) {
                        /* Call bus dpc unless it indicated down
                        (then clean stop) */
-                       if (bus->drvr->busstate != BRCMF_BUS_DOWN) {
+                       if (bus->drvr->bus_if->state != BRCMF_BUS_DOWN) {
                                if (brcmf_sdbrcm_dpc(bus))
                                        complete(&bus->dpc_wait);
                        } else {
                                /* after stopping the bus, exit thread */
-                               brcmf_sdbrcm_bus_stop(bus);
+                               brcmf_sdbrcm_bus_stop(bus->sdiodev->dev);
                                bus->dpc_tsk = NULL;
                                break;
                        }
@@ -2587,10 +2565,13 @@ static int brcmf_sdbrcm_dpc_thread(void *data)
        return 0;
 }
 
-int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt)
+int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
 {
        int ret = -EBADE;
        uint datalen, prec;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio *bus = sdiodev->bus;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -2638,7 +2619,7 @@ int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt)
 }
 
 static int
-brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data,
+brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,
                 uint size)
 {
        int bcmerror = 0;
@@ -2699,7 +2680,7 @@ xfer_done:
 #ifdef BCMDBG
 #define CONSOLE_LINE_MAX       192
 
-static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus)
+static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)
 {
        struct brcmf_console *c = &bus->console;
        u8 line[CONSOLE_LINE_MAX], ch;
@@ -2776,14 +2757,14 @@ break2:
 }
 #endif                         /* BCMDBG */
 
-static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len)
+static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
 {
        int i;
        int ret;
 
        bus->ctrl_frame_stat = false;
-       ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
-                                   SDIO_FUNC_2, F2SYNC, frame, len, NULL);
+       ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
+                                   SDIO_FUNC_2, F2SYNC, frame, len);
 
        if (ret < 0) {
                /* On failure, abort the command and terminate the frame */
@@ -2819,7 +2800,7 @@ static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len)
 }
 
 int
-brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
+brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 {
        u8 *frame;
        u16 len;
@@ -2827,6 +2808,9 @@ brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
        uint retries = 0;
        u8 doff = 0;
        int ret = -1;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio *bus = sdiodev->bus;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -2934,11 +2918,14 @@ brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
 }
 
 int
-brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
+brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
 {
        int timeleft;
        uint rxlen = 0;
        bool pending;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio *bus = sdiodev->bus;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -2971,7 +2958,7 @@ brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
        return rxlen ? (int)rxlen : -ETIMEDOUT;
 }
 
-static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len)
+static int brcmf_sdbrcm_downloadvars(struct brcmf_sdio *bus, void *arg, int len)
 {
        int bcmerror = 0;
 
@@ -3004,7 +2991,7 @@ err:
        return bcmerror;
 }
 
-static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
+static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
 {
        int bcmerror = 0;
        u32 varsize;
@@ -3091,7 +3078,7 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
        return bcmerror;
 }
 
-static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
+static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
 {
        uint retries;
        int bcmerror = 0;
@@ -3134,13 +3121,13 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
                /* Allow HT Clock now that the ARM is running. */
                bus->alp_only = false;
 
-               bus->drvr->busstate = BRCMF_BUS_LOAD;
+               bus->drvr->bus_if->state = BRCMF_BUS_LOAD;
        }
 fail:
        return bcmerror;
 }
 
-static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus)
+static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus)
 {
        if (bus->firmware->size < bus->fw_ptr + len)
                len = bus->firmware->size - bus->fw_ptr;
@@ -3150,10 +3137,7 @@ static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus)
        return len;
 }
 
-MODULE_FIRMWARE(BCM4329_FW_NAME);
-MODULE_FIRMWARE(BCM4329_NV_NAME);
-
-static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
+static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
 {
        int offset = 0;
        uint len;
@@ -3162,8 +3146,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
 
        brcmf_dbg(INFO, "Enter\n");
 
-       bus->fw_name = BCM4329_FW_NAME;
-       ret = request_firmware(&bus->firmware, bus->fw_name,
+       ret = request_firmware(&bus->firmware, BRCMFMAC_FW_NAME,
                               &bus->sdiodev->func[2]->dev);
        if (ret) {
                brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
@@ -3253,15 +3236,14 @@ static uint brcmf_process_nvram_vars(char *varbuf, uint len)
        return buf_len;
 }
 
-static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus)
+static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
 {
        uint len;
        char *memblock = NULL;
        char *bufp;
        int ret;
 
-       bus->nv_name = BCM4329_NV_NAME;
-       ret = request_firmware(&bus->firmware, bus->nv_name,
+       ret = request_firmware(&bus->firmware, BRCMFMAC_NV_NAME,
                               &bus->sdiodev->func[2]->dev);
        if (ret) {
                brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
@@ -3301,7 +3283,7 @@ err:
        return ret;
 }
 
-static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
+static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
 {
        int bcmerror = -1;
 
@@ -3334,7 +3316,7 @@ err:
 }
 
 static bool
-brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
+brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
 {
        bool ret;
 
@@ -3348,12 +3330,15 @@ brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
        return ret;
 }
 
-void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
+void brcmf_sdbrcm_bus_stop(struct device *dev)
 {
        u32 local_hostintmask;
        u8 saveclk;
        uint retries;
        int err;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio *bus = sdiodev->bus;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3382,7 +3367,7 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
        bus->hostintmask = 0;
 
        /* Change our idea of bus state */
-       bus->drvr->busstate = BRCMF_BUS_DOWN;
+       bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
 
        /* Force clocks on backplane to be sure F2 interrupt propagates */
        saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
@@ -3426,9 +3411,11 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
        up(&bus->sdsem);
 }
 
-int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
+int brcmf_sdbrcm_bus_init(struct device *dev)
 {
-       struct brcmf_bus *bus = drvr->bus;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
+       struct brcmf_sdio *bus = sdiodev->bus;
        unsigned long timeout;
        uint retries = 0;
        u8 ready, enable;
@@ -3438,7 +3425,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
        brcmf_dbg(TRACE, "Enter\n");
 
        /* try to download image and nvram to the dongle */
-       if (drvr->busstate == BRCMF_BUS_DOWN) {
+       if (bus_if->state == BRCMF_BUS_DOWN) {
                if (!(brcmf_sdbrcm_download_firmware(bus)))
                        return -1;
        }
@@ -3504,7 +3491,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
                                       SBSDIO_WATERMARK, 8, &err);
 
                /* Set bus state according to enable result */
-               drvr->busstate = BRCMF_BUS_DATA;
+               bus_if->state = BRCMF_BUS_DATA;
        }
 
        else {
@@ -3519,7 +3506,7 @@ int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
                               SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
 
        /* If we didn't come up, turn off backplane clock */
-       if (drvr->busstate != BRCMF_BUS_DATA)
+       if (bus_if->state != BRCMF_BUS_DATA)
                brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
 
 exit:
@@ -3530,7 +3517,7 @@ exit:
 
 void brcmf_sdbrcm_isr(void *arg)
 {
-       struct brcmf_bus *bus = (struct brcmf_bus *) arg;
+       struct brcmf_sdio *bus = (struct brcmf_sdio *) arg;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3539,7 +3526,7 @@ void brcmf_sdbrcm_isr(void *arg)
                return;
        }
 
-       if (bus->drvr->busstate == BRCMF_BUS_DOWN) {
+       if (bus->drvr->bus_if->state == BRCMF_BUS_DOWN) {
                brcmf_dbg(ERROR, "bus is down. we have nothing to do\n");
                return;
        }
@@ -3562,14 +3549,14 @@ void brcmf_sdbrcm_isr(void *arg)
                complete(&bus->dpc_wait);
 }
 
-static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr)
+static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
 {
-       struct brcmf_bus *bus;
+#ifdef BCMDBG
+       struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
+#endif /* BCMDBG */
 
        brcmf_dbg(TIMER, "Enter\n");
 
-       bus = drvr->bus;
-
        /* Ignore the timer if simulating bus down */
        if (bus->sleeping)
                return false;
@@ -3613,7 +3600,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr)
        }
 #ifdef BCMDBG
        /* Poll for console output periodically */
-       if (drvr->busstate == BRCMF_BUS_DATA && bus->console_interval != 0) {
+       if (bus_if->state == BRCMF_BUS_DATA &&
+           bus->console_interval != 0) {
                bus->console.count += BRCMF_WD_POLL_MS;
                if (bus->console.count >= bus->console_interval) {
                        bus->console.count -= bus->console_interval;
@@ -3651,7 +3639,7 @@ static bool brcmf_sdbrcm_chipmatch(u16 chipid)
        return false;
 }
 
-static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus)
+static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3663,7 +3651,7 @@ static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus)
        bus->databuf = NULL;
 }
 
-static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus)
+static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3699,7 +3687,7 @@ fail:
 }
 
 static bool
-brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
+brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
 {
        u8 clkctl = 0;
        int err = 0;
@@ -3784,7 +3772,7 @@ fail:
        return false;
 }
 
-static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus)
+static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3792,7 +3780,7 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus)
        brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
                               SDIO_FUNC_ENABLE_1, NULL);
 
-       bus->drvr->busstate = BRCMF_BUS_DOWN;
+       bus->drvr->bus_if->state = BRCMF_BUS_DOWN;
        bus->sleeping = false;
        bus->rxflow = false;
 
@@ -3819,7 +3807,7 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus)
 static int
 brcmf_sdbrcm_watchdog_thread(void *data)
 {
-       struct brcmf_bus *bus = (struct brcmf_bus *)data;
+       struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
 
        allow_signal(SIGTERM);
        /* Run until signal received */
@@ -3827,7 +3815,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
                if (kthread_should_stop())
                        break;
                if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
-                       brcmf_sdbrcm_bus_watchdog(bus->drvr);
+                       brcmf_sdbrcm_bus_watchdog(bus);
                        /* Count the tick for reference */
                        bus->drvr->tickcnt++;
                } else
@@ -3839,7 +3827,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
 static void
 brcmf_sdbrcm_watchdog(unsigned long data)
 {
-       struct brcmf_bus *bus = (struct brcmf_bus *)data;
+       struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
 
        if (bus->watchdog_tsk) {
                complete(&bus->watchdog_wait);
@@ -3850,7 +3838,7 @@ brcmf_sdbrcm_watchdog(unsigned long data)
        }
 }
 
-static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
+static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3867,7 +3855,7 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
 }
 
 /* Detach and free everything */
-static void brcmf_sdbrcm_release(struct brcmf_bus *bus)
+static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3889,21 +3877,10 @@ static void brcmf_sdbrcm_release(struct brcmf_bus *bus)
        brcmf_dbg(TRACE, "Disconnected\n");
 }
 
-void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
-                        u32 regsva, struct brcmf_sdio_dev *sdiodev)
+void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 {
        int ret;
-       struct brcmf_bus *bus;
-
-       /* Init global variables at run-time, not as part of the declaration.
-        * This is required to support init/de-init of the driver.
-        * Initialization
-        * of globals as part of the declaration results in non-deterministic
-        * behavior since the value of the globals may be different on the
-        * first time that the driver is initialized vs subsequent
-        * initializations.
-        */
-       brcmf_c_init();
+       struct brcmf_sdio *bus;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3911,7 +3888,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
         * regsva == SI_ENUM_BASE*/
 
        /* Allocate private bus interface state */
-       bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
+       bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC);
        if (!bus)
                goto fail;
 
@@ -3963,7 +3940,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
        }
 
        /* Attach to the brcmf/OS/network interface */
-       bus->drvr = brcmf_attach(bus, SDPCM_RESERVE);
+       bus->drvr = brcmf_attach(bus, SDPCM_RESERVE, bus->sdiodev->dev);
        if (!bus->drvr) {
                brcmf_dbg(ERROR, "brcmf_attach failed\n");
                goto fail;
@@ -4015,7 +3992,7 @@ fail:
 
 void brcmf_sdbrcm_disconnect(void *ptr)
 {
-       struct brcmf_bus *bus = (struct brcmf_bus *)ptr;
+       struct brcmf_sdio *bus = (struct brcmf_sdio *)ptr;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -4025,13 +4002,8 @@ void brcmf_sdbrcm_disconnect(void *ptr)
        brcmf_dbg(TRACE, "Disconnected\n");
 }
 
-struct device *brcmf_bus_get_device(struct brcmf_bus *bus)
-{
-       return &bus->sdiodev->func[2]->dev;
-}
-
 void
-brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
+brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick)
 {
        /* Totally stop the timer */
        if (!wdtick && bus->wd_timer_valid == true) {
@@ -4042,7 +4014,7 @@ brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
        }
 
        /* don't start the wd until fw is loaded */
-       if (bus->drvr->busstate == BRCMF_BUS_DOWN)
+       if (bus->drvr->bus_if->state == BRCMF_BUS_DOWN)
                return;
 
        if (wdtick) {
index 726fa89..c4c2543 100644 (file)
@@ -132,9 +132,9 @@ struct brcmf_sdio_dev {
        atomic_t suspend;               /* suspend flag */
        wait_queue_head_t request_byte_wait;
        wait_queue_head_t request_word_wait;
-       wait_queue_head_t request_packet_wait;
+       wait_queue_head_t request_chain_wait;
        wait_queue_head_t request_buffer_wait;
-
+       struct device *dev;
 };
 
 /* Register/deregister device interrupt handler. */
@@ -182,11 +182,21 @@ extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev);
  * NOTE: Async operation is not currently supported.
  */
 extern int
+brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+                     uint flags, struct sk_buff *pkt);
+extern int
 brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                     uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt);
+                     uint flags, u8 *buf, uint nbytes);
+
+extern int
+brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+                     uint flags, struct sk_buff *pkt);
 extern int
 brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
-                     uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt);
+                     uint flags, u8 *buf, uint nbytes);
+extern int
+brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+                       uint flags, struct sk_buff_head *pktq);
 
 /* Flags bits */
 
@@ -237,16 +247,18 @@ brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
 /* read or write any buffer using cmd53 */
 extern int
 brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
-                          uint fix_inc, uint rw, uint fnc_num,
-                          u32 addr, uint regwidth,
-                          u32 buflen, u8 *buffer, struct sk_buff *pkt);
+                          uint fix_inc, uint rw, uint fnc_num, u32 addr,
+                          struct sk_buff *pkt);
+extern int
+brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
+                         uint write, uint func, uint addr,
+                         struct sk_buff_head *pktq);
 
 /* Watchdog timer interface for pm ops */
 extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev,
                                    bool enable);
 
-extern void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
-                               u32 regsva, struct brcmf_sdio_dev *sdiodev);
+extern void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev);
 extern void brcmf_sdbrcm_disconnect(void *ptr);
 extern void brcmf_sdbrcm_isr(void *arg);
 #endif                         /* _BRCM_SDH_H_ */
index cc19a73..f23b0c3 100644 (file)
@@ -1429,7 +1429,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
 
 static s32
 brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
-                        enum nl80211_tx_power_setting type, s32 dbm)
+                           enum nl80211_tx_power_setting type, s32 mbm)
 {
 
        struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
@@ -1437,6 +1437,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
        u16 txpwrmw;
        s32 err = 0;
        s32 disable = 0;
+       s32 dbm = MBM_TO_DBM(mbm);
 
        WL_TRACE("Enter\n");
        if (!check_sys_up(wiphy))
@@ -1446,12 +1447,6 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
        case NL80211_TX_POWER_AUTOMATIC:
                break;
        case NL80211_TX_POWER_LIMITED:
-               if (dbm < 0) {
-                       WL_ERR("TX_POWER_LIMITED - dbm is negative\n");
-                       err = -EINVAL;
-                       goto done;
-               }
-               break;
        case NL80211_TX_POWER_FIXED:
                if (dbm < 0) {
                        WL_ERR("TX_POWER_FIXED - dbm is negative\n");
index 0bb8c37..b55b1f6 100644 (file)
@@ -1239,10 +1239,9 @@ bool dma_rxreset(struct dma_pub *pub)
  *   the error(toss frames) could be fatal and cause many subsequent hard
  *   to debug problems
  */
-int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)
+int dma_txfast(struct dma_pub *pub, struct sk_buff *p, bool commit)
 {
        struct dma_info *di = (struct dma_info *)pub;
-       struct sk_buff *p, *next;
        unsigned char *data;
        uint len;
        u16 txout;
@@ -1254,50 +1253,37 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)
        txout = di->txout;
 
        /*
-        * Walk the chain of packet buffers
-        * allocating and initializing transmit descriptor entries.
+        * obtain and initialize transmit descriptor entry.
         */
-       for (p = p0; p; p = next) {
-               data = p->data;
-               len = p->len;
-               next = p->next;
-
-               /* return nonzero if out of tx descriptors */
-               if (nexttxd(di, txout) == di->txin)
-                       goto outoftxd;
+       data = p->data;
+       len = p->len;
 
-               if (len == 0)
-                       continue;
-
-               /* get physical address of buffer start */
-               pa = pci_map_single(di->pbus, data, len, PCI_DMA_TODEVICE);
+       /* no use to transmit a zero length packet */
+       if (len == 0)
+               return 0;
 
-               flags = 0;
-               if (p == p0)
-                       flags |= D64_CTRL1_SOF;
+       /* return nonzero if out of tx descriptors */
+       if (nexttxd(di, txout) == di->txin)
+               goto outoftxd;
 
-               /* With a DMA segment list, Descriptor table is filled
-                * using the segment list instead of looping over
-                * buffers in multi-chain DMA. Therefore, EOF for SGLIST
-                * is when end of segment list is reached.
-                */
-               if (next == NULL)
-                       flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF);
-               if (txout == (di->ntxd - 1))
-                       flags |= D64_CTRL1_EOT;
+       /* get physical address of buffer start */
+       pa = pci_map_single(di->pbus, data, len, PCI_DMA_TODEVICE);
 
-               dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
+       /* With a DMA segment list, Descriptor table is filled
+        * using the segment list instead of looping over
+        * buffers in multi-chain DMA. Therefore, EOF for SGLIST
+        * is when end of segment list is reached.
+        */
+       flags = D64_CTRL1_SOF | D64_CTRL1_IOC | D64_CTRL1_EOF;
+       if (txout == (di->ntxd - 1))
+               flags |= D64_CTRL1_EOT;
 
-               txout = nexttxd(di, txout);
-       }
+       dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
 
-       /* if last txd eof not set, fix it */
-       if (!(flags & D64_CTRL1_EOF))
-               di->txd64[prevtxd(di, txout)].ctrl1 =
-                    cpu_to_le32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF);
+       txout = nexttxd(di, txout);
 
        /* save the packet */
-       di->txp[prevtxd(di, txout)] = p0;
+       di->txp[prevtxd(di, txout)] = p;
 
        /* bump the tx descriptor index */
        di->txout = txout;
@@ -1314,7 +1300,7 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)
 
  outoftxd:
        DMA_ERROR("%s: out of txds !!!\n", di->name);
-       brcmu_pkt_buf_free_skb(p0);
+       brcmu_pkt_buf_free_skb(p);
        di->dma.txavail = 0;
        di->dma.txnobuf++;
        return -1;
index ba3e4b5..76376eb 100644 (file)
 #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
        FIF_ALLMULTI | \
        FIF_FCSFAIL | \
-       FIF_PLCPFAIL | \
        FIF_CONTROL | \
        FIF_OTHER_BSS | \
-       FIF_BCN_PRBRESP_PROMISC)
+       FIF_BCN_PRBRESP_PROMISC | \
+       FIF_PSPOLL)
 
 #define CHAN2GHZ(channel, freqency, chflags)  { \
        .band = IEEE80211_BAND_2GHZ, \
@@ -373,7 +373,7 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
                                                   conf->listen_interval);
        }
        if (changed & IEEE80211_CONF_CHANGE_MONITOR)
-               wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n",
+               wiphy_dbg(wiphy, "%s: change monitor mode: %s\n",
                          __func__, conf->flags & IEEE80211_CONF_MONITOR ?
                          "true" : "false");
        if (changed & IEEE80211_CONF_CHANGE_PS)
@@ -550,29 +550,25 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
 
        changed_flags &= MAC_FILTERS;
        *total_flags &= MAC_FILTERS;
+
        if (changed_flags & FIF_PROMISC_IN_BSS)
-               wiphy_err(wiphy, "FIF_PROMISC_IN_BSS\n");
+               wiphy_dbg(wiphy, "FIF_PROMISC_IN_BSS\n");
        if (changed_flags & FIF_ALLMULTI)
-               wiphy_err(wiphy, "FIF_ALLMULTI\n");
+               wiphy_dbg(wiphy, "FIF_ALLMULTI\n");
        if (changed_flags & FIF_FCSFAIL)
-               wiphy_err(wiphy, "FIF_FCSFAIL\n");
-       if (changed_flags & FIF_PLCPFAIL)
-               wiphy_err(wiphy, "FIF_PLCPFAIL\n");
+               wiphy_dbg(wiphy, "FIF_FCSFAIL\n");
        if (changed_flags & FIF_CONTROL)
-               wiphy_err(wiphy, "FIF_CONTROL\n");
+               wiphy_dbg(wiphy, "FIF_CONTROL\n");
        if (changed_flags & FIF_OTHER_BSS)
-               wiphy_err(wiphy, "FIF_OTHER_BSS\n");
-       if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-               spin_lock_bh(&wl->lock);
-               if (*total_flags & FIF_BCN_PRBRESP_PROMISC) {
-                       wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS;
-                       brcms_c_mac_bcn_promisc_change(wl->wlc, 1);
-               } else {
-                       brcms_c_mac_bcn_promisc_change(wl->wlc, 0);
-                       wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS;
-               }
-               spin_unlock_bh(&wl->lock);
-       }
+               wiphy_dbg(wiphy, "FIF_OTHER_BSS\n");
+       if (changed_flags & FIF_PSPOLL)
+               wiphy_dbg(wiphy, "FIF_PSPOLL\n");
+       if (changed_flags & FIF_BCN_PRBRESP_PROMISC)
+               wiphy_dbg(wiphy, "FIF_BCN_PRBRESP_PROMISC\n");
+
+       spin_lock_bh(&wl->lock);
+       brcms_c_mac_promisc(wl->wlc, *total_flags);
+       spin_unlock_bh(&wl->lock);
        return;
 }
 
index 36e3e06..87f8f5d 100644 (file)
@@ -955,8 +955,6 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
        brcms_c_txfifo_complete(wlc, queue, 1);
 
        if (lastframe) {
-               p->next = NULL;
-               p->prev = NULL;
                /* remove PLCP & Broadcom tx descriptor header */
                skb_pull(p, D11_PHY_HDR_LEN);
                skb_pull(p, D11_TXH_LEN);
@@ -3064,7 +3062,7 @@ static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
                return false;
 
        /* disallow PS when one of these meets when not scanning */
-       if (wlc->monitor)
+       if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
                return false;
 
        if (cfg->associated) {
@@ -3584,29 +3582,31 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
 }
 
 /*
- * Set or clear maccontrol bits MCTL_PROMISC, MCTL_BCNS_PROMISC and
- * MCTL_KEEPCONTROL
+ * Set or clear filtering related maccontrol bits based on
+ * specified filter flags
  */
-static void brcms_c_mac_promisc(struct brcms_c_info *wlc)
+void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags)
 {
        u32 promisc_bits = 0;
 
-       if (wlc->bcnmisc_monitor)
+       wlc->filter_flags = filter_flags;
+
+       if (filter_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+               promisc_bits |= MCTL_PROMISC;
+
+       if (filter_flags & FIF_BCN_PRBRESP_PROMISC)
                promisc_bits |= MCTL_BCNS_PROMISC;
 
-       if (wlc->monitor)
-               promisc_bits |=
-                       MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL;
+       if (filter_flags & FIF_FCSFAIL)
+               promisc_bits |= MCTL_KEEPBADFCS;
 
-       brcms_b_mctrl(wlc->hw,
-                       MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL,
-                       promisc_bits);
-}
+       if (filter_flags & (FIF_CONTROL | FIF_PSPOLL))
+               promisc_bits |= MCTL_KEEPCONTROL;
 
-void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
-{
-       wlc->bcnmisc_monitor = promisc;
-       brcms_c_mac_promisc(wlc);
+       brcms_b_mctrl(wlc->hw,
+               MCTL_PROMISC | MCTL_BCNS_PROMISC |
+               MCTL_KEEPCONTROL | MCTL_KEEPBADFCS,
+               promisc_bits);
 }
 
 /*
@@ -3636,9 +3636,6 @@ static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
        } else {
                /* disable an active IBSS if we are not on the home channel */
        }
-
-       /* update the various promisc bits */
-       brcms_c_mac_promisc(wlc);
 }
 
 static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
@@ -8074,14 +8071,8 @@ static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
        len = p->len;
 
        if (rxh->RxStatus1 & RXS_FCSERR) {
-               if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) {
-                       wiphy_err(wlc->wiphy, "FCSERR while scanning******* -"
-                                 " tossing\n");
+               if (!(wlc->filter_flags & FIF_FCSFAIL))
                        goto toss;
-               } else {
-                       wiphy_err(wlc->wiphy, "RCSERR!!!\n");
-                       goto toss;
-               }
        }
 
        /* check received pkt has at least frame control field */
index 251c350..e2de97d 100644 (file)
@@ -519,8 +519,7 @@ struct brcms_c_info {
        struct brcms_timer *radio_timer;
 
        /* promiscuous */
-       bool monitor;
-       bool bcnmisc_monitor;
+       uint filter_flags;
 
        /* driver feature */
        bool _rifs;
@@ -658,8 +657,7 @@ extern void brcms_c_print_txdesc(struct d11txh *txh);
 #endif
 
 extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config);
-extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc,
-                                          bool promisc);
+extern void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags);
 extern void brcms_c_send_q(struct brcms_c_info *wlc);
 extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu,
                            uint *fifo);
index e17edf7..008aab9 100644 (file)
@@ -109,7 +109,7 @@ static const struct chan_info_basic chan_info_all[] = {
        {204, 5020},
        {208, 5040},
        {212, 5060},
-       {216, 50800}
+       {216, 5080}
 };
 
 static const u8 ofdm_rate_lookup[] = {
index 5441ad1..89e9d3a 100644 (file)
@@ -655,6 +655,9 @@ static const struct pcmcia_device_id hostap_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID123(
                "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
                0xe6ec52ce, 0x08649af2, 0x4b74baa0),
+       PCMCIA_DEVICE_PROD_ID123(
+               "Canon", "Wireless LAN CF Card K30225", "Version 01.00",
+               0x96ef6fe2, 0x263fcbab, 0xa57adb8c),
        PCMCIA_DEVICE_PROD_ID123(
                "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02",
                0x71b18589, 0xb6f1b0ab, 0x4b74baa0),
index 11b69b3..0c87f42 100644 (file)
@@ -1290,7 +1290,6 @@ static struct spi_driver libertas_spi_driver = {
        .remove = __devexit_p(libertas_spi_remove),
        .driver = {
                .name   = "libertas_spi",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
                .pm     = &if_spi_pm_ops,
        },
index e9ab9a3..0db97cc 100644 (file)
@@ -120,10 +120,11 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
 static int
 mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
                              enum nl80211_tx_power_setting type,
-                             int dbm)
+                             int mbm)
 {
        struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
        struct mwifiex_power_cfg power_cfg;
+       int dbm = MBM_TO_DBM(mbm);
 
        if (type == NL80211_TX_POWER_FIXED) {
                power_cfg.is_power_auto = 0;
index a454d48..5465513 100644 (file)
@@ -699,7 +699,6 @@ static int __devexit p54spi_remove(struct spi_device *spi)
 static struct spi_driver p54spi_driver = {
        .driver = {
                .name           = "p54spi",
-               .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
 
index d97a2ca..f83bc5a 100644 (file)
@@ -2493,323 +2493,7 @@ prism54_set_mac_address(struct net_device *ndev, void *addr)
        return ret;
 }
 
-/* Note: currently, use hostapd ioctl from the Host AP driver for WPA
- * support. This is to be replaced with Linux wireless extensions once they
- * get WPA support. */
-
-/* Note II: please leave all this together as it will be easier to remove later,
- * once wireless extensions add WPA support -mcgrof */
-
-/* PRISM54_HOSTAPD ioctl() cmd: */
-enum {
-       PRISM2_SET_ENCRYPTION = 6,
-       PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
-       PRISM2_HOSTAPD_MLME = 13,
-       PRISM2_HOSTAPD_SCAN_REQ = 14,
-};
-
 #define PRISM54_SET_WPA                        SIOCIWFIRSTPRIV+12
-#define PRISM54_HOSTAPD                        SIOCIWFIRSTPRIV+25
-#define PRISM54_DROP_UNENCRYPTED       SIOCIWFIRSTPRIV+26
-
-#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
-#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-       offsetof(struct prism2_hostapd_param, u.generic_elem.data)
-
-/* Maximum length for algorithm names (-1 for nul termination)
- * used in ioctl() */
-#define HOSTAP_CRYPT_ALG_NAME_LEN 16
-
-struct prism2_hostapd_param {
-       u32 cmd;
-       u8 sta_addr[ETH_ALEN];
-       union {
-              struct {
-                      u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
-                      u32 flags;
-                      u32 err;
-                      u8 idx;
-                      u8 seq[8]; /* sequence counter (set: RX, get: TX) */
-                      u16 key_len;
-                      u8 key[0];
-                      } crypt;
-               struct {
-                       u8 len;
-                       u8 data[0];
-               } generic_elem;
-               struct {
-#define MLME_STA_DEAUTH 0
-#define MLME_STA_DISASSOC 1
-                       u16 cmd;
-                       u16 reason_code;
-               } mlme;
-               struct {
-                       u8 ssid_len;
-                       u8 ssid[32];
-               } scan_req;
-       } u;
-};
-
-
-static int
-prism2_ioctl_set_encryption(struct net_device *dev,
-       struct prism2_hostapd_param *param,
-       int param_len)
-{
-       islpci_private *priv = netdev_priv(dev);
-       int rvalue = 0, force = 0;
-       int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
-       union oid_res_t r;
-
-       /* with the new API, it's impossible to get a NULL pointer.
-        * New version of iwconfig set the IW_ENCODE_NOKEY flag
-        * when no key is given, but older versions don't. */
-
-       if (param->u.crypt.key_len > 0) {
-               /* we have a key to set */
-               int index = param->u.crypt.idx;
-               int current_index;
-               struct obj_key key = { DOT11_PRIV_TKIP, 0, "" };
-
-               /* get the current key index */
-               rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
-               current_index = r.u;
-               /* Verify that the key is not marked as invalid */
-               if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
-                       key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
-                           sizeof (param->u.crypt.key) : param->u.crypt.key_len;
-                       memcpy(key.key, param->u.crypt.key, key.length);
-                       if (key.length == 32)
-                               /* we want WPA-PSK */
-                               key.type = DOT11_PRIV_TKIP;
-                       if ((index < 0) || (index > 3))
-                               /* no index provided use the current one */
-                               index = current_index;
-
-                       /* now send the key to the card  */
-                       rvalue |=
-                           mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
-                                           &key);
-               }
-               /*
-                * If a valid key is set, encryption should be enabled
-                * (user may turn it off later).
-                * This is also how "iwconfig ethX key on" works
-                */
-               if ((index == current_index) && (key.length > 0))
-                       force = 1;
-       } else {
-               int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1;
-               if ((index >= 0) && (index <= 3)) {
-                       /* we want to set the key index */
-                       rvalue |=
-                           mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
-                                           &index);
-               } else {
-                       if (!(param->u.crypt.flags & IW_ENCODE_MODE)) {
-                               /* we cannot do anything. Complain. */
-                               return -EINVAL;
-                       }
-               }
-       }
-       /* now read the flags */
-       if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
-               /* Encoding disabled,
-                * authen = DOT11_AUTH_OS;
-                * invoke = 0;
-                * exunencrypt = 0; */
-       }
-       if (param->u.crypt.flags & IW_ENCODE_OPEN)
-               /* Encode but accept non-encoded packets. No auth */
-               invoke = 1;
-       if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
-               /* Refuse non-encoded packets. Auth */
-               authen = DOT11_AUTH_BOTH;
-               invoke = 1;
-               exunencrypt = 1;
-       }
-       /* do the change if requested  */
-       if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) {
-               rvalue |=
-                   mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
-               rvalue |=
-                   mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
-               rvalue |=
-                   mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
-                                   &exunencrypt);
-       }
-       return rvalue;
-}
-
-static int
-prism2_ioctl_set_generic_element(struct net_device *ndev,
-       struct prism2_hostapd_param *param,
-       int param_len)
-{
-       islpci_private *priv = netdev_priv(ndev);
-       int max_len, len, alen, ret=0;
-       struct obj_attachment *attach;
-
-       len = param->u.generic_elem.len;
-       max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
-       if (max_len < 0 || max_len < len)
-               return -EINVAL;
-
-       alen = sizeof(*attach) + len;
-       attach = kzalloc(alen, GFP_KERNEL);
-       if (attach == NULL)
-               return -ENOMEM;
-
-#define WLAN_FC_TYPE_MGMT 0
-#define WLAN_FC_STYPE_ASSOC_REQ 0
-#define WLAN_FC_STYPE_REASSOC_REQ 2
-
-       /* Note: endianness is covered by mgt_set_varlen */
-
-       attach->type = (WLAN_FC_TYPE_MGMT << 2) |
-               (WLAN_FC_STYPE_ASSOC_REQ << 4);
-       attach->id = -1;
-       attach->size = len;
-       memcpy(attach->data, param->u.generic_elem.data, len);
-
-       ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
-
-       if (ret == 0) {
-               attach->type = (WLAN_FC_TYPE_MGMT << 2) |
-                       (WLAN_FC_STYPE_REASSOC_REQ << 4);
-
-              ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
-
-              if (ret == 0)
-                      printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
-                                      ndev->name);
-       }
-
-       kfree(attach);
-       return ret;
-
-}
-
-static int
-prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
-{
-       return -EOPNOTSUPP;
-}
-
-static int
-prism2_ioctl_scan_req(struct net_device *ndev,
-                     struct prism2_hostapd_param *param)
-{
-       islpci_private *priv = netdev_priv(ndev);
-       struct iw_request_info info;
-       int i, rvalue;
-       struct obj_bsslist *bsslist;
-       u32 noise = 0;
-       char *extra = "";
-       char *current_ev = "foo";
-       union oid_res_t r;
-
-       if (islpci_get_state(priv) < PRV_STATE_INIT) {
-               /* device is not ready, fail gently */
-               return 0;
-       }
-
-       /* first get the noise value. We will use it to report the link quality */
-       rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
-       noise = r.u;
-
-       /* Ask the device for a list of known bss. We can report at most
-        * IW_MAX_AP=64 to the range struct. But the device won't repport anything
-        * if you change the value of IWMAX_BSS=24.
-        */
-       rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
-       bsslist = r.ptr;
-
-       info.cmd = PRISM54_HOSTAPD;
-       info.flags = 0;
-
-       /* ok now, scan the list and translate its info */
-       for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
-               current_ev = prism54_translate_bss(ndev, &info, current_ev,
-                                                  extra + IW_SCAN_MAX_DATA,
-                                                  &(bsslist->bsslist[i]),
-                                                  noise);
-       kfree(bsslist);
-
-       return rvalue;
-}
-
-static int
-prism54_hostapd(struct net_device *ndev, struct iw_point *p)
-{
-       struct prism2_hostapd_param *param;
-       int ret = 0;
-       u32 uwrq;
-
-       printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
-       if (p->length < sizeof(struct prism2_hostapd_param) ||
-           p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
-               return -EINVAL;
-
-       param = memdup_user(p->pointer, p->length);
-       if (IS_ERR(param))
-               return PTR_ERR(param);
-
-       switch (param->cmd) {
-       case PRISM2_SET_ENCRYPTION:
-              printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
-                              ndev->name);
-               ret = prism2_ioctl_set_encryption(ndev, param, p->length);
-               break;
-       case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
-              printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
-                              ndev->name);
-               ret = prism2_ioctl_set_generic_element(ndev, param,
-                                                      p->length);
-               break;
-       case PRISM2_HOSTAPD_MLME:
-              printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
-                              ndev->name);
-               ret = prism2_ioctl_mlme(ndev, param);
-               break;
-       case PRISM2_HOSTAPD_SCAN_REQ:
-              printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
-                              ndev->name);
-               ret = prism2_ioctl_scan_req(ndev, param);
-               break;
-       case PRISM54_SET_WPA:
-              printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
-                              ndev->name);
-              uwrq = 1;
-              ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
-              break;
-       case PRISM54_DROP_UNENCRYPTED:
-              printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
-                              ndev->name);
-#if 0
-              uwrq = 0x01;
-              mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
-              down_write(&priv->mib_sem);
-              mgt_commit(priv);
-              up_write(&priv->mib_sem);
-#endif
-              /* Not necessary, as set_wpa does it, should we just do it here though? */
-              ret = 0;
-              break;
-       default:
-              printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
-                              ndev->name);
-               ret = -EOPNOTSUPP;
-               break;
-       }
-
-       if (ret == 0 && copy_to_user(p->pointer, param, p->length))
-               ret = -EFAULT;
-
-       kfree(param);
-
-       return ret;
-}
 
 static int
 prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
@@ -3223,20 +2907,3 @@ const struct iw_handler_def prism54_handler_def = {
        .private_args = (struct iw_priv_args *) prism54_private_args,
        .get_wireless_stats = prism54_get_wireless_stats,
 };
-
-/* For wpa_supplicant */
-
-int
-prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
-{
-       struct iwreq *wrq = (struct iwreq *) rq;
-       int ret = -1;
-       switch (cmd) {
-               case PRISM54_HOSTAPD:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               ret = prism54_hostapd(ndev, &wrq->u.data);
-               return ret;
-       }
-       return -EOPNOTSUPP;
-}
index bcfbfb9..a34bceb 100644 (file)
@@ -43,8 +43,6 @@ void prism54_wpa_bss_ie_clean(islpci_private *priv);
 
 int prism54_set_mac_address(struct net_device *, void *);
 
-int prism54_ioctl(struct net_device *, struct ifreq *, int);
-
 extern const struct iw_handler_def prism54_handler_def;
 
 #endif                         /* _ISL_IOCTL_H */
index 8a3cf4f..5970ff6 100644 (file)
@@ -804,7 +804,6 @@ static const struct ethtool_ops islpci_ethtool_ops = {
 static const struct net_device_ops islpci_netdev_ops = {
        .ndo_open               = islpci_open,
        .ndo_stop               = islpci_close,
-       .ndo_do_ioctl           = prism54_ioctl,
        .ndo_start_xmit         = islpci_eth_transmit,
        .ndo_tx_timeout         = islpci_eth_tx_timeout,
        .ndo_set_mac_address    = prism54_set_mac_address,
index 3f183a1..25dab29 100644 (file)
@@ -1203,8 +1203,10 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
                           !(filter_flags & FIF_CONTROL));
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
                           !(filter_flags & FIF_PSPOLL));
-       rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 1);
-       rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 0);
+       rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA,
+                          !(filter_flags & FIF_CONTROL));
+       rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR,
+                          !(filter_flags & FIF_CONTROL));
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
                           !(filter_flags & FIF_CONTROL));
        rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg);
index b6683a2..91f0525 100644 (file)
@@ -780,6 +780,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
        unsigned long flags;
        u32 inta = 0;
        u32 intb = 0;
+       irqreturn_t ret = IRQ_HANDLED;
 
        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 
@@ -787,8 +788,10 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
        rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb);
 
        /*Shared IRQ or HW disappared */
-       if (!inta || inta == 0xffff)
+       if (!inta || inta == 0xffff) {
+               ret = IRQ_NONE;
                goto done;
+       }
 
        /*<1> beacon related */
        if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) {
@@ -892,7 +895,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
 
 done:
        spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-       return IRQ_HANDLED;
+       return ret;
 }
 
 static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
index eaa5f95..6248c35 100644 (file)
@@ -319,7 +319,6 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi)
 static struct spi_driver wl1251_spi_driver = {
        .driver = {
                .name           = DRIVER_NAME,
-               .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
 
index 0f97186..12421a6 100644 (file)
@@ -462,7 +462,6 @@ static int __devexit wl1271_remove(struct spi_device *spi)
 static struct spi_driver wl1271_spi_driver = {
        .driver = {
                .name           = "wl1271_spi",
-               .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
 
index 7bcb1fe..dbf214e 100644 (file)
@@ -1339,7 +1339,7 @@ error:
        return 0;
 }
 
-int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
+static int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
                                                struct sk_buff *skb,
                                                data_exchange_cb_t cb,
                                                void *cb_context)
index 97bfebf..f51e3bf 100644 (file)
  *     OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
  *     messages. Note that per PHY only one application may register.
  *
+ * @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
+ *      No Acknowledgement Policy should be applied.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -675,6 +678,8 @@ enum nl80211_commands {
 
        NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
 
+       NL80211_CMD_SET_NOACK_MAP,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1185,6 +1190,9 @@ enum nl80211_commands {
  *    abides to when initiating radiation on DFS channels. A country maps
  *    to one DFS region.
  *
+ * @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of
+ *      up to 16 TIDs.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1428,6 +1436,8 @@ enum nl80211_attrs {
        NL80211_ATTR_DISABLE_HT,
        NL80211_ATTR_HT_CAPABILITY_MASK,
 
+       NL80211_ATTR_NOACK_MAP,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2084,6 +2094,10 @@ enum nl80211_mntr_flags {
  * access to a broader network beyond the MBSS.  This is done via Root
  * Announcement frames.
  *
+ * @NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in
+ * TUs) during which a mesh STA can send only one Action frame containing a
+ * PERR element.
+ *
  * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
  *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -2107,6 +2121,7 @@ enum nl80211_meshconf_params {
        NL80211_MESHCONF_ELEMENT_TTL,
        NL80211_MESHCONF_HWMP_RANN_INTERVAL,
        NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+       NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
 
        /* keep last */
        __NL80211_MESHCONF_ATTR_AFTER_LAST,
index d5e1891..f0e82b2 100644 (file)
@@ -782,6 +782,7 @@ struct mesh_config {
        u16 min_discovery_timeout;
        u32 dot11MeshHWMPactivePathTimeout;
        u16 dot11MeshHWMPpreqMinInterval;
+       u16 dot11MeshHWMPperrMinInterval;
        u16 dot11MeshHWMPnetDiameterTraversalTime;
        u8  dot11MeshHWMPRootMode;
        u16 dot11MeshHWMPRannInterval;
@@ -802,6 +803,7 @@ struct mesh_config {
  * @ie_len: length of vendor information elements
  * @is_authenticated: this mesh requires authentication
  * @is_secure: this mesh uses security
+ * @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
  *
  * These parameters are fixed when the mesh is created.
  */
@@ -814,6 +816,7 @@ struct mesh_setup {
        u8 ie_len;
        bool is_authenticated;
        bool is_secure;
+       int mcast_rate[IEEE80211_NUM_BANDS];
 };
 
 /**
@@ -1399,7 +1402,8 @@ struct cfg80211_gtk_rekey_data {
  *     have changed. The actual parameter values are available in
  *     struct wiphy. If returning an error, no value should be changed.
  *
- * @set_tx_power: set the transmit power according to the parameters
+ * @set_tx_power: set the transmit power according to the parameters,
+ *     the power passed is in mBm, to get dBm use MBM_TO_DBM().
  * @get_tx_power: store the current TX power into the dbm variable;
  *     return 0 if successful
  *
@@ -1465,6 +1469,8 @@ struct cfg80211_gtk_rekey_data {
  *
  * @probe_client: probe an associated client, must return a cookie that it
  *     later passes to cfg80211_probe_status().
+ *
+ * @set_noack_map: Set the NoAck Map for the TIDs.
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1658,6 +1664,10 @@ struct cfg80211_ops {
        int     (*probe_client)(struct wiphy *wiphy, struct net_device *dev,
                                const u8 *peer, u64 *cookie);
 
+       int     (*set_noack_map)(struct wiphy *wiphy,
+                                 struct net_device *dev,
+                                 u16 noack_map);
+
        struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
 };
 
index 7d3b438..96ddb72 100644 (file)
@@ -247,15 +247,3 @@ config MAC80211_DEBUG_COUNTERS
          and show them in debugfs.
 
          If unsure, say N.
-
-config MAC80211_DRIVER_API_TRACER
-       bool "Driver API tracer"
-       depends on MAC80211_DEBUG_MENU
-       depends on EVENT_TRACING
-       help
-         Say Y here to make mac80211 register with the ftrace
-         framework for the driver API -- you can then see which
-         driver methods it is calling and which API functions
-         drivers are calling by looking at the trace.
-
-         If unsure, say Y.
index fdb54e6..d540c3b 100644 (file)
@@ -24,7 +24,8 @@ mac80211-y := \
        util.o \
        wme.o \
        event.o \
-       chan.o
+       chan.o \
+       driver-trace.o
 
 mac80211-$(CONFIG_MAC80211_LEDS) += led.o
 mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
@@ -41,7 +42,6 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
 
 mac80211-$(CONFIG_PM) += pm.o
 
-mac80211-$(CONFIG_MAC80211_DRIVER_API_TRACER) += driver-trace.o
 CFLAGS_driver-trace.o := -I$(src)
 
 # objects for PID algorithm
index 476b106..e844e5a 100644 (file)
@@ -73,8 +73,11 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
        RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
-              sta->sta.addr, tid);
+       printk(KERN_DEBUG
+              "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
+              sta->sta.addr, tid,
+              initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
+              (int)reason);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
        if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
@@ -85,7 +88,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
        /* check if this is a self generated aggregation halt */
        if (initiator == WLAN_BACK_RECIPIENT && tx)
                ieee80211_send_delba(sta->sdata, sta->sta.addr,
-                                    tid, 0, reason);
+                                    tid, WLAN_BACK_RECIPIENT, reason);
 
        del_timer_sync(&tid_rx->session_timer);
        del_timer_sync(&tid_rx->reorder_timer);
@@ -109,7 +112,7 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
        int i;
 
        rcu_read_lock();
-       sta = sta_info_get(sdata, addr);
+       sta = sta_info_get_bss(sdata, addr);
        if (!sta) {
                rcu_read_unlock();
                return;
index 39d72cc..266cc87 100644 (file)
@@ -180,6 +180,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
        set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
 
        del_timer_sync(&tid_tx->addba_resp_timer);
+       del_timer_sync(&tid_tx->session_timer);
 
        /*
         * After this packets are no longer handed right through
@@ -349,6 +350,28 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
                                     tid_tx->timeout);
 }
 
+/*
+ * After accepting the AddBA Response we activated a timer,
+ * resetting it after each frame that we send.
+ */
+static void sta_tx_agg_session_timer_expired(unsigned long data)
+{
+       /* not an elegant detour, but there is no choice as the timer passes
+        * only one argument, and various sta_info are needed here, so init
+        * flow in sta_info_create gives the TID as data, while the timer_to_id
+        * array gives the sta through container_of */
+       u8 *ptid = (u8 *)data;
+       u8 *timer_to_id = ptid - *ptid;
+       struct sta_info *sta = container_of(timer_to_id, struct sta_info,
+                                        timer_to_tid[0]);
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+       printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
+#endif
+
+       ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
+}
+
 int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
                                  u16 timeout)
 {
@@ -418,11 +441,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
 
        tid_tx->timeout = timeout;
 
-       /* Tx timer */
+       /* response timer */
        tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
        tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
        init_timer(&tid_tx->addba_resp_timer);
 
+       /* tx timer */
+       tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
+       tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
+       init_timer(&tid_tx->session_timer);
+
        /* assign a dialog token */
        sta->ampdu_mlme.dialog_token_allocator++;
        tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
@@ -527,7 +555,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        }
 
        mutex_lock(&local->sta_mtx);
-       sta = sta_info_get(sdata, ra);
+       sta = sta_info_get_bss(sdata, ra);
        if (!sta) {
                mutex_unlock(&local->sta_mtx);
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -656,7 +684,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 
        mutex_lock(&local->sta_mtx);
 
-       sta = sta_info_get(sdata, ra);
+       sta = sta_info_get_bss(sdata, ra);
        if (!sta) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Could not find station: %pM\n", ra);
@@ -778,6 +806,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
                        ieee80211_agg_tx_operational(local, sta, tid);
 
                sta->ampdu_mlme.addba_req_num[tid] = 0;
+
+               if (tid_tx->timeout)
+                       mod_timer(&tid_tx->session_timer,
+                                 TU_TO_EXP_TIME(tid_tx->timeout));
+
        } else {
                ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
                                                true);
index 2577c45..393b2a4 100644 (file)
@@ -102,6 +102,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
        return 0;
 }
 
+static int ieee80211_set_noack_map(struct wiphy *wiphy,
+                                 struct net_device *dev,
+                                 u16 noack_map)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       sdata->noack_map = noack_map;
+       return 0;
+}
+
 static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                             u8 key_idx, bool pairwise, const u8 *mac_addr,
                             struct key_params *params)
@@ -499,7 +509,7 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
        if (!resp || !resp_len)
                return -EINVAL;
 
-       old = sdata->u.ap.probe_resp;
+       old = rtnl_dereference(sdata->u.ap.probe_resp);
 
        new = dev_alloc_skb(resp_len);
        if (!new)
@@ -1185,6 +1195,8 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
 {
        u8 *new_ie;
        const u8 *old_ie;
+       struct ieee80211_sub_if_data *sdata = container_of(ifmsh,
+                                       struct ieee80211_sub_if_data, u.mesh);
 
        /* allocate information elements */
        new_ie = NULL;
@@ -1211,6 +1223,10 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
        if (setup->is_secure)
                ifmsh->security |= IEEE80211_MESH_SEC_SECURED;
 
+       /* mcast rate setting in Mesh Node */
+       memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate,
+                                               sizeof(setup->mcast_rate));
+
        return 0;
 }
 
@@ -1256,6 +1272,9 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
        if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask))
                conf->dot11MeshHWMPpreqMinInterval =
                        nconf->dot11MeshHWMPpreqMinInterval;
+       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, mask))
+               conf->dot11MeshHWMPperrMinInterval =
+                       nconf->dot11MeshHWMPperrMinInterval;
        if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
                           mask))
                conf->dot11MeshHWMPnetDiameterTraversalTime =
@@ -2698,4 +2717,5 @@ struct cfg80211_ops mac80211_config_ops = {
        .tdls_mgmt = ieee80211_tdls_mgmt,
        .probe_client = ieee80211_probe_client,
        .get_channel = ieee80211_wiphy_get_channel,
+       .set_noack_map = ieee80211_set_noack_map,
 };
index 00cefcb..90baea5 100644 (file)
@@ -97,40 +97,6 @@ static const struct file_operations reset_ops = {
        .llseek = noop_llseek,
 };
 
-static ssize_t noack_read(struct file *file, char __user *user_buf,
-                         size_t count, loff_t *ppos)
-{
-       struct ieee80211_local *local = file->private_data;
-
-       return mac80211_format_buffer(user_buf, count, ppos, "%d\n",
-                                     local->wifi_wme_noack_test);
-}
-
-static ssize_t noack_write(struct file *file,
-                          const char __user *user_buf,
-                          size_t count, loff_t *ppos)
-{
-       struct ieee80211_local *local = file->private_data;
-       char buf[10];
-       size_t len;
-
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-       buf[len] = '\0';
-
-       local->wifi_wme_noack_test = !!simple_strtoul(buf, NULL, 0);
-
-       return count;
-}
-
-static const struct file_operations noack_ops = {
-       .read = noack_read,
-       .write = noack_write,
-       .open = mac80211_open_file_generic,
-       .llseek = default_llseek,
-};
-
 static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf,
                                 size_t count, loff_t *ppos)
 {
@@ -398,7 +364,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_ADD(wep_iv);
        DEBUGFS_ADD(queues);
        DEBUGFS_ADD_MODE(reset, 0200);
-       DEBUGFS_ADD(noack);
        DEBUGFS_ADD(uapsd_queues);
        DEBUGFS_ADD(uapsd_max_sp_len);
        DEBUGFS_ADD(channel_type);
index 9352819..8df2891 100644 (file)
@@ -405,6 +405,8 @@ IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
                u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
                u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval,
+               u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
                u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
@@ -534,6 +536,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
        MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
        MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
        MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
+       MESHPARAMS_ADD(dot11MeshHWMPperrMinInterval);
        MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
        MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
        MESHPARAMS_ADD(path_refresh_time);
index 49cc5e0..e8960ae 100644 (file)
@@ -10,6 +10,16 @@ static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
        WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER));
 }
 
+static inline struct ieee80211_sub_if_data *
+get_bss_sdata(struct ieee80211_sub_if_data *sdata)
+{
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
+                                    u.ap);
+
+       return sdata;
+}
+
 static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
 {
        local->ops->tx(&local->hw, skb);
@@ -421,6 +431,7 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
                                  enum sta_notify_cmd cmd,
                                  struct ieee80211_sta *sta)
 {
+       sdata = get_bss_sdata(sdata);
        check_sdata_in_driver(sdata);
 
        trace_drv_sta_notify(local, sdata, cmd, sta);
@@ -437,6 +448,7 @@ static inline int drv_sta_add(struct ieee80211_local *local,
 
        might_sleep();
 
+       sdata = get_bss_sdata(sdata);
        check_sdata_in_driver(sdata);
 
        trace_drv_sta_add(local, sdata, sta);
@@ -454,6 +466,7 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
 {
        might_sleep();
 
+       sdata = get_bss_sdata(sdata);
        check_sdata_in_driver(sdata);
 
        trace_drv_sta_remove(local, sdata, sta);
@@ -547,6 +560,7 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
 
        might_sleep();
 
+       sdata = get_bss_sdata(sdata);
        check_sdata_in_driver(sdata);
 
        trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
index 2af4fca..6e9df8f 100644 (file)
@@ -5,17 +5,6 @@
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 
-#if !defined(CONFIG_MAC80211_DRIVER_API_TRACER) || defined(__CHECKER__)
-#undef TRACE_EVENT
-#define TRACE_EVENT(name, proto, ...) \
-static inline void trace_ ## name(proto) {}
-#undef DECLARE_EVENT_CLASS
-#define DECLARE_EVENT_CLASS(...)
-#undef DEFINE_EVENT
-#define DEFINE_EVENT(evt_class, name, proto, ...) \
-static inline void trace_ ## name(proto) {}
-#endif
-
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM mac80211
 
index 810cfbe..d3eafae 100644 (file)
@@ -28,9 +28,9 @@ bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
        return false;
 }
 
-void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
-                          struct ieee80211_sta_ht_cap *ht_cap,
-                          u16 flag)
+static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
+                                 struct ieee80211_sta_ht_cap *ht_cap,
+                                 u16 flag)
 {
        __le16 le_flag = cpu_to_le16(flag);
        if (sdata->u.mgd.ht_capa_mask.cap_info & le_flag) {
index 762243e..bdefa6b 100644 (file)
@@ -514,7 +514,9 @@ struct ieee80211_if_mesh {
        atomic_t mpaths;
        /* Timestamp of last SN update */
        unsigned long last_sn_update;
-       /* Timestamp of last SN sent */
+       /* Time when it's ok to send next PERR */
+       unsigned long next_perr;
+       /* Timestamp of last PREQ sent */
        unsigned long last_preq;
        struct mesh_rmc *rmc;
        spinlock_t mesh_preq_queue_lock;
@@ -611,6 +613,9 @@ struct ieee80211_sub_if_data {
        struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
        unsigned int fragment_next;
 
+       /* TID bitmap for NoAck policy */
+       u16 noack_map;
+
        struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
        struct ieee80211_key __rcu *default_unicast_key;
        struct ieee80211_key __rcu *default_multicast_key;
@@ -961,7 +966,6 @@ struct ieee80211_local {
        int total_ps_buffered; /* total number of all buffered unicast and
                                * multicast packets for power saving stations
                                */
-       int wifi_wme_noack_test;
        unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
        /*
@@ -1216,13 +1220,11 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sched_scan_stopped_work(struct work_struct *work);
 
 /* off-channel helpers */
-bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local);
 void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
                                        bool tell_ap);
 void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
                                    bool offchannel_ps_enable);
 void ieee80211_offchannel_return(struct ieee80211_local *local,
-                                bool enable_beaconing,
                                 bool offchannel_ps_disable);
 void ieee80211_hw_roc_setup(struct ieee80211_local *local);
 
index b34ca0c..3d3bb5e 100644 (file)
@@ -672,7 +672,6 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_hdr *hdr;
        struct ieee80211_radiotap_header *rtap = (void *)skb->data;
-       u8 *p;
 
        if (local->hw.queues < 4)
                return 0;
@@ -683,19 +682,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
 
        hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len));
 
-       if (!ieee80211_is_data(hdr->frame_control)) {
-               skb->priority = 7;
-               return ieee802_1d_to_ac[skb->priority];
-       }
-       if (!ieee80211_is_data_qos(hdr->frame_control)) {
-               skb->priority = 0;
-               return ieee802_1d_to_ac[skb->priority];
-       }
-
-       p = ieee80211_get_qos_ctl(hdr);
-       skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
-
-       return ieee80211_downgrade_queue(local, skb);
+       return ieee80211_select_queue_80211(local, skb, hdr);
 }
 
 static const struct net_device_ops ieee80211_monitorif_ops = {
@@ -866,6 +853,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
        sdata->control_port_no_encrypt = false;
 
+       sdata->noack_map = 0;
+
        /* only monitor differs */
        sdata->dev->type = ARPHRD_ETHER;
 
index dddedfa..944bed3 100644 (file)
@@ -92,47 +92,6 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
        ieee80211_configure_filter(local);
 }
 
-/*
- * Returns true if we are logically configured to be on
- * the operating channel AND the hardware-conf is currently
- * configured on the operating channel.  Compares channel-type
- * as well.
- */
-bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
-{
-       struct ieee80211_channel *chan;
-       enum nl80211_channel_type channel_type;
-
-       /* This logic needs to match logic in ieee80211_hw_config */
-       if (local->scan_channel) {
-               chan = local->scan_channel;
-               /* If scanning on oper channel, use whatever channel-type
-                * is currently in use.
-                */
-               if (chan == local->oper_channel)
-                       channel_type = local->_oper_channel_type;
-               else
-                       channel_type = NL80211_CHAN_NO_HT;
-       } else if (local->tmp_channel) {
-               chan = local->tmp_channel;
-               channel_type = local->tmp_channel_type;
-       } else {
-               chan = local->oper_channel;
-               channel_type = local->_oper_channel_type;
-       }
-
-       if (chan != local->oper_channel ||
-           channel_type != local->_oper_channel_type)
-               return false;
-
-       /* Check current hardware-config against oper_channel. */
-       if (local->oper_channel != local->hw.conf.channel ||
-           local->_oper_channel_type != local->hw.conf.channel_type)
-               return false;
-
-       return true;
-}
-
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
        struct ieee80211_channel *chan;
index ee82d2f..c707c8b 100644 (file)
@@ -749,6 +749,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
        atomic_set(&ifmsh->mpaths, 0);
        mesh_rmc_init(sdata);
        ifmsh->last_preq = jiffies;
+       ifmsh->next_perr = jiffies;
        /* Allocate all mesh structures when creating the first mesh interface. */
        if (!mesh_allocated)
                ieee80211s_init();
index 622cc96..bd14bd2 100644 (file)
@@ -233,6 +233,8 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
 /* Mesh paths */
 int mesh_nexthop_lookup(struct sk_buff *skb,
                struct ieee80211_sub_if_data *sdata);
+int mesh_nexthop_resolve(struct sk_buff *skb,
+                        struct ieee80211_sub_if_data *sdata);
 void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
 struct mesh_path *mesh_path_lookup(u8 *dst,
                struct ieee80211_sub_if_data *sdata);
index ce3db27..73abb75 100644 (file)
@@ -241,11 +241,15 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
 {
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
+       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct ieee80211_mgmt *mgmt;
        u8 *pos, ie_len;
        int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
                      sizeof(mgmt->u.action.u.mesh_action);
 
+       if (time_before(jiffies, ifmsh->next_perr))
+               return -EAGAIN;
+
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
                            hdr_len +
                            2 + 15 /* PERR IE */);
@@ -290,6 +294,8 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
 
        /* see note in function header */
        prepare_frame_for_deferred_tx(sdata, skb);
+       ifmsh->next_perr = TU_TO_EXP_TIME(
+                                  ifmsh->mshcfg.dot11MeshHWMPperrMinInterval);
        ieee80211_add_pending_skb(local, skb);
        return 0;
 }
@@ -393,15 +399,13 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
                orig_metric = PREQ_IE_METRIC(hwmp_ie);
                break;
        case MPATH_PREP:
-               /* Originator here refers to the MP that was the destination in
-                * the Path Request. The draft refers to that MP as the
-                * destination address, even though usually it is the origin of
-                * the PREP frame. We divert from the nomenclature in the draft
+               /* Originator here refers to the MP that was the target in the
+                * Path Request. We divert from the nomenclature in the draft
                 * so that we can easily use a single function to gather path
                 * information from both PREQ and PREP frames.
                 */
-               orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie);
-               orig_sn = PREP_IE_ORIG_SN(hwmp_ie);
+               orig_addr = PREP_IE_TARGET_ADDR(hwmp_ie);
+               orig_sn = PREP_IE_TARGET_SN(hwmp_ie);
                orig_lifetime = PREP_IE_LIFETIME(hwmp_ie);
                orig_metric = PREP_IE_METRIC(hwmp_ie);
                break;
@@ -562,9 +566,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                ttl = ifmsh->mshcfg.element_ttl;
                if (ttl != 0) {
                        mhwmp_dbg("replying to the PREQ");
-                       mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr,
-                               cpu_to_le32(target_sn), 0, orig_addr,
-                               cpu_to_le32(orig_sn), mgmt->sa, 0, ttl,
+                       mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr,
+                               cpu_to_le32(orig_sn), 0, target_addr,
+                               cpu_to_le32(target_sn), mgmt->sa, 0, ttl,
                                cpu_to_le32(lifetime), cpu_to_le32(metric),
                                0, sdata);
                } else
@@ -618,14 +622,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
 
        mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));
 
-       /* Note that we divert from the draft nomenclature and denominate
-        * destination to what the draft refers to as origininator. So in this
-        * function destnation refers to the final destination of the PREP,
-        * which corresponds with the originator of the PREQ which this PREP
-        * replies
-        */
-       target_addr = PREP_IE_TARGET_ADDR(prep_elem);
-       if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0)
+       orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
+       if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0)
                /* destination, no forwarding required */
                return;
 
@@ -636,7 +634,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
        }
 
        rcu_read_lock();
-       mpath = mesh_path_lookup(target_addr, sdata);
+       mpath = mesh_path_lookup(orig_addr, sdata);
        if (mpath)
                spin_lock_bh(&mpath->state_lock);
        else
@@ -651,7 +649,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
        flags = PREP_IE_FLAGS(prep_elem);
        lifetime = PREP_IE_LIFETIME(prep_elem);
        hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1;
-       orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
+       target_addr = PREP_IE_TARGET_ADDR(prep_elem);
        target_sn = PREP_IE_TARGET_SN(prep_elem);
        orig_sn = PREP_IE_ORIG_SN(prep_elem);
 
@@ -984,71 +982,97 @@ enddiscovery:
        kfree(preq_node);
 }
 
-/**
- * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame
+/* mesh_nexthop_resolve - lookup next hop for given skb and start path
+ * discovery if no forwarding information is found.
  *
  * @skb: 802.11 frame to be sent
  * @sdata: network subif the frame will be sent through
  *
- * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
- * found, the function will start a path discovery and queue the frame so it is
- * sent when the path is resolved. This means the caller must not free the skb
- * in this case.
+ * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
+ * skb is freeed here if no mpath could be allocated.
  */
-int mesh_nexthop_lookup(struct sk_buff *skb,
-                       struct ieee80211_sub_if_data *sdata)
+int mesh_nexthop_resolve(struct sk_buff *skb,
+                        struct ieee80211_sub_if_data *sdata)
 {
-       struct sk_buff *skb_to_free = NULL;
-       struct mesh_path *mpath;
-       struct sta_info *next_hop;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct mesh_path *mpath;
+       struct sk_buff *skb_to_free = NULL;
        u8 *target_addr = hdr->addr3;
        int err = 0;
 
        rcu_read_lock();
-       mpath = mesh_path_lookup(target_addr, sdata);
+       err = mesh_nexthop_lookup(skb, sdata);
+       if (!err)
+               goto endlookup;
 
+       /* no nexthop found, start resolving */
+       mpath = mesh_path_lookup(target_addr, sdata);
        if (!mpath) {
                mesh_path_add(target_addr, sdata);
                mpath = mesh_path_lookup(target_addr, sdata);
                if (!mpath) {
-                       sdata->u.mesh.mshstats.dropped_frames_no_route++;
+                       mesh_path_discard_frame(skb, sdata);
                        err = -ENOSPC;
                        goto endlookup;
                }
        }
 
-       if (mpath->flags & MESH_PATH_ACTIVE) {
-               if (time_after(jiffies,
-                              mpath->exp_time -
-                              msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
-                   !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
-                   !(mpath->flags & MESH_PATH_RESOLVING) &&
-                   !(mpath->flags & MESH_PATH_FIXED)) {
-                       mesh_queue_preq(mpath,
-                                       PREQ_Q_F_START | PREQ_Q_F_REFRESH);
-               }
-               next_hop = rcu_dereference(mpath->next_hop);
-               if (next_hop)
-                       memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
-               else
-                       err = -ENOENT;
-       } else {
-               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-               if (!(mpath->flags & MESH_PATH_RESOLVING)) {
-                       /* Start discovery only if it is not running yet */
-                       mesh_queue_preq(mpath, PREQ_Q_F_START);
-               }
+       if (!(mpath->flags & MESH_PATH_RESOLVING))
+               mesh_queue_preq(mpath, PREQ_Q_F_START);
+
+       if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
+               skb_to_free = skb_dequeue(&mpath->frame_queue);
 
-               if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
-                       skb_to_free = skb_dequeue(&mpath->frame_queue);
+       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+       ieee80211_set_qos_hdr(sdata, skb);
+       skb_queue_tail(&mpath->frame_queue, skb);
+       err = -ENOENT;
+       if (skb_to_free)
+               mesh_path_discard_frame(skb_to_free, sdata);
+
+endlookup:
+       rcu_read_unlock();
+       return err;
+}
+/**
+ * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling
+ * this function is considered "using" the associated mpath, so preempt a path
+ * refresh if this mpath expires soon.
+ *
+ * @skb: 802.11 frame to be sent
+ * @sdata: network subif the frame will be sent through
+ *
+ * Returns: 0 if the next hop was found. Nonzero otherwise.
+ */
+int mesh_nexthop_lookup(struct sk_buff *skb,
+                       struct ieee80211_sub_if_data *sdata)
+{
+       struct mesh_path *mpath;
+       struct sta_info *next_hop;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *target_addr = hdr->addr3;
+       int err = -ENOENT;
+
+       rcu_read_lock();
+       mpath = mesh_path_lookup(target_addr, sdata);
+
+       if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
+               goto endlookup;
+
+       if (time_after(jiffies,
+                      mpath->exp_time -
+                      msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
+           !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
+           !(mpath->flags & MESH_PATH_RESOLVING) &&
+           !(mpath->flags & MESH_PATH_FIXED))
+               mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
 
-               info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
-               ieee80211_set_qos_hdr(sdata, skb);
-               skb_queue_tail(&mpath->frame_queue, skb);
-               if (skb_to_free)
-                       mesh_path_discard_frame(skb_to_free, sdata);
-               err = -ENOENT;
+       next_hop = rcu_dereference(mpath->next_hop);
+       if (next_hop) {
+               memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
+               memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
+               err = 0;
        }
 
 endlookup:
index 7bd2a76..edf167e 100644 (file)
@@ -221,6 +221,7 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
        while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
                hdr = (struct ieee80211_hdr *) skb->data;
                memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
+               memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN);
                __skb_queue_tail(&tmpq, skb);
        }
 
@@ -264,6 +265,7 @@ static void prepare_for_gate(struct sk_buff *skb, char *dst_addr,
        next_hop = rcu_dereference(gate_mpath->next_hop)->sta.addr;
        memcpy(hdr->addr1, next_hop, ETH_ALEN);
        rcu_read_unlock();
+       memcpy(hdr->addr2, gate_mpath->sdata->vif.addr, ETH_ALEN);
        memcpy(hdr->addr3, dst_addr, ETH_ALEN);
 }
 
@@ -971,38 +973,11 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
  * @skb: frame to discard
  * @sdata: network subif the frame was to be sent through
  *
- * If the frame was being forwarded from another MP, a PERR frame will be sent
- * to the precursor.  The precursor's address (i.e. the previous hop) was saved
- * in addr1 of the frame-to-be-forwarded, and would only be overwritten once
- * the destination is successfully resolved.
- *
  * Locking: the function must me called within a rcu_read_lock region
  */
 void mesh_path_discard_frame(struct sk_buff *skb,
                             struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct mesh_path *mpath;
-       u32 sn = 0;
-       __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
-
-       if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
-               u8 *ra, *da;
-
-               da = hdr->addr3;
-               ra = hdr->addr1;
-               rcu_read_lock();
-               mpath = mesh_path_lookup(da, sdata);
-               if (mpath) {
-                       spin_lock_bh(&mpath->state_lock);
-                       sn = ++mpath->sn;
-                       spin_unlock_bh(&mpath->state_lock);
-               }
-               rcu_read_unlock();
-               mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data,
-                                  cpu_to_le32(sn), reason, ra, sdata);
-       }
-
        kfree_skb(skb);
        sdata->u.mesh.mshstats.dropped_frames_no_route++;
 }
index ebd8ccc..e4330d8 100644 (file)
@@ -156,7 +156,6 @@ void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
 }
 
 void ieee80211_offchannel_return(struct ieee80211_local *local,
-                                bool enable_beaconing,
                                 bool offchannel_ps_disable)
 {
        struct ieee80211_sub_if_data *sdata;
@@ -188,11 +187,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
                        netif_tx_wake_all_queues(sdata->dev);
                }
 
-               /* Check to see if we should re-enable beaconing */
-               if (enable_beaconing &&
-                   (sdata->vif.type == NL80211_IFTYPE_AP ||
-                    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
-                    sdata->vif.type == NL80211_IFTYPE_MESH_POINT))
+               if (sdata->vif.type == NL80211_IFTYPE_AP ||
+                   sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+                   sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                        ieee80211_bss_info_change_notify(
                                sdata, BSS_CHANGED_BEACON_ENABLED);
        }
index 4eafbfd..1e231e9 100644 (file)
@@ -1892,13 +1892,16 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result
 ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_hdr *hdr;
+       struct ieee80211_hdr *fwd_hdr, *hdr;
+       struct ieee80211_tx_info *info;
        struct ieee80211s_hdr *mesh_hdr;
-       unsigned int hdrlen;
        struct sk_buff *skb = rx->skb, *fwd_skb;
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+       __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
+       u16 q, hdrlen;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -1914,14 +1917,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                return RX_CONTINUE;
 
        if (!mesh_hdr->ttl)
-               /* illegal frame */
-               return RX_DROP_MONITOR;
-
-       if (ieee80211_queue_stopped(&local->hw, skb_get_queue_mapping(skb))) {
-               IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
-                                               dropped_frames_congestion);
                return RX_DROP_MONITOR;
-       }
 
        if (mesh_hdr->flags & MESH_FLAGS_AE) {
                struct mesh_path *mppath;
@@ -1954,59 +1950,50 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
-       skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
-       mesh_hdr->ttl--;
+       q = ieee80211_select_queue_80211(local, skb, hdr);
+       if (ieee80211_queue_stopped(&local->hw, q)) {
+               IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
+               return RX_DROP_MONITOR;
+       }
+       skb_set_queue_mapping(skb, q);
 
-       if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
-               if (!mesh_hdr->ttl)
-                       IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
-                                                    dropped_frames_ttl);
-               else {
-                       struct ieee80211_hdr *fwd_hdr;
-                       struct ieee80211_tx_info *info;
-
-                       fwd_skb = skb_copy(skb, GFP_ATOMIC);
-
-                       if (!fwd_skb && net_ratelimit())
-                               printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
-                                                  sdata->name);
-                       if (!fwd_skb)
-                               goto out;
-
-                       fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
-                       memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
-                       info = IEEE80211_SKB_CB(fwd_skb);
-                       memset(info, 0, sizeof(*info));
-                       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
-                       info->control.vif = &rx->sdata->vif;
-                       info->control.jiffies = jiffies;
-                       if (is_multicast_ether_addr(fwd_hdr->addr1)) {
-                               IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
-                                                               fwded_mcast);
-                       } else {
-                               int err;
-                               /*
-                                * Save TA to addr1 to send TA a path error if a
-                                * suitable next hop is not found
-                                */
-                               memcpy(fwd_hdr->addr1, fwd_hdr->addr2,
-                                               ETH_ALEN);
-                               err = mesh_nexthop_lookup(fwd_skb, sdata);
-                               /* Failed to immediately resolve next hop:
-                                * fwded frame was dropped or will be added
-                                * later to the pending skb queue.  */
-                               if (err)
-                                       return RX_DROP_MONITOR;
-
-                               IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
-                                                               fwded_unicast);
-                       }
-                       IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
-                                                    fwded_frames);
-                       ieee80211_add_pending_skb(local, fwd_skb);
-               }
+       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
+               goto out;
+
+       if (!--mesh_hdr->ttl) {
+               IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
+               return RX_DROP_MONITOR;
+       }
+
+       fwd_skb = skb_copy(skb, GFP_ATOMIC);
+       if (!fwd_skb) {
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
+                                       sdata->name);
+               goto out;
+       }
+
+       fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
+       info = IEEE80211_SKB_CB(fwd_skb);
+       memset(info, 0, sizeof(*info));
+       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+       info->control.vif = &rx->sdata->vif;
+       info->control.jiffies = jiffies;
+       if (is_multicast_ether_addr(fwd_hdr->addr1)) {
+               IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
+               memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
+       } else if (!mesh_nexthop_lookup(fwd_skb, sdata)) {
+               IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
+       } else {
+               /* unable to resolve next hop */
+               mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3,
+                                   0, reason, fwd_hdr->addr2, sdata);
+               IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
+               return RX_DROP_MONITOR;
        }
 
+       IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
+       ieee80211_add_pending_skb(local, fwd_skb);
  out:
        if (is_multicast_ether_addr(hdr->addr1) ||
            sdata->dev->flags & IFF_PROMISC)
index 8186303..2c5041c 100644 (file)
@@ -297,7 +297,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        if (!was_hw_scan) {
                ieee80211_configure_filter(local);
                drv_sw_scan_complete(local);
-               ieee80211_offchannel_return(local, true, true);
+               ieee80211_offchannel_return(local, true);
        }
 
        ieee80211_recalc_idle(local);
@@ -602,7 +602,7 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
         * in off-channel state..will put that back
         * on-channel at the end of scanning.
         */
-       ieee80211_offchannel_return(local, true, false);
+       ieee80211_offchannel_return(local, false);
 
        *next_delay = HZ / 5;
        /* afterwards, resume scan & go to next channel */
index 8eaa746..f982352 100644 (file)
@@ -351,10 +351,6 @@ static int sta_info_finish_insert(struct sta_info *sta,
 
        if (!sta->dummy || dummy_reinsert) {
                /* notify driver */
-               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-                       sdata = container_of(sdata->bss,
-                                            struct ieee80211_sub_if_data,
-                                            u.ap);
                err = drv_sta_add(local, sdata, &sta->sta);
                if (err) {
                        if (!async)
index 6280e8b..1a14fab 100644 (file)
@@ -88,6 +88,7 @@ enum ieee80211_sta_info_flags {
  * struct tid_ampdu_tx - TID aggregation information (Tx).
  *
  * @rcu_head: rcu head for freeing structure
+ * @session_timer: check if we keep Tx-ing on the TID (by timeout value)
  * @addba_resp_timer: timer for peer's response to addba request
  * @pending: pending frames queue -- use sta's spinlock to protect
  * @dialog_token: dialog token for aggregation session
@@ -110,6 +111,7 @@ enum ieee80211_sta_info_flags {
  */
 struct tid_ampdu_tx {
        struct rcu_head rcu_head;
+       struct timer_list session_timer;
        struct timer_list addba_resp_timer;
        struct sk_buff_head pending;
        unsigned long state;
@@ -497,7 +499,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
  */
 int sta_info_insert(struct sta_info *sta);
 int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU);
-int sta_info_insert_atomic(struct sta_info *sta);
 int sta_info_reinsert(struct sta_info *sta);
 
 int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
index 8d31933..c4cb4a5 100644 (file)
@@ -151,11 +151,15 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
                rate = mrate;
        }
 
-       /* Time needed to transmit ACK
-        * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
-        * to closest integer */
-
-       dur = ieee80211_frame_duration(local, 10, rate, erp,
+       /* Don't calculate ACKs for QoS Frames with NoAck Policy set */
+       if (ieee80211_is_data_qos(hdr->frame_control) &&
+           *(ieee80211_get_qos_ctl(hdr)) | IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
+               dur = 0;
+       else
+               /* Time needed to transmit ACK
+                * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
+                * to closest integer */
+               dur = ieee80211_frame_duration(local, 10, rate, erp,
                                tx->sdata->vif.bss_conf.use_short_preamble);
 
        if (next_frag_len) {
@@ -636,6 +640,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
        else
                txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
        txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
+                   tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
                    tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
 
        /* set up RTS protection if desired */
@@ -1063,9 +1068,11 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
                                  int tid)
 {
        bool queued = false;
+       bool reset_agg_timer = false;
 
        if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
                info->flags |= IEEE80211_TX_CTL_AMPDU;
+               reset_agg_timer = true;
        } else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
                /*
                 * nothing -- this aggregation session is being started
@@ -1097,6 +1104,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
                        /* do nothing, let packet pass through */
                } else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
                        info->flags |= IEEE80211_TX_CTL_AMPDU;
+                       reset_agg_timer = true;
                } else {
                        queued = true;
                        info->control.vif = &tx->sdata->vif;
@@ -1106,6 +1114,11 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
                spin_unlock(&tx->sta->lock);
        }
 
+       /* reset session timer */
+       if (reset_agg_timer && tid_tx->timeout)
+               mod_timer(&tid_tx->session_timer,
+                         TU_TO_EXP_TIME(tid_tx->timeout));
+
        return queued;
 }
 
@@ -1173,16 +1186,8 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
        if (is_multicast_ether_addr(hdr->addr1)) {
                tx->flags &= ~IEEE80211_TX_UNICAST;
                info->flags |= IEEE80211_TX_CTL_NO_ACK;
-       } else {
+       } else
                tx->flags |= IEEE80211_TX_UNICAST;
-               if (unlikely(local->wifi_wme_noack_test))
-                       info->flags |= IEEE80211_TX_CTL_NO_ACK;
-               /*
-                * Flags are initialized to 0. Hence, no need to
-                * explicitly unset IEEE80211_TX_CTL_NO_ACK since
-                * it might already be set for injected frames.
-                */
-       }
 
        if (!(info->flags & IEEE80211_TX_CTL_DONTFRAG)) {
                if (!(tx->flags & IEEE80211_TX_UNICAST) ||
@@ -1223,9 +1228,10 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
                         * queue is woken again.
                         */
                        if (txpending)
-                               skb_queue_splice(skbs, &local->pending[q]);
+                               skb_queue_splice_init(skbs, &local->pending[q]);
                        else
-                               skb_queue_splice_tail(skbs, &local->pending[q]);
+                               skb_queue_splice_tail_init(skbs,
+                                                          &local->pending[q]);
 
                        spin_unlock_irqrestore(&local->queue_stop_reason_lock,
                                               flags);
@@ -1297,7 +1303,7 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
        ieee80211_tpt_led_trig_tx(local, fc, led_len);
        ieee80211_led_tx(local, 1);
 
-       WARN_ON(!skb_queue_empty(skbs));
+       WARN_ON_ONCE(!skb_queue_empty(skbs));
 
        return result;
 }
@@ -1458,7 +1464,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        if (ieee80211_vif_is_mesh(&sdata->vif) &&
            ieee80211_is_data(hdr->frame_control) &&
                !is_multicast_ether_addr(hdr->addr1))
-                       if (mesh_nexthop_lookup(skb, sdata)) {
+                       if (mesh_nexthop_resolve(skb, sdata)) {
                                /* skb queued: don't free */
                                rcu_read_unlock();
                                return;
@@ -2260,10 +2266,10 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
                /* Bitmap control */
                *pos++ = n1 | aid0;
                /* Part Virt Bitmap */
+               skb_put(skb, n2 - n1);
                memcpy(pos, bss->tim + n1, n2 - n1 + 1);
 
                tim[1] = n2 - n1 + 4;
-               skb_put(skb, n2 - n1);
        } else {
                *pos++ = aid0; /* Bitmap control */
                *pos++ = 0; /* Part Virt Bitmap */
index c499a16..5f7c1c6 100644 (file)
@@ -1240,8 +1240,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        changed |= BSS_CHANGED_IBSS;
                        /* fall through */
                case NL80211_IFTYPE_AP:
-                       changed |= BSS_CHANGED_SSID |
-                                  BSS_CHANGED_AP_PROBE_RESP;
+                       changed |= BSS_CHANGED_SSID;
+
+                       if (sdata->vif.type == NL80211_IFTYPE_AP)
+                               changed |= BSS_CHANGED_AP_PROBE_RESP;
+
                        /* fall through */
                case NL80211_IFTYPE_MESH_POINT:
                        changed |= BSS_CHANGED_BEACON |
index 4332711..89511be 100644 (file)
@@ -52,6 +52,30 @@ static int wme_downgrade_ac(struct sk_buff *skb)
        }
 }
 
+/* Indicate which queue to use for this fully formed 802.11 frame */
+u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
+                                struct sk_buff *skb,
+                                struct ieee80211_hdr *hdr)
+{
+       u8 *p;
+
+       if (local->hw.queues < 4)
+               return 0;
+
+       if (!ieee80211_is_data(hdr->frame_control)) {
+               skb->priority = 7;
+               return ieee802_1d_to_ac[skb->priority];
+       }
+       if (!ieee80211_is_data_qos(hdr->frame_control)) {
+               skb->priority = 0;
+               return ieee802_1d_to_ac[skb->priority];
+       }
+
+       p = ieee80211_get_qos_ctl(hdr);
+       skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
+
+       return ieee80211_downgrade_queue(local, skb);
+}
 
 /* Indicate which queue to use. */
 u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
@@ -139,6 +163,7 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
                           struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (void *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        /* Fill in the QoS header if there is one. */
        if (ieee80211_is_data_qos(hdr->frame_control)) {
@@ -150,9 +175,12 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
                /* preserve EOSP bit */
                ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
 
-               if (unlikely(sdata->local->wifi_wme_noack_test) ||
-                   is_multicast_ether_addr(hdr->addr1))
+               if (is_multicast_ether_addr(hdr->addr1) ||
+                   sdata->noack_map & BIT(tid)) {
                        ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
+                       info->flags |= IEEE80211_TX_CTL_NO_ACK;
+               }
+
                /* qos header is 2 bytes */
                *p++ = ack_policy | tid;
                *p = ieee80211_vif_is_mesh(&sdata->vif) ?
index 34e166f..94edceb 100644 (file)
@@ -15,6 +15,9 @@
 
 extern const int ieee802_1d_to_ac[8];
 
+u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
+                                struct sk_buff *skb,
+                                struct ieee80211_hdr *hdr);
 u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
                           struct sk_buff *skb);
 void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
index 6884a2d..c6dd01a 100644 (file)
@@ -862,44 +862,6 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
        kfree_skb(skb);
 }
 
-static bool ieee80211_work_ct_coexists(enum nl80211_channel_type wk_ct,
-                                      enum nl80211_channel_type oper_ct)
-{
-       switch (wk_ct) {
-       case NL80211_CHAN_NO_HT:
-               return true;
-       case NL80211_CHAN_HT20:
-               if (oper_ct != NL80211_CHAN_NO_HT)
-                       return true;
-               return false;
-       case NL80211_CHAN_HT40MINUS:
-       case NL80211_CHAN_HT40PLUS:
-               return (wk_ct == oper_ct);
-       }
-       WARN_ON(1); /* shouldn't get here */
-       return false;
-}
-
-static enum nl80211_channel_type
-ieee80211_calc_ct(enum nl80211_channel_type wk_ct,
-                 enum nl80211_channel_type oper_ct)
-{
-       switch (wk_ct) {
-       case NL80211_CHAN_NO_HT:
-               return oper_ct;
-       case NL80211_CHAN_HT20:
-               if (oper_ct != NL80211_CHAN_NO_HT)
-                       return oper_ct;
-               return wk_ct;
-       case NL80211_CHAN_HT40MINUS:
-       case NL80211_CHAN_HT40PLUS:
-               return wk_ct;
-       }
-       WARN_ON(1); /* shouldn't get here */
-       return wk_ct;
-}
-
-
 static void ieee80211_work_timer(unsigned long data)
 {
        struct ieee80211_local *local = (void *) data;
@@ -950,40 +912,12 @@ static void ieee80211_work_work(struct work_struct *work)
                }
 
                if (!started && !local->tmp_channel) {
-                       bool on_oper_chan, on_oper_chan2;
-                       enum nl80211_channel_type wk_ct;
-
-                       on_oper_chan = ieee80211_cfg_on_oper_channel(local);
-
-                       /* Work with existing channel type if possible. */
-                       wk_ct = wk->chan_type;
-                       if (wk->chan == local->hw.conf.channel)
-                               wk_ct = ieee80211_calc_ct(wk->chan_type,
-                                               local->hw.conf.channel_type);
+                       ieee80211_offchannel_stop_vifs(local, true);
 
                        local->tmp_channel = wk->chan;
-                       local->tmp_channel_type = wk_ct;
-                       /*
-                        * Leave the station vifs in awake mode if they
-                        * happen to be on the same channel as
-                        * the requested channel.
-                        */
-                       on_oper_chan2 = ieee80211_cfg_on_oper_channel(local);
-                       if (on_oper_chan != on_oper_chan2) {
-                               if (on_oper_chan2) {
-                                       /* going off oper channel, PS too */
-                                       ieee80211_offchannel_stop_vifs(local,
-                                                                      true);
-                                       ieee80211_hw_config(local, 0);
-                               } else {
-                                       /* going on channel, but leave PS
-                                        * off-channel. */
-                                       ieee80211_hw_config(local, 0);
-                                       ieee80211_offchannel_return(local,
-                                                                   true,
-                                                                   false);
-                               }
-                       }
+                       local->tmp_channel_type = wk->chan_type;
+
+                       ieee80211_hw_config(local, 0);
 
                        started = true;
                        wk->timeout = jiffies;
@@ -1052,34 +986,17 @@ static void ieee80211_work_work(struct work_struct *work)
        list_for_each_entry(wk, &local->work_list, list) {
                if (!wk->started)
                        continue;
-               if (wk->chan != local->tmp_channel)
-                       continue;
-               if (!ieee80211_work_ct_coexists(wk->chan_type,
-                                               local->tmp_channel_type))
+               if (wk->chan != local->tmp_channel ||
+                   wk->chan_type != local->tmp_channel_type)
                        continue;
                remain_off_channel = true;
        }
 
        if (!remain_off_channel && local->tmp_channel) {
                local->tmp_channel = NULL;
-               /* If tmp_channel wasn't operating channel, then
-                * we need to go back on-channel.
-                * NOTE:  If we can ever be here while scannning,
-                * or if the hw_config() channel config logic changes,
-                * then we may need to do a more thorough check to see if
-                * we still need to do a hardware config.  Currently,
-                * we cannot be here while scanning, however.
-                */
-               if (!ieee80211_cfg_on_oper_channel(local))
-                       ieee80211_hw_config(local, 0);
+               ieee80211_hw_config(local, 0);
 
-               /* At the least, we need to disable offchannel_ps,
-                * so just go ahead and run the entire offchannel
-                * return logic here.  We *could* skip enabling
-                * beaconing if we were already on-oper-channel
-                * as a future optimization.
-                */
-               ieee80211_offchannel_return(local, true, true);
+               ieee80211_offchannel_return(local, true);
 
                /* give connection some time to breathe */
                run_again(local, jiffies + HZ/2);
index 47e02c1..3ebc6b3 100644 (file)
@@ -21,6 +21,8 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 int nfc_devlist_generation;
 DEFINE_MUTEX(nfc_devlist_mutex);
 
-int nfc_printk(const char *level, const char *format, ...)
-{
-       struct va_format vaf;
-       va_list args;
-       int r;
-
-       va_start(args, format);
-
-       vaf.fmt = format;
-       vaf.va = &args;
-
-       r = printk("%sNFC: %pV\n", level, &vaf);
-
-       va_end(args);
-
-       return r;
-}
-EXPORT_SYMBOL(nfc_printk);
-
 /**
  * nfc_dev_up - turn on the NFC device
  *
@@ -63,7 +46,7 @@ int nfc_dev_up(struct nfc_dev *dev)
 {
        int rc = 0;
 
-       nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+       pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
        device_lock(&dev->dev);
 
@@ -97,7 +80,7 @@ int nfc_dev_down(struct nfc_dev *dev)
 {
        int rc = 0;
 
-       nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+       pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
        device_lock(&dev->dev);
 
@@ -139,7 +122,8 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
 {
        int rc;
 
-       nfc_dbg("dev_name=%s protocols=0x%x", dev_name(&dev->dev), protocols);
+       pr_debug("dev_name=%s protocols=0x%x\n",
+                dev_name(&dev->dev), protocols);
 
        if (!protocols)
                return -EINVAL;
@@ -174,7 +158,7 @@ int nfc_stop_poll(struct nfc_dev *dev)
 {
        int rc = 0;
 
-       nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+       pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
        device_lock(&dev->dev);
 
@@ -207,8 +191,8 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
 {
        int rc;
 
-       nfc_dbg("dev_name=%s target_idx=%u protocol=%u", dev_name(&dev->dev),
-                                                       target_idx, protocol);
+       pr_debug("dev_name=%s target_idx=%u protocol=%u\n",
+                dev_name(&dev->dev), target_idx, protocol);
 
        device_lock(&dev->dev);
 
@@ -236,7 +220,8 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx)
 {
        int rc = 0;
 
-       nfc_dbg("dev_name=%s target_idx=%u", dev_name(&dev->dev), target_idx);
+       pr_debug("dev_name=%s target_idx=%u\n",
+                dev_name(&dev->dev), target_idx);
 
        device_lock(&dev->dev);
 
@@ -271,8 +256,8 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx,
 {
        int rc;
 
-       nfc_dbg("dev_name=%s target_idx=%u skb->len=%u", dev_name(&dev->dev),
-                                                       target_idx, skb->len);
+       pr_debug("dev_name=%s target_idx=%u skb->len=%u\n",
+                dev_name(&dev->dev), target_idx, skb->len);
 
        device_lock(&dev->dev);
 
@@ -326,7 +311,7 @@ int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
 {
        int i;
 
-       nfc_dbg("dev_name=%s n_targets=%d", dev_name(&dev->dev), n_targets);
+       pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets);
 
        dev->polling = false;
 
@@ -360,7 +345,7 @@ static void nfc_release(struct device *d)
 {
        struct nfc_dev *dev = to_nfc_dev(d);
 
-       nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+       pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
        nfc_genl_data_exit(&dev->genl_data);
        kfree(dev->targets);
@@ -446,7 +431,7 @@ int nfc_register_device(struct nfc_dev *dev)
 {
        int rc;
 
-       nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+       pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
        mutex_lock(&nfc_devlist_mutex);
        nfc_devlist_generation++;
@@ -458,9 +443,8 @@ int nfc_register_device(struct nfc_dev *dev)
 
        rc = nfc_genl_device_added(dev);
        if (rc)
-               nfc_dbg("The userspace won't be notified that the device %s was"
-                                               " added", dev_name(&dev->dev));
-
+               pr_debug("The userspace won't be notified that the device %s was added\n",
+                        dev_name(&dev->dev));
 
        return 0;
 }
@@ -475,7 +459,7 @@ void nfc_unregister_device(struct nfc_dev *dev)
 {
        int rc;
 
-       nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+       pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
        mutex_lock(&nfc_devlist_mutex);
        nfc_devlist_generation++;
@@ -490,8 +474,8 @@ void nfc_unregister_device(struct nfc_dev *dev)
 
        rc = nfc_genl_device_removed(dev);
        if (rc)
-               nfc_dbg("The userspace won't be notified that the device %s"
-                                       " was removed", dev_name(&dev->dev));
+               pr_debug("The userspace won't be notified that the device %s was removed\n",
+                        dev_name(&dev->dev));
 
 }
 EXPORT_SYMBOL(nfc_unregister_device);
@@ -500,7 +484,7 @@ static int __init nfc_init(void)
 {
        int rc;
 
-       nfc_info("NFC Core ver %s", VERSION);
+       pr_info("NFC Core ver %s\n", VERSION);
 
        rc = class_register(&nfc_class);
        if (rc)
index fe5ca89..37de28e 100644 (file)
@@ -25,6 +25,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/workqueue.h>
 #include <linux/completion.h>
@@ -79,7 +81,7 @@ static int __nci_request(struct nci_dev *ndev,
                                                        &ndev->req_completion,
                                                        timeout);
 
-       nfc_dbg("wait_for_completion return %ld", completion_rc);
+       pr_debug("wait_for_completion return %ld\n", completion_rc);
 
        if (completion_rc > 0) {
                switch (ndev->req_status) {
@@ -96,8 +98,8 @@ static int __nci_request(struct nci_dev *ndev,
                        break;
                }
        } else {
-               nfc_err("wait_for_completion_interruptible_timeout failed %ld",
-                       completion_rc);
+               pr_err("wait_for_completion_interruptible_timeout failed %ld\n",
+                      completion_rc);
 
                rc = ((completion_rc == 0) ? (-ETIMEDOUT) : (completion_rc));
        }
@@ -323,8 +325,6 @@ static void nci_cmd_timer(unsigned long arg)
 {
        struct nci_dev *ndev = (void *) arg;
 
-       nfc_dbg("entry");
-
        atomic_set(&ndev->cmd_cnt, 1);
        queue_work(ndev->cmd_wq, &ndev->cmd_work);
 }
@@ -333,8 +333,6 @@ static int nci_dev_up(struct nfc_dev *nfc_dev)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
 
-       nfc_dbg("entry");
-
        return nci_open_device(ndev);
 }
 
@@ -342,8 +340,6 @@ static int nci_dev_down(struct nfc_dev *nfc_dev)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
 
-       nfc_dbg("entry");
-
        return nci_close_device(ndev);
 }
 
@@ -352,20 +348,18 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
        int rc;
 
-       nfc_dbg("entry");
-
        if (test_bit(NCI_DISCOVERY, &ndev->flags)) {
-               nfc_err("unable to start poll, since poll is already active");
+               pr_err("unable to start poll, since poll is already active\n");
                return -EBUSY;
        }
 
        if (ndev->target_active_prot) {
-               nfc_err("there is an active target");
+               pr_err("there is an active target\n");
                return -EBUSY;
        }
 
        if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
-               nfc_dbg("target is active, implicitly deactivate...");
+               pr_debug("target is active, implicitly deactivate...\n");
 
                rc = nci_request(ndev, nci_rf_deactivate_req, 0,
                        msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
@@ -386,10 +380,8 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
 
-       nfc_dbg("entry");
-
        if (!test_bit(NCI_DISCOVERY, &ndev->flags)) {
-               nfc_err("unable to stop poll, since poll is not active");
+               pr_err("unable to stop poll, since poll is not active\n");
                return;
        }
 
@@ -402,21 +394,21 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
 
-       nfc_dbg("entry, target_idx %d, protocol 0x%x", target_idx, protocol);
+       pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol);
 
        if (!test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
-               nfc_err("there is no available target to activate");
+               pr_err("there is no available target to activate\n");
                return -EINVAL;
        }
 
        if (ndev->target_active_prot) {
-               nfc_err("there is already an active target");
+               pr_err("there is already an active target\n");
                return -EBUSY;
        }
 
        if (!(ndev->target_available_prots & (1 << protocol))) {
-               nfc_err("target does not support the requested protocol 0x%x",
-                       protocol);
+               pr_err("target does not support the requested protocol 0x%x\n",
+                      protocol);
                return -EINVAL;
        }
 
@@ -430,10 +422,10 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
 
-       nfc_dbg("entry, target_idx %d", target_idx);
+       pr_debug("target_idx %d\n", target_idx);
 
        if (!ndev->target_active_prot) {
-               nfc_err("unable to deactivate target, no active target");
+               pr_err("unable to deactivate target, no active target\n");
                return;
        }
 
@@ -453,10 +445,10 @@ static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
        int rc;
 
-       nfc_dbg("entry, target_idx %d, len %d", target_idx, skb->len);
+       pr_debug("target_idx %d, len %d\n", target_idx, skb->len);
 
        if (!ndev->target_active_prot) {
-               nfc_err("unable to exchange data, no active target");
+               pr_err("unable to exchange data, no active target\n");
                return -EINVAL;
        }
 
@@ -499,7 +491,7 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops,
 {
        struct nci_dev *ndev;
 
-       nfc_dbg("entry, supported_protocols 0x%x", supported_protocols);
+       pr_debug("supported_protocols 0x%x\n", supported_protocols);
 
        if (!ops->open || !ops->close || !ops->send)
                return NULL;
@@ -539,8 +531,6 @@ EXPORT_SYMBOL(nci_allocate_device);
  */
 void nci_free_device(struct nci_dev *ndev)
 {
-       nfc_dbg("entry");
-
        nfc_free_device(ndev->nfc_dev);
        kfree(ndev);
 }
@@ -557,8 +547,6 @@ int nci_register_device(struct nci_dev *ndev)
        struct device *dev = &ndev->nfc_dev->dev;
        char name[32];
 
-       nfc_dbg("entry");
-
        rc = nfc_register_device(ndev->nfc_dev);
        if (rc)
                goto exit;
@@ -621,8 +609,6 @@ EXPORT_SYMBOL(nci_register_device);
  */
 void nci_unregister_device(struct nci_dev *ndev)
 {
-       nfc_dbg("entry");
-
        nci_close_device(ndev);
 
        destroy_workqueue(ndev->cmd_wq);
@@ -642,7 +628,7 @@ int nci_recv_frame(struct sk_buff *skb)
 {
        struct nci_dev *ndev = (struct nci_dev *) skb->dev;
 
-       nfc_dbg("entry, len %d", skb->len);
+       pr_debug("len %d\n", skb->len);
 
        if (!ndev || (!test_bit(NCI_UP, &ndev->flags)
                && !test_bit(NCI_INIT, &ndev->flags))) {
@@ -662,7 +648,7 @@ static int nci_send_frame(struct sk_buff *skb)
 {
        struct nci_dev *ndev = (struct nci_dev *) skb->dev;
 
-       nfc_dbg("entry, len %d", skb->len);
+       pr_debug("len %d\n", skb->len);
 
        if (!ndev) {
                kfree_skb(skb);
@@ -681,11 +667,11 @@ int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload)
        struct nci_ctrl_hdr *hdr;
        struct sk_buff *skb;
 
-       nfc_dbg("entry, opcode 0x%x, plen %d", opcode, plen);
+       pr_debug("opcode 0x%x, plen %d\n", opcode, plen);
 
        skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + plen), GFP_KERNEL);
        if (!skb) {
-               nfc_err("no memory for command");
+               pr_err("no memory for command\n");
                return -ENOMEM;
        }
 
@@ -715,7 +701,7 @@ static void nci_tx_work(struct work_struct *work)
        struct nci_dev *ndev = container_of(work, struct nci_dev, tx_work);
        struct sk_buff *skb;
 
-       nfc_dbg("entry, credits_cnt %d", atomic_read(&ndev->credits_cnt));
+       pr_debug("credits_cnt %d\n", atomic_read(&ndev->credits_cnt));
 
        /* Send queued tx data */
        while (atomic_read(&ndev->credits_cnt)) {
@@ -728,10 +714,10 @@ static void nci_tx_work(struct work_struct *work)
                                NCI_DATA_FLOW_CONTROL_NOT_USED)
                        atomic_dec(&ndev->credits_cnt);
 
-               nfc_dbg("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d",
-                               nci_pbf(skb->data),
-                               nci_conn_id(skb->data),
-                               nci_plen(skb->data));
+               pr_debug("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d\n",
+                        nci_pbf(skb->data),
+                        nci_conn_id(skb->data),
+                        nci_plen(skb->data));
 
                nci_send_frame(skb);
        }
@@ -760,7 +746,7 @@ static void nci_rx_work(struct work_struct *work)
                        break;
 
                default:
-                       nfc_err("unknown MT 0x%x", nci_mt(skb->data));
+                       pr_err("unknown MT 0x%x\n", nci_mt(skb->data));
                        kfree_skb(skb);
                        break;
                }
@@ -774,7 +760,7 @@ static void nci_cmd_work(struct work_struct *work)
        struct nci_dev *ndev = container_of(work, struct nci_dev, cmd_work);
        struct sk_buff *skb;
 
-       nfc_dbg("entry, cmd_cnt %d", atomic_read(&ndev->cmd_cnt));
+       pr_debug("cmd_cnt %d\n", atomic_read(&ndev->cmd_cnt));
 
        /* Send queued command */
        if (atomic_read(&ndev->cmd_cnt)) {
@@ -784,11 +770,11 @@ static void nci_cmd_work(struct work_struct *work)
 
                atomic_dec(&ndev->cmd_cnt);
 
-               nfc_dbg("NCI TX: MT=cmd, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
-                               nci_pbf(skb->data),
-                               nci_opcode_gid(nci_opcode(skb->data)),
-                               nci_opcode_oid(nci_opcode(skb->data)),
-                               nci_plen(skb->data));
+               pr_debug("NCI TX: MT=cmd, PBF=%d, GID=0x%x, OID=0x%x, plen=%d\n",
+                        nci_pbf(skb->data),
+                        nci_opcode_gid(nci_opcode(skb->data)),
+                        nci_opcode_oid(nci_opcode(skb->data)),
+                        nci_plen(skb->data));
 
                nci_send_frame(skb);
 
index 511fb96..1e040fe 100644 (file)
@@ -21,6 +21,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
@@ -40,7 +42,7 @@ void nci_data_exchange_complete(struct nci_dev *ndev,
        data_exchange_cb_t cb = ndev->data_exchange_cb;
        void *cb_context = ndev->data_exchange_cb_context;
 
-       nfc_dbg("entry, len %d, err %d", ((skb) ? (skb->len) : (0)), err);
+       pr_debug("len %d, err %d\n", skb ? skb->len : 0, err);
 
        if (cb) {
                ndev->data_exchange_cb = NULL;
@@ -49,7 +51,7 @@ void nci_data_exchange_complete(struct nci_dev *ndev,
                /* forward skb to nfc core */
                cb(cb_context, skb, err);
        } else if (skb) {
-               nfc_err("no rx callback, dropping rx data...");
+               pr_err("no rx callback, dropping rx data...\n");
 
                /* no waiting callback, free skb */
                kfree_skb(skb);
@@ -90,7 +92,7 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
        int frag_len;
        int rc = 0;
 
-       nfc_dbg("entry, conn_id 0x%x, total_len %d", conn_id, total_len);
+       pr_debug("conn_id 0x%x, total_len %d\n", conn_id, total_len);
 
        __skb_queue_head_init(&frags_q);
 
@@ -119,8 +121,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
                data += frag_len;
                total_len -= frag_len;
 
-               nfc_dbg("frag_len %d, remaining total_len %d",
-                       frag_len, total_len);
+               pr_debug("frag_len %d, remaining total_len %d\n",
+                        frag_len, total_len);
        }
 
        /* queue all fragments atomically */
@@ -149,7 +151,7 @@ int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
 {
        int rc = 0;
 
-       nfc_dbg("entry, conn_id 0x%x, plen %d", conn_id, skb->len);
+       pr_debug("conn_id 0x%x, plen %d\n", conn_id, skb->len);
 
        /* check if the packet need to be fragmented */
        if (skb->len <= ndev->max_data_pkt_payload_size) {
@@ -161,7 +163,7 @@ int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
                /* fragment packet and queue the fragments */
                rc = nci_queue_tx_data_frags(ndev, conn_id, skb);
                if (rc) {
-                       nfc_err("failed to fragment tx data packet");
+                       pr_err("failed to fragment tx data packet\n");
                        goto free_exit;
                }
        }
@@ -191,7 +193,7 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev,
 
                /* first, make enough room for the already accumulated data */
                if (skb_cow_head(skb, reassembly_len)) {
-                       nfc_err("error adding room for accumulated rx data");
+                       pr_err("error adding room for accumulated rx data\n");
 
                        kfree_skb(skb);
                        skb = 0;
@@ -228,19 +230,19 @@ void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb)
 {
        __u8 pbf = nci_pbf(skb->data);
 
-       nfc_dbg("entry, len %d", skb->len);
+       pr_debug("len %d\n", skb->len);
 
-       nfc_dbg("NCI RX: MT=data, PBF=%d, conn_id=%d, plen=%d",
-                       nci_pbf(skb->data),
-                       nci_conn_id(skb->data),
-                       nci_plen(skb->data));
+       pr_debug("NCI RX: MT=data, PBF=%d, conn_id=%d, plen=%d\n",
+                nci_pbf(skb->data),
+                nci_conn_id(skb->data),
+                nci_plen(skb->data));
 
        /* strip the nci data header */
        skb_pull(skb, NCI_DATA_HDR_SIZE);
 
        if (ndev->target_active_prot == NFC_PROTO_MIFARE) {
                /* frame I/F => remove the status byte */
-               nfc_dbg("NFC_PROTO_MIFARE => remove the status byte");
+               pr_debug("NFC_PROTO_MIFARE => remove the status byte\n");
                skb_trim(skb, (skb->len - 1));
        }
 
index c1bf541..c36bd4a 100644 (file)
@@ -25,6 +25,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
@@ -43,16 +45,16 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
        struct nci_core_conn_credit_ntf *ntf = (void *) skb->data;
        int i;
 
-       nfc_dbg("entry, num_entries %d", ntf->num_entries);
+       pr_debug("num_entries %d\n", ntf->num_entries);
 
        if (ntf->num_entries > NCI_MAX_NUM_CONN)
                ntf->num_entries = NCI_MAX_NUM_CONN;
 
        /* update the credits */
        for (i = 0; i < ntf->num_entries; i++) {
-               nfc_dbg("entry[%d]: conn_id %d, credits %d", i,
-                       ntf->conn_entries[i].conn_id,
-                       ntf->conn_entries[i].credits);
+               pr_debug("entry[%d]: conn_id %d, credits %d\n",
+                        i, ntf->conn_entries[i].conn_id,
+                        ntf->conn_entries[i].credits);
 
                if (ntf->conn_entries[i].conn_id == NCI_STATIC_RF_CONN_ID) {
                        /* found static rf connection */
@@ -78,9 +80,8 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
 
        nfca_poll->nfcid1_len = *data++;
 
-       nfc_dbg("sens_res 0x%x, nfcid1_len %d",
-               nfca_poll->sens_res,
-               nfca_poll->nfcid1_len);
+       pr_debug("sens_res 0x%x, nfcid1_len %d\n",
+                nfca_poll->sens_res, nfca_poll->nfcid1_len);
 
        memcpy(nfca_poll->nfcid1, data, nfca_poll->nfcid1_len);
        data += nfca_poll->nfcid1_len;
@@ -90,9 +91,9 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
        if (nfca_poll->sel_res_len != 0)
                nfca_poll->sel_res = *data++;
 
-       nfc_dbg("sel_res_len %d, sel_res 0x%x",
-               nfca_poll->sel_res_len,
-               nfca_poll->sel_res);
+       pr_debug("sel_res_len %d, sel_res 0x%x\n",
+                nfca_poll->sel_res_len,
+                nfca_poll->sel_res);
 
        return data;
 }
@@ -114,8 +115,8 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
                break;
 
        default:
-               nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
-                       ntf->activation_rf_tech_and_mode);
+               pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
+                      ntf->activation_rf_tech_and_mode);
                return -EPROTO;
        }
 
@@ -138,12 +139,12 @@ static void nci_target_found(struct nci_dev *ndev,
        nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res;
 
        if (!(nfc_tgt.supported_protocols & ndev->poll_prots)) {
-               nfc_dbg("the target found does not have the desired protocol");
+               pr_debug("the target found does not have the desired protocol\n");
                return;
        }
 
-       nfc_dbg("new target found,  supported_protocols 0x%x",
-               nfc_tgt.supported_protocols);
+       pr_debug("new target found,  supported_protocols 0x%x\n",
+                nfc_tgt.supported_protocols);
 
        ndev->target_available_prots = nfc_tgt.supported_protocols;
 
@@ -166,13 +167,13 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
        ntf.activation_rf_tech_and_mode = *data++;
        ntf.rf_tech_specific_params_len = *data++;
 
-       nfc_dbg("rf_discovery_id %d", ntf.rf_discovery_id);
-       nfc_dbg("rf_interface_type 0x%x", ntf.rf_interface_type);
-       nfc_dbg("rf_protocol 0x%x", ntf.rf_protocol);
-       nfc_dbg("activation_rf_tech_and_mode 0x%x",
-               ntf.activation_rf_tech_and_mode);
-       nfc_dbg("rf_tech_specific_params_len %d",
-               ntf.rf_tech_specific_params_len);
+       pr_debug("rf_discovery_id %d\n", ntf.rf_discovery_id);
+       pr_debug("rf_interface_type 0x%x\n", ntf.rf_interface_type);
+       pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol);
+       pr_debug("activation_rf_tech_and_mode 0x%x\n",
+                ntf.activation_rf_tech_and_mode);
+       pr_debug("rf_tech_specific_params_len %d\n",
+                ntf.rf_tech_specific_params_len);
 
        if (ntf.rf_tech_specific_params_len > 0) {
                switch (ntf.activation_rf_tech_and_mode) {
@@ -182,8 +183,8 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
                        break;
 
                default:
-                       nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
-                               ntf.activation_rf_tech_and_mode);
+                       pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
+                              ntf.activation_rf_tech_and_mode);
                        return;
                }
        }
@@ -193,14 +194,14 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
        ntf.data_exch_rx_bit_rate = *data++;
        ntf.activation_params_len = *data++;
 
-       nfc_dbg("data_exch_rf_tech_and_mode 0x%x",
-               ntf.data_exch_rf_tech_and_mode);
-       nfc_dbg("data_exch_tx_bit_rate 0x%x",
-               ntf.data_exch_tx_bit_rate);
-       nfc_dbg("data_exch_rx_bit_rate 0x%x",
-               ntf.data_exch_rx_bit_rate);
-       nfc_dbg("activation_params_len %d",
-               ntf.activation_params_len);
+       pr_debug("data_exch_rf_tech_and_mode 0x%x\n",
+                ntf.data_exch_rf_tech_and_mode);
+       pr_debug("data_exch_tx_bit_rate 0x%x\n",
+                ntf.data_exch_tx_bit_rate);
+       pr_debug("data_exch_rx_bit_rate 0x%x\n",
+                ntf.data_exch_rx_bit_rate);
+       pr_debug("activation_params_len %d\n",
+                ntf.activation_params_len);
 
        if (ntf.activation_params_len > 0) {
                switch (ntf.rf_interface_type) {
@@ -214,8 +215,8 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
                        break;
 
                default:
-                       nfc_err("unsupported rf_interface_type 0x%x",
-                               ntf.rf_interface_type);
+                       pr_err("unsupported rf_interface_type 0x%x\n",
+                              ntf.rf_interface_type);
                        return;
                }
        }
@@ -229,7 +230,7 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
 {
        struct nci_rf_deactivate_ntf *ntf = (void *) skb->data;
 
-       nfc_dbg("entry, type 0x%x, reason 0x%x", ntf->type, ntf->reason);
+       pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason);
 
        clear_bit(NCI_POLL_ACTIVE, &ndev->flags);
        ndev->target_active_prot = 0;
@@ -255,11 +256,11 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
 {
        __u16 ntf_opcode = nci_opcode(skb->data);
 
-       nfc_dbg("NCI RX: MT=ntf, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
-                       nci_pbf(skb->data),
-                       nci_opcode_gid(ntf_opcode),
-                       nci_opcode_oid(ntf_opcode),
-                       nci_plen(skb->data));
+       pr_debug("NCI RX: MT=ntf, PBF=%d, GID=0x%x, OID=0x%x, plen=%d\n",
+                nci_pbf(skb->data),
+                nci_opcode_gid(ntf_opcode),
+                nci_opcode_oid(ntf_opcode),
+                nci_plen(skb->data));
 
        /* strip the nci control header */
        skb_pull(skb, NCI_CTRL_HDR_SIZE);
@@ -278,7 +279,7 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
                break;
 
        default:
-               nfc_err("unknown ntf opcode 0x%x", ntf_opcode);
+               pr_err("unknown ntf opcode 0x%x\n", ntf_opcode);
                break;
        }
 
index 0591f5a..ca611c5 100644 (file)
@@ -25,6 +25,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
@@ -40,12 +42,12 @@ static void nci_core_reset_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
 {
        struct nci_core_reset_rsp *rsp = (void *) skb->data;
 
-       nfc_dbg("entry, status 0x%x", rsp->status);
+       pr_debug("status 0x%x\n", rsp->status);
 
        if (rsp->status == NCI_STATUS_OK) {
                ndev->nci_ver = rsp->nci_ver;
-               nfc_dbg("nci_ver 0x%x, config_status 0x%x",
-                       rsp->nci_ver, rsp->config_status);
+               pr_debug("nci_ver 0x%x, config_status 0x%x\n",
+                        rsp->nci_ver, rsp->config_status);
        }
 
        nci_req_complete(ndev, rsp->status);
@@ -56,7 +58,7 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
        struct nci_core_init_rsp_1 *rsp_1 = (void *) skb->data;
        struct nci_core_init_rsp_2 *rsp_2;
 
-       nfc_dbg("entry, status 0x%x", rsp_1->status);
+       pr_debug("status 0x%x\n", rsp_1->status);
 
        if (rsp_1->status != NCI_STATUS_OK)
                goto exit;
@@ -95,34 +97,34 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
 
        atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
 
-       nfc_dbg("nfcc_features 0x%x",
-               ndev->nfcc_features);
-       nfc_dbg("num_supported_rf_interfaces %d",
-               ndev->num_supported_rf_interfaces);
-       nfc_dbg("supported_rf_interfaces[0] 0x%x",
-               ndev->supported_rf_interfaces[0]);
-       nfc_dbg("supported_rf_interfaces[1] 0x%x",
-               ndev->supported_rf_interfaces[1]);
-       nfc_dbg("supported_rf_interfaces[2] 0x%x",
-               ndev->supported_rf_interfaces[2]);
-       nfc_dbg("supported_rf_interfaces[3] 0x%x",
-               ndev->supported_rf_interfaces[3]);
-       nfc_dbg("max_logical_connections %d",
-               ndev->max_logical_connections);
-       nfc_dbg("max_routing_table_size %d",
-               ndev->max_routing_table_size);
-       nfc_dbg("max_ctrl_pkt_payload_len %d",
-               ndev->max_ctrl_pkt_payload_len);
-       nfc_dbg("max_size_for_large_params %d",
-               ndev->max_size_for_large_params);
-       nfc_dbg("max_data_pkt_payload_size %d",
-               ndev->max_data_pkt_payload_size);
-       nfc_dbg("initial_num_credits %d",
-               ndev->initial_num_credits);
-       nfc_dbg("manufact_id 0x%x",
-               ndev->manufact_id);
-       nfc_dbg("manufact_specific_info 0x%x",
-               ndev->manufact_specific_info);
+       pr_debug("nfcc_features 0x%x\n",
+                ndev->nfcc_features);
+       pr_debug("num_supported_rf_interfaces %d\n",
+                ndev->num_supported_rf_interfaces);
+       pr_debug("supported_rf_interfaces[0] 0x%x\n",
+                ndev->supported_rf_interfaces[0]);
+       pr_debug("supported_rf_interfaces[1] 0x%x\n",
+                ndev->supported_rf_interfaces[1]);
+       pr_debug("supported_rf_interfaces[2] 0x%x\n",
+                ndev->supported_rf_interfaces[2]);
+       pr_debug("supported_rf_interfaces[3] 0x%x\n",
+                ndev->supported_rf_interfaces[3]);
+       pr_debug("max_logical_connections %d\n",
+                ndev->max_logical_connections);
+       pr_debug("max_routing_table_size %d\n",
+                ndev->max_routing_table_size);
+       pr_debug("max_ctrl_pkt_payload_len %d\n",
+                ndev->max_ctrl_pkt_payload_len);
+       pr_debug("max_size_for_large_params %d\n",
+                ndev->max_size_for_large_params);
+       pr_debug("max_data_pkt_payload_size %d\n",
+                ndev->max_data_pkt_payload_size);
+       pr_debug("initial_num_credits %d\n",
+                ndev->initial_num_credits);
+       pr_debug("manufact_id 0x%x\n",
+                ndev->manufact_id);
+       pr_debug("manufact_specific_info 0x%x\n",
+                ndev->manufact_specific_info);
 
 exit:
        nci_req_complete(ndev, rsp_1->status);
@@ -133,7 +135,7 @@ static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
 {
        __u8 status = skb->data[0];
 
-       nfc_dbg("entry, status 0x%x", status);
+       pr_debug("status 0x%x\n", status);
 
        nci_req_complete(ndev, status);
 }
@@ -142,7 +144,7 @@ static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
 {
        __u8 status = skb->data[0];
 
-       nfc_dbg("entry, status 0x%x", status);
+       pr_debug("status 0x%x\n", status);
 
        if (status == NCI_STATUS_OK)
                set_bit(NCI_DISCOVERY, &ndev->flags);
@@ -155,7 +157,7 @@ static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev,
 {
        __u8 status = skb->data[0];
 
-       nfc_dbg("entry, status 0x%x", status);
+       pr_debug("status 0x%x\n", status);
 
        clear_bit(NCI_DISCOVERY, &ndev->flags);
 
@@ -169,11 +171,11 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
        /* we got a rsp, stop the cmd timer */
        del_timer(&ndev->cmd_timer);
 
-       nfc_dbg("NCI RX: MT=rsp, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
-                       nci_pbf(skb->data),
-                       nci_opcode_gid(rsp_opcode),
-                       nci_opcode_oid(rsp_opcode),
-                       nci_plen(skb->data));
+       pr_debug("NCI RX: MT=rsp, PBF=%d, GID=0x%x, OID=0x%x, plen=%d\n",
+                nci_pbf(skb->data),
+                nci_opcode_gid(rsp_opcode),
+                nci_opcode_oid(rsp_opcode),
+                nci_plen(skb->data));
 
        /* strip the nci control header */
        skb_pull(skb, NCI_CTRL_HDR_SIZE);
@@ -200,7 +202,7 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                break;
 
        default:
-               nfc_err("unknown rsp opcode 0x%x", rsp_opcode);
+               pr_err("unknown rsp opcode 0x%x\n", rsp_opcode);
                break;
        }
 
index 03f8818..c10e9b8 100644 (file)
@@ -21,6 +21,8 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <net/genetlink.h>
 #include <linux/nfc.h>
 #include <linux/slab.h>
@@ -51,8 +53,6 @@ static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
 {
        void *hdr;
 
-       nfc_dbg("entry");
-
        hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
                                &nfc_genl_family, flags, NFC_CMD_GET_TARGET);
        if (!hdr)
@@ -105,8 +105,6 @@ static int nfc_genl_dump_targets(struct sk_buff *skb,
        struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
        int rc;
 
-       nfc_dbg("entry");
-
        if (!dev) {
                dev = __get_device_from_cb(cb);
                if (IS_ERR(dev))
@@ -139,8 +137,6 @@ static int nfc_genl_dump_targets_done(struct netlink_callback *cb)
 {
        struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
 
-       nfc_dbg("entry");
-
        if (dev)
                nfc_put_device(dev);
 
@@ -152,8 +148,6 @@ int nfc_genl_targets_found(struct nfc_dev *dev)
        struct sk_buff *msg;
        void *hdr;
 
-       nfc_dbg("entry");
-
        dev->genl_data.poll_req_pid = 0;
 
        msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
@@ -183,8 +177,6 @@ int nfc_genl_device_added(struct nfc_dev *dev)
        struct sk_buff *msg;
        void *hdr;
 
-       nfc_dbg("entry");
-
        msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
        if (!msg)
                return -ENOMEM;
@@ -216,8 +208,6 @@ int nfc_genl_device_removed(struct nfc_dev *dev)
        struct sk_buff *msg;
        void *hdr;
 
-       nfc_dbg("entry");
-
        msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
        if (!msg)
                return -ENOMEM;
@@ -249,8 +239,6 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
 {
        void *hdr;
 
-       nfc_dbg("entry");
-
        hdr = genlmsg_put(msg, pid, seq, &nfc_genl_family, flags,
                                                        NFC_CMD_GET_DEVICE);
        if (!hdr)
@@ -277,8 +265,6 @@ static int nfc_genl_dump_devices(struct sk_buff *skb,
        struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
        bool first_call = false;
 
-       nfc_dbg("entry");
-
        if (!iter) {
                first_call = true;
                iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
@@ -319,8 +305,6 @@ static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
 {
        struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
 
-       nfc_dbg("entry");
-
        nfc_device_iter_exit(iter);
        kfree(iter);
 
@@ -334,8 +318,6 @@ static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info)
        u32 idx;
        int rc = -ENOBUFS;
 
-       nfc_dbg("entry");
-
        if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
                return -EINVAL;
 
@@ -373,8 +355,6 @@ static int nfc_genl_dev_up(struct sk_buff *skb, struct genl_info *info)
        int rc;
        u32 idx;
 
-       nfc_dbg("entry");
-
        if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
                return -EINVAL;
 
@@ -396,8 +376,6 @@ static int nfc_genl_dev_down(struct sk_buff *skb, struct genl_info *info)
        int rc;
        u32 idx;
 
-       nfc_dbg("entry");
-
        if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
                return -EINVAL;
 
@@ -420,8 +398,6 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
        u32 idx;
        u32 protocols;
 
-       nfc_dbg("entry");
-
        if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
                !info->attrs[NFC_ATTR_PROTOCOLS])
                return -EINVAL;
@@ -451,8 +427,6 @@ static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info)
        int rc;
        u32 idx;
 
-       nfc_dbg("entry");
-
        if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
                return -EINVAL;
 
@@ -524,7 +498,7 @@ static int nfc_genl_rcv_nl_event(struct notifier_block *this,
        if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC)
                goto out;
 
-       nfc_dbg("NETLINK_URELEASE event from id %d", n->pid);
+       pr_debug("NETLINK_URELEASE event from id %d\n", n->pid);
 
        nfc_device_iter_init(&iter);
        dev = nfc_device_iter_next(&iter);
index d86583f..67d6050 100644 (file)
 #include <net/nfc/nfc.h>
 #include <net/sock.h>
 
-__printf(2, 3)
-int nfc_printk(const char *level, const char *fmt, ...);
-
-#define nfc_info(fmt, arg...) nfc_printk(KERN_INFO, fmt, ##arg)
-#define nfc_err(fmt, arg...) nfc_printk(KERN_ERR, fmt, ##arg)
-#define nfc_dbg(fmt, arg...) pr_debug(fmt "\n", ##arg)
-
 struct nfc_protocol {
        int id;
        struct proto *proto;
index ee7b2b3..68ecf3f 100644 (file)
@@ -21,6 +21,8 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <net/tcp_states.h>
 #include <linux/nfc.h>
 #include <linux/export.h>
@@ -29,7 +31,7 @@
 
 static void rawsock_write_queue_purge(struct sock *sk)
 {
-       nfc_dbg("sk=%p", sk);
+       pr_debug("sk=%p\n", sk);
 
        spin_lock_bh(&sk->sk_write_queue.lock);
        __skb_queue_purge(&sk->sk_write_queue);
@@ -39,7 +41,7 @@ static void rawsock_write_queue_purge(struct sock *sk)
 
 static void rawsock_report_error(struct sock *sk, int err)
 {
-       nfc_dbg("sk=%p err=%d", sk, err);
+       pr_debug("sk=%p err=%d\n", sk, err);
 
        sk->sk_shutdown = SHUTDOWN_MASK;
        sk->sk_err = -err;
@@ -52,7 +54,7 @@ static int rawsock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
 
-       nfc_dbg("sock=%p", sock);
+       pr_debug("sock=%p\n", sock);
 
        sock_orphan(sk);
        sock_put(sk);
@@ -68,14 +70,14 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
        struct nfc_dev *dev;
        int rc = 0;
 
-       nfc_dbg("sock=%p sk=%p flags=%d", sock, sk, flags);
+       pr_debug("sock=%p sk=%p flags=%d\n", sock, sk, flags);
 
        if (!addr || len < sizeof(struct sockaddr_nfc) ||
                addr->sa_family != AF_NFC)
                return -EINVAL;
 
-       nfc_dbg("addr dev_idx=%u target_idx=%u protocol=%u", addr->dev_idx,
-                                       addr->target_idx, addr->nfc_protocol);
+       pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n",
+                addr->dev_idx, addr->target_idx, addr->nfc_protocol);
 
        lock_sock(sk);
 
@@ -136,7 +138,7 @@ static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb,
 
        BUG_ON(in_irq());
 
-       nfc_dbg("sk=%p err=%d", sk, err);
+       pr_debug("sk=%p err=%d\n", sk, err);
 
        if (err)
                goto error;
@@ -172,7 +174,7 @@ static void rawsock_tx_work(struct work_struct *work)
        struct sk_buff *skb;
        int rc;
 
-       nfc_dbg("sk=%p target_idx=%u", sk, target_idx);
+       pr_debug("sk=%p target_idx=%u\n", sk, target_idx);
 
        if (sk->sk_shutdown & SEND_SHUTDOWN) {
                rawsock_write_queue_purge(sk);
@@ -198,7 +200,7 @@ static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct sk_buff *skb;
        int rc;
 
-       nfc_dbg("sock=%p sk=%p len=%zu", sock, sk, len);
+       pr_debug("sock=%p sk=%p len=%zu\n", sock, sk, len);
 
        if (msg->msg_namelen)
                return -EOPNOTSUPP;
@@ -239,7 +241,7 @@ static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
        int copied;
        int rc;
 
-       nfc_dbg("sock=%p sk=%p len=%zu flags=%d", sock, sk, len, flags);
+       pr_debug("sock=%p sk=%p len=%zu flags=%d\n", sock, sk, len, flags);
 
        skb = skb_recv_datagram(sk, flags, noblock, &rc);
        if (!skb)
@@ -283,7 +285,7 @@ static const struct proto_ops rawsock_ops = {
 
 static void rawsock_destruct(struct sock *sk)
 {
-       nfc_dbg("sk=%p", sk);
+       pr_debug("sk=%p\n", sk);
 
        if (sk->sk_state == TCP_ESTABLISHED) {
                nfc_deactivate_target(nfc_rawsock(sk)->dev,
@@ -294,7 +296,7 @@ static void rawsock_destruct(struct sock *sk)
        skb_queue_purge(&sk->sk_receive_queue);
 
        if (!sock_flag(sk, SOCK_DEAD)) {
-               nfc_err("Freeing alive NFC raw socket %p", sk);
+               pr_err("Freeing alive NFC raw socket %p\n", sk);
                return;
        }
 }
@@ -304,7 +306,7 @@ static int rawsock_create(struct net *net, struct socket *sock,
 {
        struct sock *sk;
 
-       nfc_dbg("sock=%p", sock);
+       pr_debug("sock=%p\n", sock);
 
        if (sock->type != SOCK_SEQPACKET)
                return -ESOCKTNOSUPPORT;
index 128677d..ca355e7 100644 (file)
@@ -220,18 +220,7 @@ static struct platform_driver rfkill_gpio_driver = {
        },
 };
 
-static int __init rfkill_gpio_init(void)
-{
-       return platform_driver_register(&rfkill_gpio_driver);
-}
-
-static void __exit rfkill_gpio_exit(void)
-{
-       platform_driver_unregister(&rfkill_gpio_driver);
-}
-
-module_init(rfkill_gpio_init);
-module_exit(rfkill_gpio_exit);
+module_platform_driver(rfkill_gpio_driver);
 
 MODULE_DESCRIPTION("gpio rfkill");
 MODULE_AUTHOR("NVIDIA");
index 3ca7277..2ebfe8d 100644 (file)
@@ -144,17 +144,7 @@ static struct platform_driver rfkill_regulator_driver = {
        },
 };
 
-static int __init rfkill_regulator_init(void)
-{
-       return platform_driver_register(&rfkill_regulator_driver);
-}
-module_init(rfkill_regulator_init);
-
-static void __exit rfkill_regulator_exit(void)
-{
-       platform_driver_unregister(&rfkill_regulator_driver);
-}
-module_exit(rfkill_regulator_exit);
+module_platform_driver(rfkill_regulator_driver);
 
 MODULE_AUTHOR("Guiming Zhuo <gmzhuo@gmail.com>");
 MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
index b7b7868..8c550df 100644 (file)
@@ -20,6 +20,7 @@
  * interface
  */
 #define MESH_PREQ_MIN_INT      10
+#define MESH_PERR_MIN_INT      100
 #define MESH_DIAM_TRAVERSAL_TIME 50
 
 /*
@@ -47,6 +48,7 @@ const struct mesh_config default_mesh_config = {
        .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS,
        .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT,
        .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT,
+       .dot11MeshHWMPperrMinInterval = MESH_PERR_MIN_INT,
        .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME,
        .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
        .path_refresh_time = MESH_PATH_REFRESH_TIME,
index a1cabde..0ee512b 100644 (file)
@@ -204,6 +204,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_HT_CAPABILITY_MASK] = {
                .len = NL80211_HT_CAPABILITY_LEN
        },
+       [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
 };
 
 /* policy for the key attributes */
@@ -904,6 +905,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
                CMD(sched_scan_start, START_SCHED_SCAN);
        CMD(probe_client, PROBE_CLIENT);
+       CMD(set_noack_map, SET_NOACK_MAP);
        if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
                i++;
                NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
@@ -1759,6 +1761,23 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
        return rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
 }
 
+static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       u16 noack_map;
+
+       if (!info->attrs[NL80211_ATTR_NOACK_MAP])
+               return -EINVAL;
+
+       if (!rdev->ops->set_noack_map)
+               return -EOPNOTSUPP;
+
+       noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
+
+       return rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map);
+}
+
 struct get_key_cookie {
        struct sk_buff *msg;
        int error;
@@ -3176,6 +3195,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
                        cur_params.dot11MeshHWMPactivePathTimeout);
        NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
                        cur_params.dot11MeshHWMPpreqMinInterval);
+       NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
+                       cur_params.dot11MeshHWMPperrMinInterval);
        NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
                        cur_params.dot11MeshHWMPnetDiameterTraversalTime);
        NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
@@ -3210,6 +3231,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
        [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
        [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
        [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
+       [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
        [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
        [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
        [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
@@ -3284,6 +3306,9 @@ do {\
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
                        mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
                        nla_get_u16);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
+                       mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
+                       nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
                        dot11MeshHWMPnetDiameterTraversalTime,
                        mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
@@ -5648,6 +5673,11 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
        setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
        setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
 
+       if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
+           !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
+                           nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
+                       return -EINVAL;
+
        if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
                /* parse additional setup parameters if given */
                err = nl80211_parse_mesh_setup(info, &setup);
@@ -6604,6 +6634,15 @@ static struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_WIPHY |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_SET_NOACK_MAP,
+               .doit = nl80211_set_noack_map,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {