Commit 77443951 authored by Johannes Berg's avatar Johannes Berg

Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next

parents b571a697 a910e4a9
......@@ -132,9 +132,7 @@
!Finclude/net/cfg80211.h cfg80211_send_rx_assoc
!Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
!Finclude/net/cfg80211.h cfg80211_send_deauth
!Finclude/net/cfg80211.h __cfg80211_send_deauth
!Finclude/net/cfg80211.h cfg80211_send_disassoc
!Finclude/net/cfg80211.h __cfg80211_send_disassoc
!Finclude/net/cfg80211.h cfg80211_ibss_joined
!Finclude/net/cfg80211.h cfg80211_connect_result
!Finclude/net/cfg80211.h cfg80211_roamed
......
......@@ -2299,6 +2299,11 @@ M: Jaya Kumar <jayakumar.alsa@gmail.com>
S: Maintained
F: sound/pci/cs5535audio/
CW1200 WLAN driver
M: Solomon Peachy <pizza@shaftnet.org>
S: Maintained
F: drivers/net/wireless/cw1200/
CX18 VIDEO4LINUX DRIVER
M: Andy Walls <awalls@md.metrocast.net>
L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
......
......@@ -72,12 +72,12 @@ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
* R/W ops.
**************************************************/
static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
size_t words)
{
int i;
for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
sprom[i] = bcma_read16(bus->drv_cc.core,
offset + (i * 2));
for (i = 0; i < words; i++)
sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));
}
/**************************************************
......@@ -124,29 +124,29 @@ static inline u8 bcma_crc8(u8 crc, u8 data)
return t[crc ^ data];
}
static u8 bcma_sprom_crc(const u16 *sprom)
static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
{
int word;
u8 crc = 0xFF;
for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
for (word = 0; word < words - 1; word++) {
crc = bcma_crc8(crc, sprom[word] & 0x00FF);
crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
}
crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
crc ^= 0xFF;
return crc;
}
static int bcma_sprom_check_crc(const u16 *sprom)
static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
{
u8 crc;
u8 expected_crc;
u16 tmp;
crc = bcma_sprom_crc(sprom);
tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
crc = bcma_sprom_crc(sprom, words);
tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
if (crc != expected_crc)
return -EPROTO;
......@@ -154,21 +154,25 @@ static int bcma_sprom_check_crc(const u16 *sprom)
return 0;
}
static int bcma_sprom_valid(const u16 *sprom)
static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom,
size_t words)
{
u16 revision;
int err;
err = bcma_sprom_check_crc(sprom);
err = bcma_sprom_check_crc(sprom, words);
if (err)
return err;
revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
if (revision != 8 && revision != 9) {
revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
if (revision != 8 && revision != 9 && revision != 10) {
pr_err("Unsupported SPROM revision: %d\n", revision);
return -ENOENT;
}
bus->sprom.revision = revision;
bcma_debug(bus, "Found SPROM revision %d\n", revision);
return 0;
}
......@@ -208,9 +212,6 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
ARRAY_SIZE(bus->sprom.core_pwr_info));
bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
SSB_SPROM_REVISION_REV;
for (i = 0; i < 3; i++) {
v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
*(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
......@@ -502,7 +503,6 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
case BCMA_CHIP_ID_BCM4331:
present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
break;
case BCMA_CHIP_ID_BCM43224:
case BCMA_CHIP_ID_BCM43225:
/* for these chips OTP is always available */
......@@ -550,7 +550,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
{
u16 offset = BCMA_CC_SPROM;
u16 *sprom;
int err = 0;
size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
SSB_SPROMSIZE_WORDS_R10, };
int i, err = 0;
if (!bus->drv_cc.core)
return -EOPNOTSUPP;
......@@ -579,32 +581,37 @@ int bcma_sprom_get(struct bcma_bus *bus)
}
}
sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
GFP_KERNEL);
if (!sprom)
return -ENOMEM;
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
bcma_debug(bus, "SPROM offset 0x%x\n", offset);
bcma_sprom_read(bus, offset, sprom);
for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
size_t words = sprom_sizes[i];
sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
if (!sprom)
return -ENOMEM;
bcma_sprom_read(bus, offset, sprom, words);
err = bcma_sprom_valid(bus, sprom, words);
if (!err)
break;
kfree(sprom);
}
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
err = bcma_sprom_valid(sprom);
if (err) {
bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
goto out;
} else {
bcma_sprom_extract_r8(bus, sprom);
kfree(sprom);
}
bcma_sprom_extract_r8(bus, sprom);
out:
kfree(sprom);
return err;
}
......@@ -280,5 +280,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/mwifiex/Kconfig"
source "drivers/net/wireless/cw1200/Kconfig"
endif # WLAN
......@@ -57,3 +57,5 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/
obj-$(CONFIG_BRCMFMAC) += brcm80211/
obj-$(CONFIG_BRCMSMAC) += brcm80211/
obj-$(CONFIG_CW1200) += cw1200/
......@@ -84,14 +84,6 @@ config ATH9K_DFS_CERTIFIED
developed. At this point enabling this option won't do anything
except increase code size.
config ATH9K_MAC_DEBUG
bool "Atheros MAC statistics"
depends on ATH9K_DEBUGFS
default y
---help---
This option enables collection of statistics for Rx/Tx status
data and some other MAC related statistics
config ATH9K_RATE_CONTROL
bool "Atheros ath9k rate control"
depends on ATH9K
......
......@@ -454,6 +454,8 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
if (accum_cnt <= thresh_accum_cnt)
continue;
max_index++;
/* sum(tx amplitude) */
accum_tx = ((data_L[i] >> 16) & 0xffff) |
((data_U[i] & 0x7ff) << 16);
......@@ -468,20 +470,21 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
accum_tx <<= scale_factor;
accum_rx <<= scale_factor;
x_est[i + 1] = (((accum_tx + accum_cnt) / accum_cnt) + 32) >>
scale_factor;
x_est[max_index] =
(((accum_tx + accum_cnt) / accum_cnt) + 32) >>
scale_factor;
Y[i + 1] = ((((accum_rx + accum_cnt) / accum_cnt) + 32) >>
Y[max_index] =
((((accum_rx + accum_cnt) / accum_cnt) + 32) >>
scale_factor) +
(1 << scale_factor) * max_index + 16;
(1 << scale_factor) * i + 16;
if (accum_ang >= (1 << 26))
accum_ang -= 1 << 27;
theta[i + 1] = ((accum_ang * (1 << scale_factor)) + accum_cnt) /
accum_cnt;
max_index++;
theta[max_index] =
((accum_ang * (1 << scale_factor)) + accum_cnt) /
accum_cnt;
}
/*
......
......@@ -646,6 +646,7 @@ enum sc_op_flags {
SC_OP_ANI_RUN,
SC_OP_PRIM_STA_VIF,
SC_OP_HW_RESET,
SC_OP_SCANNING,
};
/* Powersave flags */
......@@ -759,7 +760,6 @@ struct ath_softc {
struct rchan *rfs_chan_spec_scan;
enum spectral_mode spectral_mode;
struct ath_spec_scan spec_config;
int scanning;
#ifdef CONFIG_PM_SLEEP
atomic_t wow_got_bmiss_intr;
......
......@@ -39,7 +39,8 @@ static void ath9k_beaconq_config(struct ath_softc *sc)
ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) {
/* Always burst out beacon and CAB traffic. */
qi.tqi_aifs = 1;
qi.tqi_cwmin = 0;
......@@ -273,7 +274,8 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)
u64 tsf;
int slot;
if (sc->sc_ah->opmode != NL80211_IFTYPE_AP) {
if (sc->sc_ah->opmode != NL80211_IFTYPE_AP &&
sc->sc_ah->opmode != NL80211_IFTYPE_MESH_POINT) {
ath_dbg(common, BEACON, "slot 0, tsf: %llu\n",
ath9k_hw_gettsf64(sc->sc_ah));
return 0;
......@@ -765,10 +767,10 @@ void ath9k_set_beacon(struct ath_softc *sc)
switch (sc->sc_ah->opmode) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
ath9k_beacon_config_ap(sc, cur_conf);
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
ath9k_beacon_config_adhoc(sc, cur_conf);
break;
case NL80211_IFTYPE_STATION:
......
This diff is collapsed.
......@@ -294,13 +294,6 @@ struct ath9k_debug {
struct dentry *debugfs_phy;
u32 regidx;
struct ath_stats stats;
#ifdef CONFIG_ATH9K_MAC_DEBUG
spinlock_t samp_lock;
struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES];
u8 sampidx;
u8 tsidx;
u8 rsidx;
#endif
};
int ath9k_init_debug(struct ath_hw *ah);
......@@ -359,17 +352,4 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc,
#endif /* CONFIG_ATH9K_DEBUGFS */
#ifdef CONFIG_ATH9K_MAC_DEBUG
void ath9k_debug_samp_bb_mac(struct ath_softc *sc);
#else
static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc)
{
}
#endif
#endif /* DEBUG_H */
......@@ -208,6 +208,9 @@ struct ath9k_htc_target_rx_stats {
case NL80211_IFTYPE_AP: \
_priv->num_ap_vif++; \
break; \
case NL80211_IFTYPE_MESH_POINT: \
_priv->num_mbss_vif++; \
break; \
default: \
break; \
} \
......@@ -224,6 +227,9 @@ struct ath9k_htc_target_rx_stats {
case NL80211_IFTYPE_AP: \
_priv->num_ap_vif--; \
break; \
case NL80211_IFTYPE_MESH_POINT: \
_priv->num_mbss_vif--; \
break; \
default: \
break; \
} \
......@@ -450,6 +456,7 @@ struct ath9k_htc_priv {
u8 sta_slot;
u8 vif_sta_pos[ATH9K_HTC_MAX_VIF];
u8 num_ibss_vif;
u8 num_mbss_vif;
u8 num_sta_vif;
u8 num_sta_assoc_vif;
u8 num_ap_vif;
......
......@@ -28,7 +28,8 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
ath9k_hw_get_txq_props(ah, priv->beaconq, &qi);
if (priv->ah->opmode == NL80211_IFTYPE_AP) {
if (priv->ah->opmode == NL80211_IFTYPE_AP ||
priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) {
qi.tqi_aifs = 1;
qi.tqi_cwmin = 0;
qi.tqi_cwmax = 0;
......@@ -628,6 +629,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
case NL80211_IFTYPE_ADHOC:
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
ath9k_htc_beacon_config_ap(priv, cur_conf);
break;
......@@ -649,6 +651,7 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv)
case NL80211_IFTYPE_ADHOC:
ath9k_htc_beacon_config_adhoc(priv, cur_conf);
break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
ath9k_htc_beacon_config_ap(priv, cur_conf);
break;
......
......@@ -698,7 +698,8 @@ static const struct ieee80211_iface_limit if_limits[] = {
{ .max = 2, .types = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT) },
{ .max = 2, .types = BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) },
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_MESH_POINT) },
};
static const struct ieee80211_iface_combination if_comb = {
......@@ -721,6 +722,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
hw->wiphy->interface_modes =
......@@ -728,7 +730,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT);
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_MESH_POINT);
hw->wiphy->iface_combinations = &if_comb;
hw->wiphy->n_iface_combinations = 1;
......
......@@ -113,7 +113,9 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
struct ath9k_htc_priv *priv = data;
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
if ((vif->type == NL80211_IFTYPE_AP) && bss_conf->enable_beacon)
if ((vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_MESH_POINT) &&
bss_conf->enable_beacon)
priv->reconfig_beacon = true;
if (bss_conf->assoc) {
......@@ -180,6 +182,8 @@ static void ath9k_htc_set_opmode(struct ath9k_htc_priv *priv)
priv->ah->opmode = NL80211_IFTYPE_ADHOC;
else if (priv->num_ap_vif)
priv->ah->opmode = NL80211_IFTYPE_AP;
else if (priv->num_mbss_vif)
priv->ah->opmode = NL80211_IFTYPE_MESH_POINT;
else
priv->ah->opmode = NL80211_IFTYPE_STATION;
......@@ -1052,6 +1056,9 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
case NL80211_IFTYPE_AP:
hvif.opmode = HTC_M_HOSTAP;
break;
case NL80211_IFTYPE_MESH_POINT:
hvif.opmode = HTC_M_WDS; /* close enough */
break;
default:
ath_err(common,
"Interface type %d not yet supported\n", vif->type);
......@@ -1084,6 +1091,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
INC_VIF(priv, vif->type);
if ((vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_MESH_POINT) ||
(vif->type == NL80211_IFTYPE_ADHOC))
ath9k_htc_assign_bslot(priv, vif);
......@@ -1134,6 +1142,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
DEC_VIF(priv, vif->type);
if ((vif->type == NL80211_IFTYPE_AP) ||
vif->type == NL80211_IFTYPE_MESH_POINT ||
(vif->type == NL80211_IFTYPE_ADHOC))
ath9k_htc_remove_bslot(priv, vif);
......@@ -1525,9 +1534,10 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) {
/*
* Disable SWBA interrupt only if there are no
* AP/IBSS interfaces.
* concurrent AP/mesh or IBSS interfaces.
*/
if ((priv->num_ap_vif <= 1) || priv->num_ibss_vif) {
if ((priv->num_ap_vif + priv->num_mbss_vif <= 1) ||
priv->num_ibss_vif) {
ath_dbg(common, CONFIG,
"Beacon disabled for BSS: %pM\n",
bss_conf->bssid);
......@@ -1538,12 +1548,15 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BEACON_INT) {
/*
* Reset the HW TSF for the first AP interface.
* Reset the HW TSF for the first AP or mesh interface.
*/
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
(priv->nvifs == 1) &&
(priv->num_ap_vif == 1) &&
(vif->type == NL80211_IFTYPE_AP)) {
if (priv->nvifs == 1 &&
((priv->ah->opmode == NL80211_IFTYPE_AP &&
vif->type == NL80211_IFTYPE_AP &&
priv->num_ap_vif == 1) ||
(priv->ah->opmode == NL80211_IFTYPE_MESH_POINT &&
vif->type == NL80211_IFTYPE_MESH_POINT &&
priv->num_mbss_vif == 1))) {
set_bit(OP_TSF_RESET, &priv->op_flags);
}
ath_dbg(common, CONFIG,
......
......@@ -887,7 +887,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
if (priv->rxfilter & FIF_PSPOLL)
rfilt |= ATH9K_RX_FILTER_PSPOLL;
if (priv->nvifs > 1)
if (priv->nvifs > 1 || priv->rxfilter & FIF_OTHER_BSS)
rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
return rfilt;
......
......@@ -1245,10 +1245,10 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
switch (opmode) {
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
set |= AR_STA_ID1_ADHOC;
REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
set |= AR_STA_ID1_STA_AP;
/* fall through */
......@@ -2246,12 +2246,12 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
switch (ah->opmode) {
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
REG_SET_BIT(ah, AR_TXCFG,
AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon +
TU_TO_USEC(ah->atim_window ? ah->atim_window : 1));
flags |= AR_NDP_TIMER_EN;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon);
REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon -
......
......@@ -613,9 +613,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
spin_lock_init(&sc->sc_serial_rw);
spin_lock_init(&sc->sc_pm_lock);
mutex_init(&sc->mutex);
#ifdef CONFIG_ATH9K_MAC_DEBUG
spin_lock_init(&sc->debug.samp_lock);
#endif
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
(unsigned long)sc);
......
......@@ -418,7 +418,6 @@ void ath_ani_calibrate(unsigned long data)
longcal ? "long" : "", shortcal ? "short" : "",
aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
ath9k_debug_samp_bb_mac(sc);
ath9k_ps_restore(sc);
set_timer:
......
......@@ -193,7 +193,6 @@ static bool ath_prepare_reset(struct ath_softc *sc)
ath_stop_ani(sc);
del_timer_sync(&sc->rx_poll_timer);
ath9k_debug_samp_bb_mac(sc);
ath9k_hw_disable_interrupts(ah);
if (!ath_drain_all_txq(sc))
......@@ -1273,7 +1272,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
curchan->center_freq);
} else {
/* perform spectral scan if requested. */
if (sc->scanning &&
if (test_bit(SC_OP_SCANNING, &sc->sc_flags) &&
sc->spectral_mode == SPECTRAL_CHANSCAN)
ath9k_spectral_scan_trigger(hw);
}
......@@ -1689,7 +1688,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
int ret = 0;
local_bh_disable();
mutex_lock(&sc->mutex);
switch (action) {
case IEEE80211_AMPDU_RX_START:
......@@ -1720,7 +1719,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
}
local_bh_enable();
mutex_unlock(&sc->mutex);
return ret;
}
......@@ -2339,15 +2338,13 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
sc->scanning = 1;
set_bit(SC_OP_SCANNING, &sc->sc_flags);
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
sc->scanning = 0;
clear_bit(SC_OP_SCANNING, &sc->sc_flags);
}
struct ieee80211_ops ath9k_ops = {
......
......@@ -27,3 +27,15 @@ config WIL6210_ISR_COR
self-clear when accessed for debug purposes, it makes
such monitoring impossible.
Say y unless you debug interrupts
config ATH6KL_TRACING
bool "wil6210 tracing support"
depends on WIL6210
depends on EVENT_TRACING
default y
---help---
Say Y here to enable tracepoints for the wil6210 driver
using the kernel tracing infrastructure. Select this
option if you are interested in debugging the driver.
If unsure, say Y to make it easier to debug problems.
obj-$(CONFIG_WIL6210) += wil6210.o
wil6210-objs := main.o
wil6210-objs += netdev.o
wil6210-objs += cfg80211.o
wil6210-objs += pcie_bus.o
wil6210-objs += debugfs.o
wil6210-objs += wmi.o
wil6210-objs += interrupt.o
wil6210-objs += txrx.o
wil6210-y := main.o
wil6210-y += netdev.o
wil6210-y += cfg80211.o
wil6210-y += pcie_bus.o
wil6210-y += debugfs.o
wil6210-y += wmi.o
wil6210-y += interrupt.o
wil6210-y += txrx.o
wil6210-y += debug.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
subdir-ccflags-y += -Werror
endif
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
subdir-ccflags-y += -D__CHECK_ENDIAN__
......@@ -322,12 +322,16 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
* FW don't support scan after connection attempt
*/
set_bit(wil_status_dontscan, &wil->status);
set_bit(wil_status_fwconnecting, &wil->status);
rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
if (rc == 0) {
/* Connect can take lots of time */
mod_timer(&wil->connect_timer,
jiffies + msecs_to_jiffies(2000));
} else {
clear_bit(wil_status_dontscan, &wil->status);
clear_bit(wil_status_fwconnecting, &wil->status);
}
out:
......
/*
* Copyright (c) 2013 Qualcomm Atheros, 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 "wil6210.h"
#include "trace.h"
int wil_err(struct wil6210_priv *wil, const char *fmt, ...)
{
struct net_device *ndev = wil_to_ndev(wil);
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
int ret;
va_start(args, fmt);
vaf.va = &args;
ret = netdev_err(ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf);
va_end(args);
return ret;
}
int wil_info(struct wil6210_priv *wil, const char *fmt, ...)
{
struct net_device *ndev = wil_to_ndev(wil);
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
int ret;
va_start(args, fmt);
vaf.va = &args;
ret = netdev_info(ndev, "%pV", &vaf);
trace_wil6210_log_info(&vaf);
va_end(args);
return ret;
}
int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
};
va_list args;
va_start(args, fmt);
vaf.va = &args;
trace_wil6210_log_dbg(&vaf);
va_end(args);
return 0;
}
......@@ -418,9 +418,15 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
if (skb) {
unsigned char printbuf[16 * 3 + 2];
int i = 0;
int len = skb_headlen(skb);
int len = le16_to_cpu(d->dma.length);
void *p = skb->data;
if (len != skb_headlen(skb)) {
seq_printf(s, "!!! len: desc = %d skb = %d\n",
len, skb_headlen(skb));
len = min_t(int, len, skb_headlen(skb));
}
seq_printf(s, " len = %d\n", len);
while (i < len) {
......
......@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include "wil6210.h"
#include "trace.h"
/**
* Theory of operation:
......@@ -103,14 +104,14 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
clear_bit(wil_status_irqen, &wil->status);
}
static void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
{
iowrite32(WIL6210_IMC_TX, wil->csr +
HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, IMC));
}
static void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
{
iowrite32(WIL6210_IMC_RX, wil->csr +
HOSTADDR(RGF_DMA_EP_RX_ICR) +
......@@ -168,6 +169,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICR));
trace_wil6210_irq_rx(isr);
wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
if (!isr) {
......@@ -180,13 +182,14 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
wil_dbg_irq(wil, "RX done\n");
isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
wil_rx_handle(wil);
wil_dbg_txrx(wil, "NAPI schedule\n");
napi_schedule(&wil->napi_rx);
}
if (isr)
wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
wil6210_unmask_irq_rx(wil);
/* Rx IRQ will be enabled when NAPI processing finished */
return IRQ_HANDLED;
}
......@@ -198,6 +201,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, ICR));
trace_wil6210_irq_tx(isr);
wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
if (!isr) {
......@@ -208,23 +212,17 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
wil6210_mask_irq_tx(wil);
if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
uint i;
wil_dbg_irq(wil, "TX done\n");
napi_schedule(&wil->napi_tx);
isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
for (i = 0; i < 24; i++) {
u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i);
if (isr & mask) {
isr &= ~mask;
wil_dbg_irq(wil, "TX done(%i)\n", i);
wil_tx_complete(wil, i);
}
}
/* clear also all VRING interrupts */
isr &= ~(BIT(25) - 1UL);
}
if (isr)
wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
wil6210_unmask_irq_tx(wil);
/* Tx IRQ will be enabled when NAPI processing finished */
return IRQ_HANDLED;
}
......@@ -256,6 +254,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICR));
trace_wil6210_irq_misc(isr);
wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr);
if (!isr) {
......@@ -301,6 +300,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
struct wil6210_priv *wil = cookie;
u32 isr = wil->isr_misc;
trace_wil6210_irq_misc_thread(isr);
wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
if (isr & ISR_MISC_FW_ERROR) {
......@@ -408,6 +408,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)
if (wil6210_debug_irq_mask(wil, pseudo_cause))
return IRQ_NONE;
trace_wil6210_irq_pseudo(pseudo_cause);
wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause);
wil6210_mask_irq_pseudo(wil);
......
......@@ -56,27 +56,21 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
{
uint i;
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
wil_dbg_misc(wil, "%s()\n", __func__);
wil_link_off(wil);
clear_bit(wil_status_fwconnected, &wil->status);
switch (wdev->sme_state) {
case CFG80211_SME_CONNECTED:
cfg80211_disconnected(ndev, WLAN_STATUS_UNSPECIFIED_FAILURE,
if (test_bit(wil_status_fwconnected, &wil->status)) {
clear_bit(wil_status_fwconnected, &wil->status);
cfg80211_disconnected(ndev,
WLAN_STATUS_UNSPECIFIED_FAILURE,
NULL, 0, GFP_KERNEL);
break;
case CFG80211_SME_CONNECTING:
} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
break;
default:
break;
}
clear_bit(wil_status_fwconnecting, &wil->status);
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
wil_vring_fini_tx(wil, i);
......@@ -365,6 +359,9 @@ static int __wil_up(struct wil6210_priv *wil)
/* Rx VRING. After MAC and beacon */
wil_rx_init(wil);
napi_enable(&wil->napi_rx);
napi_enable(&wil->napi_tx);
return 0;
}
......@@ -381,6 +378,9 @@ int wil_up(struct wil6210_priv *wil)
static int __wil_down(struct wil6210_priv *wil)
{
napi_disable(&wil->napi_rx);
napi_disable(&wil->napi_tx);
if (wil->scan_request) {
cfg80211_scan_done(wil->scan_request, true);
wil->scan_request = NULL;
......
......@@ -40,6 +40,55 @@ static const struct net_device_ops wil_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
{
struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
napi_rx);
int quota = budget;
int done;
wil_rx_handle(wil, &quota);
done = budget - quota;
if (done <= 1) { /* burst ends - only one packet processed */
napi_complete(napi);
wil6210_unmask_irq_rx(wil);
wil_dbg_txrx(wil, "NAPI RX complete\n");
}
wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done);
return done;
}
static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
{
struct wil6210_priv *wil = container_of(napi, struct wil6210_priv,
napi_tx);
int tx_done = 0;
uint i;
/* always process ALL Tx complete, regardless budget - it is fast */
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
struct vring *vring = &wil->vring_tx[i];
if (!vring->va)
continue;
tx_done += wil_tx_complete(wil, i);
}
if (tx_done <= 1) { /* burst ends - only one packet processed */
napi_complete(napi);
wil6210_unmask_irq_tx(wil);
wil_dbg_txrx(wil, "NAPI TX complete\n");
}
wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done);
return min(tx_done, budget);
}
void *wil_if_alloc(struct device *dev, void __iomem *csr)
{
struct net_device *ndev;
......@@ -81,6 +130,11 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
WIL6210_NAPI_BUDGET);
netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);
wil_link_off(wil);
return wil;
......
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/module.h>
#define CREATE_TRACE_POINTS
#include "trace.h"
/*
* Copyright (c) 2013 Qualcomm Atheros, 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.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM wil6210
#if !defined(WIL6210_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#define WIL6210_TRACE_H
#include <linux/tracepoint.h>
#include "wil6210.h"
#include "txrx.h"
/* create empty functions when tracing is disabled */
#if !defined(CONFIG_WIL6210_TRACING) || 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 /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */
DECLARE_EVENT_CLASS(wil6210_wmi,
TP_PROTO(u16 id, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len),
TP_STRUCT__entry(
__field(u16, id)
__field(u16, buf_len)
__dynamic_array(u8, buf, buf_len)
),
TP_fast_assign(
__entry->id = id;
__entry->buf_len = buf_len;
memcpy(__get_dynamic_array(buf), buf, buf_len);
),
TP_printk(
"id 0x%04x len %d",
__entry->id, __entry->buf_len
)
);
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd,
TP_PROTO(u16 id, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len)
);
DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event,
TP_PROTO(u16 id, void *buf, u16 buf_len),
TP_ARGS(id, buf, buf_len)
);
#define WIL6210_MSG_MAX (200)
DECLARE_EVENT_CLASS(wil6210_log_event,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf),
TP_STRUCT__entry(
__dynamic_array(char, msg, WIL6210_MSG_MAX)
),
TP_fast_assign(
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
WIL6210_MSG_MAX,
vaf->fmt,
*vaf->va) >= WIL6210_MSG_MAX);
),
TP_printk("%s", __get_str(msg))
);
DEFINE_EVENT(wil6210_log_event, wil6210_log_err,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(wil6210_log_event, wil6210_log_info,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(wil6210_log_event, wil6210_log_dbg,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
#define wil_pseudo_irq_cause(x) __print_flags(x, "|", \
{BIT_DMA_PSEUDO_CAUSE_RX, "Rx" }, \
{BIT_DMA_PSEUDO_CAUSE_TX, "Tx" }, \
{BIT_DMA_PSEUDO_CAUSE_MISC, "Misc" })
TRACE_EVENT(wil6210_irq_pseudo,
TP_PROTO(u32 x),
TP_ARGS(x),
TP_STRUCT__entry(
__field(u32, x)
),
TP_fast_assign(
__entry->x = x;
),
TP_printk("cause 0x%08x : %s", __entry->x,
wil_pseudo_irq_cause(__entry->x))
);
DECLARE_EVENT_CLASS(wil6210_irq,
TP_PROTO(u32 x),
TP_ARGS(x),
TP_STRUCT__entry(
__field(u32, x)
),
TP_fast_assign(
__entry->x = x;
),
TP_printk("cause 0x%08x", __entry->x)
);
DEFINE_EVENT(wil6210_irq, wil6210_irq_rx,
TP_PROTO(u32 x),
TP_ARGS(x)
);
DEFINE_EVENT(wil6210_irq, wil6210_irq_tx,
TP_PROTO(u32 x),
TP_ARGS(x)
);
DEFINE_EVENT(wil6210_irq, wil6210_irq_misc,
TP_PROTO(u32 x),
TP_ARGS(x)
);
DEFINE_EVENT(wil6210_irq, wil6210_irq_misc_thread,
TP_PROTO(u32 x),
TP_ARGS(x)
);
TRACE_EVENT(wil6210_rx,
TP_PROTO(u16 index, struct vring_rx_desc *d),
TP_ARGS(index, d),
TP_STRUCT__entry(
__field(u16, index)
__field(unsigned int, len)
__field(u8, mid)
__field(u8, cid)
__field(u8, tid)
__field(u8, type)
__field(u8, subtype)
__field(u16, seq)
__field(u8, mcs)
),
TP_fast_assign(
__entry->index = index;
__entry->len = d->dma.length;
__entry->mid = wil_rxdesc_mid(d);
__entry->cid = wil_rxdesc_cid(d);
__entry->tid = wil_rxdesc_tid(d);
__entry->type = wil_rxdesc_ftype(d);
__entry->subtype = wil_rxdesc_subtype(d);
__entry->seq = wil_rxdesc_seq(d);
__entry->mcs = wil_rxdesc_mcs(d);
),
TP_printk("index %d len %d mid %d cid %d tid %d mcs %d seq 0x%03x"
" type 0x%1x subtype 0x%1x", __entry->index, __entry->len,
__entry->mid, __entry->cid, __entry->tid, __entry->mcs,
__entry->seq, __entry->type, __entry->subtype)
);
TRACE_EVENT(wil6210_tx,
TP_PROTO(u8 vring, u16 index, unsigned int len, u8 frags),
TP_ARGS(vring, index, len, frags),
TP_STRUCT__entry(
__field(u8, vring)
__field(u8, frags)
__field(u16, index)
__field(unsigned int, len)
),
TP_fast_assign(
__entry->vring = vring;
__entry->frags = frags;
__entry->index = index;
__entry->len = len;
),
TP_printk("vring %d index %d len %d frags %d",
__entry->vring, __entry->index, __entry->len, __entry->frags)
);
TRACE_EVENT(wil6210_tx_done,
TP_PROTO(u8 vring, u16 index, unsigned int len, u8 err),
TP_ARGS(vring, index, len, err),
TP_STRUCT__entry(
__field(u8, vring)
__field(u8, err)
__field(u16, index)
__field(unsigned int, len)
),
TP_fast_assign(
__entry->vring = vring;
__entry->index = index;
__entry->len = len;
__entry->err = err;
),
TP_printk("vring %d index %d len %d err 0x%02x",
__entry->vring, __entry->index, __entry->len,
__entry->err)
);
#endif /* WIL6210_TRACE_H || TRACE_HEADER_MULTI_READ*/
#if defined(CONFIG_WIL6210_TRACING) && !defined(__CHECKER__)
/* we don't want to use include/trace/events */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace
/* This part must be outside protection */
#include <trace/define_trace.h>
#endif /* defined(CONFIG_WIL6210_TRACING) && !defined(__CHECKER__) */
This diff is collapsed.
......@@ -27,6 +27,28 @@
#define WIL6210_RTAP_SIZE (128)
/* Tx/Rx path */
/*
* Common representation of physical address in Vring
*/
struct vring_dma_addr {
__le32 addr_low;
__le16 addr_high;
} __packed;
static inline dma_addr_t wil_desc_addr(struct vring_dma_addr *addr)
{
return le32_to_cpu(addr->addr_low) |
((u64)le16_to_cpu(addr->addr_high) << 32);
}
static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
dma_addr_t pa)
{
addr->addr_low = cpu_to_le32(lower_32_bits(pa));
addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa));
}
/*
* Tx descriptor - MAC part
* [dword 0]
......@@ -216,13 +238,12 @@ struct vring_tx_mac {
struct vring_tx_dma {
u32 d0;
u32 addr_low;
u16 addr_high;
struct vring_dma_addr addr;
u8 ip_length;
u8 b11; /* 0..6: mac_length; 7:ip_version */
u8 error; /* 0..2: err; 3..7: reserved; */
u8 status; /* 0: used; 1..7; reserved */
u16 length;
__le16 length;
} __packed;
/*
......@@ -315,13 +336,12 @@ struct vring_rx_mac {
struct vring_rx_dma {
u32 d0;
u32 addr_low;
u16 addr_high;
struct vring_dma_addr addr;
u8 ip_length;
u8 b11;
u8 error;
u8 status;
u16 length;
__le16 length;
} __packed;
struct vring_tx_desc {
......
......@@ -34,9 +34,11 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL6210_MEM_SIZE (2*1024*1024UL)
#define WIL6210_RX_RING_SIZE (128)
#define WIL6210_TX_RING_SIZE (128)
#define WIL6210_MAX_TX_RINGS (24)
#define WIL6210_RX_RING_SIZE (128)
#define WIL6210_TX_RING_SIZE (128)
#define WIL6210_MAX_TX_RINGS (24) /* HW limit */
#define WIL6210_MAX_CID (8) /* HW limit */
#define WIL6210_NAPI_BUDGET (16) /* arbitrary */
/* Hardware definitions begin */
......@@ -184,6 +186,7 @@ struct vring {
enum { /* for wil6210_priv.status */
wil_status_fwready = 0,
wil_status_fwconnecting,
wil_status_fwconnected,
wil_status_dontscan,
wil_status_reset_done,
......@@ -239,6 +242,8 @@ struct wil6210_priv {
* - consumed in thread by wmi_event_worker
*/
spinlock_t wmi_ev_lock;
struct napi_struct napi_rx;
struct napi_struct napi_tx;
/* DMA related */
struct vring vring_rx;
struct vring vring_tx[WIL6210_MAX_TX_RINGS];
......@@ -267,9 +272,13 @@ struct wil6210_priv {
#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
#define wil_dbg(wil, fmt, arg...) netdev_dbg(wil_to_ndev(wil), fmt, ##arg)
#define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg)
#define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg)
int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
int wil_err(struct wil6210_priv *wil, const char *fmt, ...);
int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg(wil, fmt, arg...) do { \
netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
wil_dbg_trace(wil, fmt, ##arg); \
} while (0)
#define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg)
#define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
......@@ -356,10 +365,12 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
void wil_tx_complete(struct wil6210_priv *wil, int ringid);
int wil_tx_complete(struct wil6210_priv *wil, int ringid);
void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
/* RX API */
void wil_rx_handle(struct wil6210_priv *wil);
void wil_rx_handle(struct wil6210_priv *wil, int *quota);
void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
int wil_iftype_nl2wmi(enum nl80211_iftype type);
......
......@@ -20,6 +20,7 @@
#include "wil6210.h"
#include "txrx.h"
#include "wmi.h"
#include "trace.h"
/**
* WMI event receiving - theory of operations
......@@ -246,6 +247,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
iowrite32(r->head = next_head, wil->csr + HOST_MBOX +
offsetof(struct wil6210_mbox_ctl, tx.head));
trace_wil6210_wmi_cmd(cmdid, buf, len);
/* interrupt to FW */
iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT);
......@@ -406,7 +409,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
if (wdev->sme_state != CFG80211_SME_CONNECTING) {
if (!test_bit(wil_status_fwconnecting, &wil->status)) {
wil_err(wil, "Not in connecting state\n");
return;
}
......@@ -430,6 +433,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
}
clear_bit(wil_status_fwconnecting, &wil->status);
set_bit(wil_status_fwconnected, &wil->status);
/* FIXME FW can transmit only ucast frames to peer */
......@@ -635,8 +639,9 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
hdr.flags);
if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
(len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
wil_dbg_wmi(wil, "WMI event 0x%04x\n",
evt->event.wmi.id);
u16 id = le16_to_cpu(evt->event.wmi.id);
wil_dbg_wmi(wil, "WMI event 0x%04x\n", id);
trace_wil6210_wmi_event(id, &evt->event.wmi, len);
}
wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
&evt->event.hdr, sizeof(hdr) + len, true);
......@@ -724,7 +729,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
.bcon_interval = cpu_to_le16(bi),
.network_type = wmi_nettype,
.disable_sec_offload = 1,
.channel = chan,
.channel = chan - 1,
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
......
......@@ -606,7 +606,8 @@ static int brcmf_sdio_pd_remove(struct platform_device *pdev)
static struct platform_driver brcmf_sdio_pd = {
.remove = brcmf_sdio_pd_remove,
.driver = {
.name = BRCMFMAC_SDIO_PDATA_NAME
.name = BRCMFMAC_SDIO_PDATA_NAME,
.owner = THIS_MODULE,
}
};
......
config CW1200
tristate "CW1200 WLAN support"
depends on MAC80211 && CFG80211
help
This is a driver for the ST-E CW1100 & CW1200 WLAN chipsets.
This option just enables the driver core, see below for
specific bus support.
if CW1200
config CW1200_WLAN_SDIO
tristate "Support SDIO platforms"
depends on CW1200 && MMC
help
Enable support for the CW1200 connected via an SDIO bus.
config CW1200_WLAN_SPI
tristate "Support SPI platforms"
depends on CW1200 && SPI
help
Enables support for the CW1200 connected via a SPI bus.
config CW1200_WLAN_SAGRAD
tristate "Support Sagrad SG901-1091/1098 modules"
depends on CW1200_WLAN_SDIO
help
This provides the platform data glue to support the
Sagrad SG901-1091/1098 modules in their standard SDIO EVK.
It also includes example SPI platform data.
menu "Driver debug features"
depends on CW1200 && DEBUG_FS
config CW1200_ETF
bool "Enable CW1200 Engineering Test Framework hooks"
help
If you don't know what this is, just say N.
config CW1200_ITP
bool "Enable ITP access"
help
If you don't know what this is, just say N.
endmenu
endif
cw1200_core-y := \
fwio.o \
txrx.o \
main.o \
queue.o \
hwio.o \
bh.o \
wsm.o \
sta.o \
scan.o \
pm.o \
debug.o
cw1200_core-$(CONFIG_CW1200_ITP) += itp.o
# CFLAGS_sta.o += -DDEBUG
cw1200_wlan_sdio-y := cw1200_sdio.o
cw1200_wlan_spi-y := cw1200_spi.o
cw1200_wlan_sagrad-y := cw1200_sagrad.o
obj-$(CONFIG_CW1200) += cw1200_core.o
obj-$(CONFIG_CW1200_WLAN_SDIO) += cw1200_wlan_sdio.o
obj-$(CONFIG_CW1200_WLAN_SPI) += cw1200_wlan_spi.o
obj-$(CONFIG_CW1200_WLAN_SAGRAD) += cw1200_wlan_sagrad.o
This diff is collapsed.
/*
* Device handling thread interface for mac80211 ST-Ericsson CW1200 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef CW1200_BH_H
#define CW1200_BH_H
/* extern */ struct cw1200_common;
int cw1200_register_bh(struct cw1200_common *priv);
void cw1200_unregister_bh(struct cw1200_common *priv);
void cw1200_irq_handler(struct cw1200_common *priv);
void cw1200_bh_wakeup(struct cw1200_common *priv);
int cw1200_bh_suspend(struct cw1200_common *priv);
int cw1200_bh_resume(struct cw1200_common *priv);
/* Must be called from BH thread. */
void cw1200_enable_powersave(struct cw1200_common *priv,
bool enable);
int wsm_release_tx_buffer(struct cw1200_common *priv, int count);
#endif /* CW1200_BH_H */
/*
* Common private data for ST-Ericsson CW1200 drivers
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
*
* Based on the mac80211 Prism54 code, which is
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
*
* Based on the islsm (softmac prism54) driver, which is:
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef CW1200_H
#define CW1200_H
#include <linux/wait.h>
#include <linux/version.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <net/mac80211.h>
#include "queue.h"
#include "wsm.h"
#include "scan.h"
#include "txrx.h"
#include "pm.h"
/* Forward declarations */
struct sbus_ops;
struct task_struct;
struct cw1200_debug_priv;
struct firmware;
#ifdef CONFIG_CW1200_ETF
extern int etf_mode;
extern char *etf_firmware;
#endif
#define CW1200_MAX_CTRL_FRAME_LEN (0x1000)
#define CW1200_MAX_STA_IN_AP_MODE (5)
#define CW1200_LINK_ID_AFTER_DTIM (CW1200_MAX_STA_IN_AP_MODE + 1)
#define CW1200_LINK_ID_UAPSD (CW1200_MAX_STA_IN_AP_MODE + 2)
#define CW1200_LINK_ID_MAX (CW1200_MAX_STA_IN_AP_MODE + 3)
#define CW1200_MAX_REQUEUE_ATTEMPTS (5)
#define CW1200_MAX_TID (8)
#define CW1200_BLOCK_ACK_CNT (30)
#define CW1200_BLOCK_ACK_THLD (800)
#define CW1200_BLOCK_ACK_HIST (3)
#define CW1200_BLOCK_ACK_INTERVAL (1 * HZ / CW1200_BLOCK_ACK_HIST)
#define CW1200_JOIN_TIMEOUT (1 * HZ)
#define CW1200_AUTH_TIMEOUT (5 * HZ)
struct cw1200_ht_info {
struct ieee80211_sta_ht_cap ht_cap;
enum nl80211_channel_type channel_type;
u16 operation_mode;
};
/* Please keep order */
enum cw1200_join_status {
CW1200_JOIN_STATUS_PASSIVE = 0,
CW1200_JOIN_STATUS_MONITOR,
CW1200_JOIN_STATUS_JOINING,
CW1200_JOIN_STATUS_PRE_STA,
CW1200_JOIN_STATUS_STA,
CW1200_JOIN_STATUS_IBSS,
CW1200_JOIN_STATUS_AP,
};
enum cw1200_link_status {
CW1200_LINK_OFF,
CW1200_LINK_RESERVE,
CW1200_LINK_SOFT,
CW1200_LINK_HARD,
CW1200_LINK_RESET,
CW1200_LINK_RESET_REMAP,
};
extern int cw1200_power_mode;
extern const char * const cw1200_fw_types[];
struct cw1200_link_entry {
unsigned long timestamp;
enum cw1200_link_status status;
enum cw1200_link_status prev_status;
u8 mac[ETH_ALEN];
u8 buffered[CW1200_MAX_TID];
struct sk_buff_head rx_queue;
};
struct cw1200_common {
/* interfaces to the rest of the stack */
struct ieee80211_hw *hw;
struct ieee80211_vif *vif;
struct device *pdev;
/* Statistics */
struct ieee80211_low_level_stats stats;
/* Our macaddr */
u8 mac_addr[ETH_ALEN];
/* Hardware interface */
const struct sbus_ops *sbus_ops;
struct sbus_priv *sbus_priv;
/* Hardware information */
enum {
HIF_9000_SILICON_VERSATILE = 0,
HIF_8601_VERSATILE,
HIF_8601_SILICON,
} hw_type;
enum {
CW1200_HW_REV_CUT10 = 10,
CW1200_HW_REV_CUT11 = 11,
CW1200_HW_REV_CUT20 = 20,
CW1200_HW_REV_CUT22 = 22,
CW1X60_HW_REV = 40,
} hw_revision;
int hw_refclk;
bool hw_have_5ghz;
const struct firmware *sdd;
char *sdd_path;
struct cw1200_debug_priv *debug;
struct workqueue_struct *workqueue;
struct mutex conf_mutex;
struct cw1200_queue tx_queue[4];
struct cw1200_queue_stats tx_queue_stats;
int tx_burst_idx;
/* firmware/hardware info */
unsigned int tx_hdr_len;
/* Radio data */
int output_power;
/* BBP/MAC state */
struct ieee80211_rate *rates;
struct ieee80211_rate *mcs_rates;
struct ieee80211_channel *channel;
struct wsm_edca_params edca;
struct wsm_tx_queue_params tx_queue_params;
struct wsm_mib_association_mode association_mode;
struct wsm_set_bss_params bss_params;
struct cw1200_ht_info ht_info;
struct wsm_set_pm powersave_mode;
struct wsm_set_pm firmware_ps_mode;
int cqm_rssi_thold;
unsigned cqm_rssi_hyst;
bool cqm_use_rssi;
int cqm_beacon_loss_count;
int channel_switch_in_progress;
wait_queue_head_t channel_switch_done;
u8 long_frame_max_tx_count;
u8 short_frame_max_tx_count;
int mode;
bool enable_beacon;
int beacon_int;
bool listening;
struct wsm_rx_filter rx_filter;
struct wsm_mib_multicast_filter multicast_filter;
bool has_multicast_subscription;
bool disable_beacon_filter;
struct work_struct update_filtering_work;
struct work_struct set_beacon_wakeup_period_work;
u8 ba_rx_tid_mask;
u8 ba_tx_tid_mask;
struct cw1200_pm_state pm_state;
struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo;
struct wsm_uapsd_info uapsd_info;
bool setbssparams_done;
bool bt_present;
u8 conf_listen_interval;
u32 listen_interval;
u32 erp_info;
u32 rts_threshold;
/* BH */
atomic_t bh_rx;
atomic_t bh_tx;
atomic_t bh_term;
atomic_t bh_suspend;
struct workqueue_struct *bh_workqueue;
struct work_struct bh_work;
int bh_error;
wait_queue_head_t bh_wq;
wait_queue_head_t bh_evt_wq;
u8 buf_id_tx;
u8 buf_id_rx;
u8 wsm_rx_seq;
u8 wsm_tx_seq;
int hw_bufs_used;
bool powersave_enabled;
bool device_can_sleep;
/* Scan status */
struct cw1200_scan scan;
/* Keep cw1200 awake (WUP = 1) 1 second after each scan to avoid
* FW issue with sleeping/waking up. */
atomic_t recent_scan;
struct delayed_work clear_recent_scan_work;
/* WSM */
struct wsm_startup_ind wsm_caps;
struct mutex wsm_cmd_mux;
struct wsm_buf wsm_cmd_buf;
struct wsm_cmd wsm_cmd;
wait_queue_head_t wsm_cmd_wq;
wait_queue_head_t wsm_startup_done;
int firmware_ready;
atomic_t tx_lock;
/* WSM debug */
int wsm_enable_wsm_dumps;
/* WSM Join */
enum cw1200_join_status join_status;
u32 pending_frame_id;
bool join_pending;
struct delayed_work join_timeout;
struct work_struct unjoin_work;
struct work_struct join_complete_work;
int join_complete_status;
int join_dtim_period;
bool delayed_unjoin;
/* TX/RX and security */
s8 wep_default_key_id;
struct work_struct wep_key_work;
u32 key_map;
struct wsm_add_key keys[WSM_KEY_MAX_INDEX + 1];
/* AP powersave */
u32 link_id_map;
struct cw1200_link_entry link_id_db[CW1200_MAX_STA_IN_AP_MODE];
struct work_struct link_id_work;
struct delayed_work link_id_gc_work;
u32 sta_asleep_mask;
u32 pspoll_mask;
bool aid0_bit_set;
spinlock_t ps_state_lock; /* Protect power save state */
bool buffered_multicasts;
bool tx_multicast;
struct work_struct set_tim_work;
struct work_struct set_cts_work;
struct work_struct multicast_start_work;
struct work_struct multicast_stop_work;
struct timer_list mcast_timeout;
/* WSM events and CQM implementation */
spinlock_t event_queue_lock; /* Protect event queue */
struct list_head event_queue;
struct work_struct event_handler;
struct delayed_work bss_loss_work;
spinlock_t bss_loss_lock; /* Protect BSS loss state */
int bss_loss_state;
int bss_loss_confirm_id;
int delayed_link_loss;
struct work_struct bss_params_work;
/* TX rate policy cache */
struct tx_policy_cache tx_policy_cache;
struct work_struct tx_policy_upload_work;
/* legacy PS mode switch in suspend */
int ps_mode_switch_in_progress;
wait_queue_head_t ps_mode_switch_done;
/* Workaround for WFD testcase 6.1.10*/
struct work_struct linkid_reset_work;
u8 action_frame_sa[ETH_ALEN];
u8 action_linkid;
#ifdef CONFIG_CW1200_ETF
struct sk_buff_head etf_q;
#endif
};
struct cw1200_sta_priv {
int link_id;
};
/* interfaces for the drivers */
int cw1200_core_probe(const struct sbus_ops *sbus_ops,
struct sbus_priv *sbus,
struct device *pdev,
struct cw1200_common **pself,
int ref_clk, const u8 *macaddr,
const char *sdd_path, bool have_5ghz);
void cw1200_core_release(struct cw1200_common *self);
#define FWLOAD_BLOCK_SIZE (1024)
static inline int cw1200_is_ht(const struct cw1200_ht_info *ht_info)
{
return ht_info->channel_type != NL80211_CHAN_NO_HT;
}
static inline int cw1200_ht_greenfield(const struct cw1200_ht_info *ht_info)
{
return cw1200_is_ht(ht_info) &&
(ht_info->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
!(ht_info->operation_mode &
IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
}
static inline int cw1200_ht_ampdu_density(const struct cw1200_ht_info *ht_info)
{
if (!cw1200_is_ht(ht_info))
return 0;
return ht_info->ht_cap.ampdu_density;
}
#endif /* CW1200_H */
/*
* Platform glue data for ST-Ericsson CW1200 driver
*
* Copyright (c) 2013, Sagrad, Inc
* Author: Solomon Peachy <speachy@sagrad.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/cw1200_platform.h>
MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>");
MODULE_DESCRIPTION("ST-Ericsson CW1200 Platform glue driver");
MODULE_LICENSE("GPL");
/* Define just one of these. Feel free to customize as needed */
#define SAGRAD_1091_1098_EVK_SDIO
/* #define SAGRAD_1091_1098_EVK_SPI */
#ifdef SAGRAD_1091_1098_EVK_SDIO
#if 0
static struct resource cw1200_href_resources[] = {
{
.start = 215, /* fix me as appropriate */
.end = 215, /* ditto */
.flags = IORESOURCE_IO,
.name = "cw1200_wlan_reset",
},
{
.start = 216, /* fix me as appropriate */
.end = 216, /* ditto */
.flags = IORESOURCE_IO,
.name = "cw1200_wlan_powerup",
},
{
.start = NOMADIK_GPIO_TO_IRQ(216), /* fix me as appropriate */
.end = NOMADIK_GPIO_TO_IRQ(216), /* ditto */
.flags = IORESOURCE_IRQ,
.name = "cw1200_wlan_irq",
},
};
#endif
static int cw1200_power_ctrl(const struct cw1200_platform_data_sdio *pdata,
bool enable)
{
/* Control 3v3 and 1v8 to hardware as appropriate */
/* Note this is not needed if it's controlled elsewhere or always on */
/* May require delay for power to stabilize */
return 0;
}
static int cw1200_clk_ctrl(const struct cw1200_platform_data_sdio *pdata,
bool enable)
{
/* Turn CLK_32K off and on as appropriate. */
/* Note this is not needed if it's always on */
/* May require delay for clock to stabilize */
return 0;
}
static struct cw1200_platform_data_sdio cw1200_platform_data = {
.ref_clk = 38400,
.have_5ghz = false,
#if 0
.reset = &cw1200_href_resources[0],
.powerup = &cw1200_href_resources[1],
.irq = &cw1200_href_resources[2],
#endif
.power_ctrl = cw1200_power_ctrl,
.clk_ctrl = cw1200_clk_ctrl,
/* .macaddr = ??? */
.sdd_file = "sdd_sagrad_1091_1098.bin",
};
#endif
#ifdef SAGRAD_1091_1098_EVK_SPI
/* Note that this is an example of integrating into your board support file */
static struct resource cw1200_href_resources[] = {
{
.start = GPIO_RF_RESET,
.end = GPIO_RF_RESET,
.flags = IORESOURCE_IO,
.name = "cw1200_wlan_reset",
},
{
.start = GPIO_RF_POWERUP,
.end = GPIO_RF_POWERUP,
.flags = IORESOURCE_IO,
.name = "cw1200_wlan_powerup",
},
};
static int cw1200_power_ctrl(const struct cw1200_platform_data_spi *pdata,
bool enable)
{
/* Control 3v3 and 1v8 to hardware as appropriate */
/* Note this is not needed if it's controlled elsewhere or always on */
/* May require delay for power to stabilize */
return 0;
}
static int cw1200_clk_ctrl(const struct cw1200_platform_data_spi *pdata,
bool enable)
{
/* Turn CLK_32K off and on as appropriate. */
/* Note this is not needed if it's always on */
/* May require delay for clock to stabilize */
return 0;
}
static struct cw1200_platform_data_spi cw1200_platform_data = {
.ref_clk = 38400,
.spi_bits_per_word = 16,
.reset = &cw1200_href_resources[0],
.powerup = &cw1200_href_resources[1],
.power_ctrl = cw1200_power_ctrl,
.clk_ctrl = cw1200_clk_ctrl,
/* .macaddr = ??? */
.sdd_file = "sdd_sagrad_1091_1098.bin",
};
static struct spi_board_info myboard_spi_devices[] __initdata = {
{
.modalias = "cw1200_wlan_spi",
.max_speed_hz = 10000000, /* 52MHz Max */
.bus_num = 0,
.irq = WIFI_IRQ,
.platform_data = &cw1200_platform_data,
.chip_select = 0,
},
};
#endif
const void *cw1200_get_platform_data(void)
{
return &cw1200_platform_data;
}
EXPORT_SYMBOL_GPL(cw1200_get_platform_data);
/*
* Mac80211 SDIO driver for ST-Ericsson CW1200 device
*
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <net/mac80211.h>
#include "cw1200.h"
#include "sbus.h"
#include <linux/cw1200_platform.h>
#include "hwio.h"
MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
MODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SDIO driver");
MODULE_LICENSE("GPL");
#define SDIO_BLOCK_SIZE (512)
struct sbus_priv {
struct sdio_func *func;
struct cw1200_common *core;
const struct cw1200_platform_data_sdio *pdata;
};
#ifndef SDIO_VENDOR_ID_STE
#define SDIO_VENDOR_ID_STE 0x0020
#endif
#ifndef SDIO_DEVICE_ID_STE_CW1200
#define SDIO_DEVICE_ID_STE_CW1200 0x2280
#endif
static const struct sdio_device_id cw1200_sdio_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200) },
{ /* end: all zeroes */ },
};
/* sbus_ops implemetation */
static int cw1200_sdio_memcpy_fromio(struct sbus_priv *self,
unsigned int addr,
void *dst, int count)
{
return sdio_memcpy_fromio(self->func, dst, addr, count);
}
static int cw1200_sdio_memcpy_toio(struct sbus_priv *self,
unsigned int addr,
const void *src, int count)
{
return sdio_memcpy_toio(self->func, addr, (void *)src, count);
}
static void cw1200_sdio_lock(struct sbus_priv *self)
{
sdio_claim_host(self->func);
}
static void cw1200_sdio_unlock(struct sbus_priv *self)
{
sdio_release_host(self->func);
}
static void cw1200_sdio_irq_handler(struct sdio_func *func)
{
struct sbus_priv *self = sdio_get_drvdata(func);
/* note: sdio_host already claimed here. */
if (self->core)
cw1200_irq_handler(self->core);
}
static irqreturn_t cw1200_gpio_hardirq(int irq, void *dev_id)
{
return IRQ_WAKE_THREAD;
}
static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
{
struct sbus_priv *self = dev_id;
if (self->core) {
sdio_claim_host(self->func);
cw1200_irq_handler(self->core);
sdio_release_host(self->func);
return IRQ_HANDLED;
} else {
return IRQ_NONE;
}
}
static int cw1200_request_irq(struct sbus_priv *self)
{
int ret;
const struct resource *irq = self->pdata->irq;
u8 cccr;
cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret);
if (WARN_ON(ret))
goto err;
/* Master interrupt enable ... */
cccr |= BIT(0);
/* ... for our function */
cccr |= BIT(self->func->num);
sdio_f0_writeb(self->func, cccr, SDIO_CCCR_IENx, &ret);
if (WARN_ON(ret))
goto err;
ret = enable_irq_wake(irq->start);
if (WARN_ON(ret))
goto err;
/* Request the IRQ */
ret = request_threaded_irq(irq->start, cw1200_gpio_hardirq,
cw1200_gpio_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
irq->name, self);
if (WARN_ON(ret))
goto err;
return 0;
err:
return ret;
}
static int cw1200_sdio_irq_subscribe(struct sbus_priv *self)
{
int ret = 0;
pr_debug("SW IRQ subscribe\n");
sdio_claim_host(self->func);
if (self->pdata->irq)
ret = cw1200_request_irq(self);
else
ret = sdio_claim_irq(self->func, cw1200_sdio_irq_handler);
sdio_release_host(self->func);
return ret;
}
static int cw1200_sdio_irq_unsubscribe(struct sbus_priv *self)
{
int ret = 0;
pr_debug("SW IRQ unsubscribe\n");
if (self->pdata->irq) {
disable_irq_wake(self->pdata->irq->start);
free_irq(self->pdata->irq->start, self);
} else {
sdio_claim_host(self->func);
ret = sdio_release_irq(self->func);
sdio_release_host(self->func);
}
return ret;
}
static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
{
const struct resource *reset = pdata->reset;
if (reset) {
gpio_set_value(reset->start, 0);
msleep(30); /* Min is 2 * CLK32K cycles */
gpio_free(reset->start);
}
if (pdata->power_ctrl)
pdata->power_ctrl(pdata, false);
if (pdata->clk_ctrl)
pdata->clk_ctrl(pdata, false);
return 0;
}
static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
{
const struct resource *reset = pdata->reset;
const struct resource *powerup = pdata->reset;
/* Ensure I/Os are pulled low */
if (reset) {
gpio_request(reset->start, reset->name);
gpio_direction_output(reset->start, 0);
}
if (powerup) {
gpio_request(powerup->start, powerup->name);
gpio_direction_output(powerup->start, 0);
}
if (reset || powerup)
msleep(50); /* Settle time */
/* Enable 3v3 and 1v8 to hardware */
if (pdata->power_ctrl) {
if (pdata->power_ctrl(pdata, true)) {
pr_err("power_ctrl() failed!\n");
return -1;
}
}
/* Enable CLK32K */
if (pdata->clk_ctrl) {
if (pdata->clk_ctrl(pdata, true)) {
pr_err("clk_ctrl() failed!\n");
return -1;
}
msleep(10); /* Delay until clock is stable for 2 cycles */
}
/* Enable POWERUP signal */
if (powerup) {
gpio_set_value(powerup->start, 1);
msleep(250); /* or more..? */
}
/* Enable RSTn signal */
if (reset) {
gpio_set_value(reset->start, 1);
msleep(50); /* Or more..? */
}
return 0;
}
static size_t cw1200_sdio_align_size(struct sbus_priv *self, size_t size)
{
if (self->pdata->no_nptb)
size = round_up(size, SDIO_BLOCK_SIZE);
else
size = sdio_align_size(self->func, size);
return size;
}
static int cw1200_sdio_pm(struct sbus_priv *self, bool suspend)
{
int ret = 0;
if (self->pdata->irq)
ret = irq_set_irq_wake(self->pdata->irq->start, suspend);
return ret;
}
static struct sbus_ops cw1200_sdio_sbus_ops = {
.sbus_memcpy_fromio = cw1200_sdio_memcpy_fromio,
.sbus_memcpy_toio = cw1200_sdio_memcpy_toio,
.lock = cw1200_sdio_lock,
.unlock = cw1200_sdio_unlock,
.align_size = cw1200_sdio_align_size,
.power_mgmt = cw1200_sdio_pm,
};
/* Probe Function to be called by SDIO stack when device is discovered */
static int cw1200_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
struct sbus_priv *self;
int status;
pr_info("cw1200_wlan_sdio: Probe called\n");
/* We are only able to handle the wlan function */
if (func->num != 0x01)
return -ENODEV;
self = kzalloc(sizeof(*self), GFP_KERNEL);
if (!self) {
pr_err("Can't allocate SDIO sbus_priv.\n");
return -ENOMEM;
}
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
self->pdata = cw1200_get_platform_data();
self->func = func;
sdio_set_drvdata(func, self);
sdio_claim_host(func);
sdio_enable_func(func);
sdio_release_host(func);
status = cw1200_sdio_irq_subscribe(self);
status = cw1200_core_probe(&cw1200_sdio_sbus_ops,
self, &func->dev, &self->core,
self->pdata->ref_clk,
self->pdata->macaddr,
self->pdata->sdd_file,
self->pdata->have_5ghz);
if (status) {
cw1200_sdio_irq_unsubscribe(self);
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
sdio_set_drvdata(func, NULL);
kfree(self);
}
return status;
}
/* Disconnect Function to be called by SDIO stack when
* device is disconnected */
static void cw1200_sdio_disconnect(struct sdio_func *func)
{
struct sbus_priv *self = sdio_get_drvdata(func);
if (self) {
cw1200_sdio_irq_unsubscribe(self);
if (self->core) {
cw1200_core_release(self->core);
self->core = NULL;
}
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
sdio_set_drvdata(func, NULL);
kfree(self);
}
}
static int cw1200_sdio_suspend(struct device *dev)
{
int ret;
struct sdio_func *func = dev_to_sdio_func(dev);
struct sbus_priv *self = sdio_get_drvdata(func);
if (!cw1200_can_suspend(self->core))
return -EAGAIN;
/* Notify SDIO that CW1200 will remain powered during suspend */
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
if (ret)
pr_err("Error setting SDIO pm flags: %i\n", ret);
return ret;
}
static int cw1200_sdio_resume(struct device *dev)
{
return 0;
}
static const struct dev_pm_ops cw1200_pm_ops = {
.suspend = cw1200_sdio_suspend,
.resume = cw1200_sdio_resume,
};
static struct sdio_driver sdio_driver = {
.name = "cw1200_wlan_sdio",
.id_table = cw1200_sdio_ids,
.probe = cw1200_sdio_probe,
.remove = cw1200_sdio_disconnect,
.drv = {
.pm = &cw1200_pm_ops,
}
};
/* Init Module function -> Called by insmod */
static int __init cw1200_sdio_init(void)
{
const struct cw1200_platform_data_sdio *pdata;
int ret;
pdata = cw1200_get_platform_data();
if (cw1200_sdio_on(pdata)) {
ret = -1;
goto err;
}
ret = sdio_register_driver(&sdio_driver);
if (ret)
goto err;
return 0;
err:
cw1200_sdio_off(pdata);
return ret;
}
/* Called at Driver Unloading */
static void __exit cw1200_sdio_exit(void)
{
const struct cw1200_platform_data_sdio *pdata;
pdata = cw1200_get_platform_data();
sdio_unregister_driver(&sdio_driver);
cw1200_sdio_off(pdata);
}
module_init(cw1200_sdio_init);
module_exit(cw1200_sdio_exit);
This diff is collapsed.
This diff is collapsed.
/*
* DebugFS code for ST-Ericsson CW1200 mac80211 driver
*
* Copyright (c) 2011, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef CW1200_DEBUG_H_INCLUDED
#define CW1200_DEBUG_H_INCLUDED
#include "itp.h"
struct cw1200_debug_priv {
struct dentry *debugfs_phy;
int tx;
int tx_agg;
int rx;
int rx_agg;
int tx_multi;
int tx_multi_frames;
int tx_cache_miss;
int tx_align;
int tx_ttl;
int tx_burst;
int ba_cnt;
int ba_acc;
int ba_cnt_rx;
int ba_acc_rx;
#ifdef CONFIG_CW1200_ITP
struct cw1200_itp itp;
#endif /* CONFIG_CW1200_ITP */
};
int cw1200_debug_init(struct cw1200_common *priv);
void cw1200_debug_release(struct cw1200_common *priv);
static inline void cw1200_debug_txed(struct cw1200_common *priv)
{
++priv->debug->tx;
}
static inline void cw1200_debug_txed_agg(struct cw1200_common *priv)
{
++priv->debug->tx_agg;
}
static inline void cw1200_debug_txed_multi(struct cw1200_common *priv,
int count)
{
++priv->debug->tx_multi;
priv->debug->tx_multi_frames += count;
}
static inline void cw1200_debug_rxed(struct cw1200_common *priv)
{
++priv->debug->rx;
}
static inline void cw1200_debug_rxed_agg(struct cw1200_common *priv)
{
++priv->debug->rx_agg;
}
static inline void cw1200_debug_tx_cache_miss(struct cw1200_common *priv)
{
++priv->debug->tx_cache_miss;
}
static inline void cw1200_debug_tx_align(struct cw1200_common *priv)
{
++priv->debug->tx_align;
}
static inline void cw1200_debug_tx_ttl(struct cw1200_common *priv)
{
++priv->debug->tx_ttl;
}
static inline void cw1200_debug_tx_burst(struct cw1200_common *priv)
{
++priv->debug->tx_burst;
}
static inline void cw1200_debug_ba(struct cw1200_common *priv,
int ba_cnt, int ba_acc,
int ba_cnt_rx, int ba_acc_rx)
{
priv->debug->ba_cnt = ba_cnt;
priv->debug->ba_acc = ba_acc;
priv->debug->ba_cnt_rx = ba_cnt_rx;
priv->debug->ba_acc_rx = ba_acc_rx;
}
#endif /* CW1200_DEBUG_H_INCLUDED */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1347,14 +1347,6 @@ struct il_rx_mpdu_res_start {
#define TX_CMD_SEC_SHIFT 6
#define TX_CMD_SEC_KEY128 0x08
/*
* security overhead sizes
*/
#define WEP_IV_LEN 4
#define WEP_ICV_LEN 4
#define CCMP_MIC_LEN 8
#define TKIP_ICV_LEN 4
/*
* C_TX = 0x1c (command)
*/
......
......@@ -1220,14 +1220,6 @@ struct iwl_rx_mpdu_res_start {
#define TX_CMD_SEC_SHIFT 6
#define TX_CMD_SEC_KEY128 0x08
/*
* security overhead sizes
*/
#define WEP_IV_LEN 4
#define WEP_ICV_LEN 4
#define CCMP_MIC_LEN 8
#define TKIP_ICV_LEN 4
/*
* REPLY_TX = 0x1c (command)
*/
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -570,6 +570,7 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_UAP_SYS_CONFIG:
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
case HostCmd_CMD_UAP_STA_DEAUTH:
ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf,
cmd_ptr);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment