2011-09-13 07:50:12

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 00/17] staging: brcm80211: 5th reaction to mainline patch #2

Code cleanup, and one fix for a build problem.

This series applies to staging-next and depends on the following patch set:

Message-ID: <[email protected]>

Arend van Spriel (4):
staging: brcm80211: remove ioctl layer from brcmsmac
staging: brcm80211: remove function ieee_set_channel()
staging: brcm80211: remove devpath related nvram variable lookup
staging: brcm80211: remove brcms_c_get_par and set_par functions

Franky Lin (1):
staging: brcm80211: remove static function declaration in dhd_sdio

Roland Vossen (12):
staging: brcm80211: fix for fullmac build problem
staging: brcm80211: macro cleanup in softmac dma
staging: brcm80211: cleanup of softmac macro EDCF_ENAB()
staging: brcm80211: removed function brcms_c_wme_initparams_sta()
staging: brcm80211: macro cleanup in softmac main.c
staging: brcm80211: added clarification on softmac dma alignment
staging: brcm80211: macro cleanup in softmac rate.h
staging: brcm80211: separated public from private ioctl functions
staging: brcm80211: simplification of brcmf_netdev_ioctl_priv()
staging: brcm80211: cleaned up function brcmf_cfg80211_get_key()
staging: brcm80211: fullmac sparse endianness encryption keys check
staging: brcm80211: introduced fullmac function get/set u32 to/from
dongle

drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 2 -
drivers/staging/brcm80211/brcmfmac/dhd.h | 50 +-
drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 79 +-
drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 6392 ++++++++++-----------
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 162 +-
drivers/staging/brcm80211/brcmsmac/aiutils.c | 62 +-
drivers/staging/brcm80211/brcmsmac/aiutils.h | 5 -
drivers/staging/brcm80211/brcmsmac/ampdu.c | 25 +-
drivers/staging/brcm80211/brcmsmac/dma.c | 147 +-
drivers/staging/brcm80211/brcmsmac/mac80211_if.c | 118 +-
drivers/staging/brcm80211/brcmsmac/main.c | 955 ++--
drivers/staging/brcm80211/brcmsmac/main.h | 21 -
drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c | 2 +-
drivers/staging/brcm80211/brcmsmac/pub.h | 25 +-
drivers/staging/brcm80211/brcmsmac/rate.c | 16 +-
drivers/staging/brcm80211/brcmsmac/rate.h | 188 +-
drivers/staging/brcm80211/brcmsmac/scb.h | 2 +-
drivers/staging/brcm80211/brcmsmac/stf.c | 2 +-
drivers/staging/brcm80211/include/defs.h | 13 +-
19 files changed, 3931 insertions(+), 4335 deletions(-)

--
1.7.4.1




2011-09-14 07:05:11

by Roland Vossen

[permalink] [raw]
Subject: Re: [PATCH 14/17] staging: brcm80211: simplification of brcmf_netdev_ioctl_priv()

>> + if (ioc->buf != NULL)
>> + buflen = min_t(int, ioc->len, BRCMF_IOCTL_MAXLEN);
> ^^^^
> Should be uint here.

You are right. Greg, please drop [14/17], I will post a v2 patch.

Thanks, Roland.


2011-09-13 07:50:22

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 02/17] staging: brcm80211: remove ioctl layer from brcmsmac

From: Arend van Spriel <[email protected]>

The ioctl layer in brcmsmac only provided an interface layer that
was internal to the driver. This is considered pointless and has
been removed.

Reported-by: Johannes Berg <[email protected]>
Reviewed-by: Roland Vossen <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/mac80211_if.c | 65 ++---
drivers/staging/brcm80211/brcmsmac/main.c | 353 +++++++--------------
drivers/staging/brcm80211/brcmsmac/pub.h | 12 +-
drivers/staging/brcm80211/include/defs.h | 13 +-
4 files changed, 158 insertions(+), 285 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
index d003786..7d012be 100644
--- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
@@ -371,23 +371,23 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
enum nl80211_channel_type type)
{
struct brcms_info *wl = hw->priv;
- int err = 0;
+ int err;

switch (type) {
case NL80211_CHAN_HT20:
case NL80211_CHAN_NO_HT:
- err = brcms_c_set(wl->wlc, BRCM_SET_CHANNEL, chan->hw_value);
+ err = brcms_c_set_channel(wl->wlc, chan->hw_value);
break;
case NL80211_CHAN_HT40MINUS:
case NL80211_CHAN_HT40PLUS:
wiphy_err(hw->wiphy,
"%s: Need to implement 40 Mhz Channels!\n", __func__);
- err = 1;
+ err = -ENOTSUPP;
break;
+ default:
+ err = -EINVAL;
}

- if (err)
- return -EIO;
return err;
}

@@ -436,21 +436,10 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
err = ieee_set_channel(hw, conf->channel, conf->channel_type);

- if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
- if (brcms_c_set
- (wl->wlc, BRCM_SET_SRL,
- conf->short_frame_max_tx_count) < 0) {
- wiphy_err(wiphy, "%s: Error setting srl\n", __func__);
- err = -EIO;
- goto config_out;
- }
- if (brcms_c_set(wl->wlc, BRCM_SET_LRL,
- conf->long_frame_max_tx_count) < 0) {
- wiphy_err(wiphy, "%s: Error setting lrl\n", __func__);
- err = -EIO;
- goto config_out;
- }
- }
+ if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ err = brcms_c_set_rate_limit(wl->wlc,
+ conf->short_frame_max_tx_count,
+ conf->long_frame_max_tx_count);

config_out:
UNLOCK(wl);
@@ -464,7 +453,6 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
{
struct brcms_info *wl = hw->priv;
struct wiphy *wiphy = hw->wiphy;
- int val;

if (changed & BSS_CHANGED_ASSOC) {
/* association status changed (associated/disassociated)
@@ -477,13 +465,15 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
UNLOCK(wl);
}
if (changed & BSS_CHANGED_ERP_SLOT) {
+ s8 val;
+
/* slot timing changed */
if (info->use_short_slot)
val = 1;
else
val = 0;
LOCK(wl);
- brcms_c_set(wl->wlc, BRCMS_SET_SHORTSLOT_OVERRIDE, val);
+ brcms_c_set_shortslot_override(wl->wlc, val);
UNLOCK(wl);
}

@@ -509,14 +499,9 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,

/* retrieve the current rates */
LOCK(wl);
- error = brcms_c_ioctl(wl->wlc, BRCM_GET_CURR_RATESET,
- &rs, sizeof(rs));
+ brcms_c_get_current_rateset(wl->wlc, &rs);
UNLOCK(wl);
- if (error) {
- wiphy_err(wiphy, "%s: retrieve rateset failed: %d\n",
- __func__, error);
- return;
- }
+
br_mask = info->basic_rates;
bi = hw->wiphy->bands[brcms_c_get_curband(wl->wlc)];
for (i = 0; i < bi->n_bitrates; i++) {
@@ -530,20 +515,22 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,

/* update the rate set */
LOCK(wl);
- brcms_c_ioctl(wl->wlc, BRCM_SET_RATESET, &rs, sizeof(rs));
+ error = brcms_c_set_rateset(wl->wlc, &rs);
UNLOCK(wl);
+ if (!error)
+ wiphy_err(wiphy, "changing basic rates failed: %d\n",
+ error);
}
if (changed & BSS_CHANGED_BEACON_INT) {
/* Beacon interval changed */
LOCK(wl);
- brcms_c_set(wl->wlc, BRCM_SET_BCNPRD, info->beacon_int);
+ brcms_c_set_beacon_period(wl->wlc, info->beacon_int);
UNLOCK(wl);
}
if (changed & BSS_CHANGED_BSSID) {
/* BSSID changed, for whatever reason (IBSS and managed mode) */
LOCK(wl);
- brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET,
- info->bssid);
+ brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);
UNLOCK(wl);
}
if (changed & BSS_CHANGED_BEACON)
@@ -1086,18 +1073,16 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)
{
struct brcms_info *wl = hw->priv;
int has_5g;
- char phy_list[4];
+ u16 phy_type;

has_5g = 0;

hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;

- if (brcms_c_get(wl->wlc, BRCM_GET_PHYLIST, (int *)&phy_list) < 0)
- wiphy_err(hw->wiphy, "Phy list failed\n");
-
- if (phy_list[0] == 'n' || phy_list[0] == 'c') {
- if (phy_list[0] == 'c') {
+ phy_type = brcms_c_get_phy_type(wl->wlc, 0);
+ if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) {
+ if (phy_type == PHY_TYPE_LCN) {
/* Single stream */
brcms_band_2GHz_nphy.ht_cap.mcs.rx_mask[1] = 0;
brcms_band_2GHz_nphy.ht_cap.mcs.rx_highest = 72;
@@ -1110,7 +1095,7 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)
/* Assume all bands use the same phy. True for 11n devices. */
if (wl->pub->_nbands > 1) {
has_5g++;
- if (phy_list[0] == 'n' || phy_list[0] == 'c')
+ if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN)
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&brcms_band_5GHz_nphy;
else
diff --git a/drivers/staging/brcm80211/brcmsmac/main.c b/drivers/staging/brcm80211/brcmsmac/main.c
index 2b5d4de..705f0eb 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.c
+++ b/drivers/staging/brcm80211/brcmsmac/main.c
@@ -5252,7 +5252,7 @@ brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
/* init per-band default rateset, depend on band->gmode */
brcms_default_rateset(wlc, &wlc->band->defrateset);

- /* fill in hw_rateset (used early by BRCM_SET_RATESET) */
+ /* fill in hw_rateset */
brcms_c_rateset_filter(&wlc->band->defrateset,
&wlc->band->hw_rateset, false,
BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
@@ -6116,7 +6116,8 @@ int brcms_c_set_nmode(struct brcms_c_info *wlc, s32 nmode)
}

static int
-brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs_arg)
+brcms_c_set_internal_rateset(struct brcms_c_info *wlc,
+ struct brcms_c_rateset *rs_arg)
{
struct brcms_c_rateset rs, new;
uint bandunit;
@@ -6158,18 +6159,6 @@ brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs_arg)
return 0;
}

-/* simplified integer set interface for common ioctl handler */
-int brcms_c_set(struct brcms_c_info *wlc, int cmd, int arg)
-{
- return brcms_c_ioctl(wlc, cmd, (void *)&arg, sizeof(arg));
-}
-
-/* simplified integer get interface for common ioctl handler */
-int brcms_c_get(struct brcms_c_info *wlc, int cmd, int *arg)
-{
- return brcms_c_ioctl(wlc, cmd, arg, sizeof(int));
-}
-
static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
{
u8 r;
@@ -6185,259 +6174,153 @@ static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
return;
}

-/* common ioctl handler. return: 0=ok, -1=error, positive=particular error */
-static int
-_brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len)
+int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
{
- int val, *pval;
- bool bool_val;
- int bcmerror;
- struct scb *nextscb;
- bool ta_ok;
- uint band;
- struct brcms_bss_cfg *bsscfg;
- struct brcms_bss_info *current_bss;
-
- /* update bsscfg pointer */
- bsscfg = wlc->cfg;
- current_bss = bsscfg->current_bss;
-
- /* initialize the following to get rid of compiler warning */
- nextscb = NULL;
- ta_ok = false;
- band = 0;
-
- /* If the device is turned off, then it's not "removed" */
- if (!wlc->pub->hw_off && DEVICEREMOVED(wlc)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
- __func__);
- brcms_down(wlc->wl);
- return -EBADE;
- }
+ u16 chspec = ch20mhz_chspec(channel);

- /* default argument is generic integer */
- pval = arg ? (int *)arg : NULL;
+ if (channel < 0 || channel > MAXCHANNEL)
+ return -EINVAL;

- /*
- * This will prevent misaligned access. The (void *) cast prevents a
- * memcpy alignment issue on e.g. Sparc64 platforms.
- */
- if (pval && (u32) len >= sizeof(val))
- memcpy((void *)&val, (void *)pval, sizeof(val));
- else
- val = 0;
+ if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec))
+ return -EINVAL;

- /* bool conversion to avoid duplication below */
- bool_val = val != 0;
- bcmerror = 0;

- if ((arg == NULL) || (len <= 0)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: Command %d needs arguments\n",
- wlc->pub->unit, __func__, cmd);
- bcmerror = -EINVAL;
- goto done;
+ if (!wlc->pub->up && IS_MBAND_UNLOCKED(wlc)) {
+ if (wlc->band->bandunit != chspec_bandunit(chspec))
+ wlc->bandinit_pending = true;
+ else
+ wlc->bandinit_pending = false;
}

- switch (cmd) {
-
- case BRCM_SET_CHANNEL:{
- u16 chspec = ch20mhz_chspec(val);
-
- if (val < 0 || val > MAXCHANNEL) {
- bcmerror = -EINVAL;
- break;
- }
-
- if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec)) {
- bcmerror = -EINVAL;
- break;
- }
-
- if (!wlc->pub->up && IS_MBAND_UNLOCKED(wlc)) {
- if (wlc->band->bandunit !=
- chspec_bandunit(chspec))
- wlc->bandinit_pending = true;
- else
- wlc->bandinit_pending = false;
- }
-
- wlc->default_bss->chanspec = chspec;
- /* brcms_c_BSSinit() will sanitize the rateset before
- * using it.. */
- if (wlc->pub->up &&
- (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) {
- brcms_c_set_home_chanspec(wlc, chspec);
- brcms_c_suspend_mac_and_wait(wlc);
- brcms_c_set_chanspec(wlc, chspec);
- brcms_c_enable_mac(wlc);
- }
- break;
- }
-
- case BRCM_SET_SRL:
- if (val >= 1 && val <= RETRY_SHORT_MAX) {
- int ac;
- wlc->SRL = (u16) val;
-
- brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
-
- for (ac = 0; ac < AC_COUNT; ac++)
- BRCMS_WME_RETRY_SHORT_SET(wlc, ac, wlc->SRL);
-
- brcms_c_wme_retries_write(wlc);
- } else
- bcmerror = -EINVAL;
- break;
-
- case BRCM_SET_LRL:
- if (val >= 1 && val <= 255) {
- int ac;
- wlc->LRL = (u16) val;
-
- brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
+ wlc->default_bss->chanspec = chspec;
+ /* brcms_c_BSSinit() will sanitize the rateset before
+ * using it.. */
+ if (wlc->pub->up && (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) {
+ brcms_c_set_home_chanspec(wlc, chspec);
+ brcms_c_suspend_mac_and_wait(wlc);
+ brcms_c_set_chanspec(wlc, chspec);
+ brcms_c_enable_mac(wlc);
+ }
+ return 0;
+}

- for (ac = 0; ac < AC_COUNT; ac++)
- BRCMS_WME_RETRY_LONG_SET(wlc, ac, wlc->LRL);
+int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)
+{
+ int ac;

- brcms_c_wme_retries_write(wlc);
- } else
- bcmerror = -EINVAL;
- break;
+ if (srl < 1 || srl > RETRY_SHORT_MAX ||
+ lrl < 1 || lrl > RETRY_SHORT_MAX)
+ return -EINVAL;

- case BRCM_GET_CURR_RATESET:{
- struct brcm_rateset *ret_rs =
- (struct brcm_rateset *) arg;
- struct brcms_c_rateset *rs;
+ wlc->SRL = srl;
+ wlc->LRL = lrl;

- if (wlc->pub->associated)
- rs = &current_bss->rateset;
- else
- rs = &wlc->default_bss->rateset;
+ brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);

- if (len < (int)(rs->count + sizeof(rs->count))) {
- bcmerror = -EOVERFLOW;
- break;
- }
+ for (ac = 0; ac < AC_COUNT; ac++) {
+ BRCMS_WME_RETRY_SHORT_SET(wlc, ac, srl);
+ BRCMS_WME_RETRY_LONG_SET(wlc, ac, lrl);
+ }
+ brcms_c_wme_retries_write(wlc);

- /* Copy only legacy rateset section */
- ret_rs->count = rs->count;
- memcpy(&ret_rs->rates, &rs->rates, rs->count);
- break;
- }
+ return 0;
+}

- case BRCM_SET_RATESET:{
- struct brcms_c_rateset rs;
- struct brcm_rateset *in_rs =
- (struct brcm_rateset *) arg;
+void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
+ struct brcm_rateset *currs)
+{
+ struct brcms_c_rateset *rs;

- if (len < (int)(in_rs->count + sizeof(in_rs->count))) {
- bcmerror = -EOVERFLOW;
- break;
- }
+ if (wlc->pub->associated)
+ rs = &wlc->cfg->current_bss->rateset;
+ else
+ rs = &wlc->default_bss->rateset;

- if (in_rs->count > BRCMS_NUMRATES) {
- bcmerror = -ENOBUFS;
- break;
- }
+ /* Copy only legacy rateset section */
+ currs->count = rs->count;
+ memcpy(&currs->rates, &rs->rates, rs->count);
+}

- memset(&rs, 0, sizeof(struct brcms_c_rateset));
-
- /* Copy only legacy rateset section */
- rs.count = in_rs->count;
- memcpy(&rs.rates, &in_rs->rates, rs.count);
-
- /* merge rateset coming in with the current mcsset */
- if (wlc->pub->_n_enab & SUPPORT_11N) {
- struct brcms_bss_info *mcsset_bss;
- if (bsscfg->associated)
- mcsset_bss = current_bss;
- else
- mcsset_bss = wlc->default_bss;
- memcpy(rs.mcs, &mcsset_bss->rateset.mcs[0],
- MCSSET_LEN);
- }
+int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
+{
+ struct brcms_c_rateset internal_rs;
+ int bcmerror;

- bcmerror = brcms_c_set_rateset(wlc, &rs);
+ if (rs->count > BRCMS_NUMRATES)
+ return -ENOBUFS;

- if (!bcmerror)
- brcms_c_ofdm_rateset_war(wlc);
+ memset(&internal_rs, 0, sizeof(struct brcms_c_rateset));

- break;
- }
+ /* Copy only legacy rateset section */
+ internal_rs.count = rs->count;
+ memcpy(&internal_rs.rates, &rs->rates, internal_rs.count);

- case BRCM_SET_BCNPRD:
- /* range [1, 0xffff] */
- if (val >= DOT11_MIN_BEACON_PERIOD
- && val <= DOT11_MAX_BEACON_PERIOD)
- wlc->default_bss->beacon_period = (u16) val;
+ /* merge rateset coming in with the current mcsset */
+ if (wlc->pub->_n_enab & SUPPORT_11N) {
+ struct brcms_bss_info *mcsset_bss;
+ if (wlc->cfg->associated)
+ mcsset_bss = wlc->cfg->current_bss;
else
- bcmerror = -EINVAL;
- break;
-
- case BRCM_GET_PHYLIST:
- {
- unsigned char *cp = arg;
- if (len < 3) {
- bcmerror = -EOVERFLOW;
- break;
- }
+ mcsset_bss = wlc->default_bss;
+ memcpy(internal_rs.mcs, &mcsset_bss->rateset.mcs[0],
+ MCSSET_LEN);
+ }

- if (BRCMS_ISNPHY(wlc->band))
- *cp++ = 'n';
- else if (BRCMS_ISLCNPHY(wlc->band))
- *cp++ = 'c';
- else if (BRCMS_ISSSLPNPHY(wlc->band))
- *cp++ = 's';
- *cp = '\0';
- break;
- }
+ bcmerror = brcms_c_set_internal_rateset(wlc, &internal_rs);
+ if (!bcmerror)
+ brcms_c_ofdm_rateset_war(wlc);

- case BRCMS_SET_SHORTSLOT_OVERRIDE:
- if (val != BRCMS_SHORTSLOT_AUTO && val != BRCMS_SHORTSLOT_OFF &&
- val != BRCMS_SHORTSLOT_ON) {
- bcmerror = -EINVAL;
- break;
- }
-
- wlc->shortslot_override = (s8) val;
+ return bcmerror;
+}

- /* shortslot is an 11g feature, so no more work if we are
- * currently on the 5G band
- */
- if (wlc->band->bandtype == BRCM_BAND_5G)
- break;
+int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
+{
+ if (period < DOT11_MIN_BEACON_PERIOD ||
+ period > DOT11_MAX_BEACON_PERIOD)
+ return -EINVAL;

- if (wlc->pub->up && wlc->pub->associated) {
- /* let watchdog or beacon processing update shortslot */
- } else if (wlc->pub->up) {
- /* unassociated shortslot is off */
- brcms_c_switch_shortslot(wlc, false);
- } else {
- /* driver is down, so just update the brcms_c_info
- * value */
- if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO)
- wlc->shortslot = false;
- else
- wlc->shortslot =
- (wlc->shortslot_override ==
- BRCMS_SHORTSLOT_ON);
- }
+ wlc->default_bss->beacon_period = period;
+ return 0;
+}

- break;
+u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx)
+{
+ return wlc->band->phytype;
+}

+int brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)
+{
+ if (sslot_override != BRCMS_SHORTSLOT_AUTO &&
+ sslot_override != BRCMS_SHORTSLOT_OFF &&
+ sslot_override != BRCMS_SHORTSLOT_ON) {
+ return -EINVAL;
}
- done:

- if (bcmerror)
- wlc->pub->bcmerror = bcmerror;
+ wlc->shortslot_override = sslot_override;

- return bcmerror;
-}
+ /*
+ * shortslot is an 11g feature, so no more work if we are
+ * currently on the 5G band
+ */
+ if (wlc->band->bandtype == BRCM_BAND_5G)
+ return 0;

-int
-brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len)
-{
- return _brcms_c_ioctl(wlc, cmd, arg, len);
+ if (wlc->pub->up && wlc->pub->associated) {
+ /* let watchdog or beacon processing update shortslot */
+ } else if (wlc->pub->up) {
+ /* unassociated shortslot is off */
+ brcms_c_switch_shortslot(wlc, false);
+ } else {
+ /* driver is down, so just update the brcms_c_info
+ * value */
+ if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO)
+ wlc->shortslot = false;
+ else
+ wlc->shortslot =
+ (wlc->shortslot_override ==
+ BRCMS_SHORTSLOT_ON);
+ }
+ return 0;
}

/*
diff --git a/drivers/staging/brcm80211/brcmsmac/pub.h b/drivers/staging/brcm80211/brcmsmac/pub.h
index 33e7ebe..3655ac6 100644
--- a/drivers/staging/brcm80211/brcmsmac/pub.h
+++ b/drivers/staging/brcm80211/brcmsmac/pub.h
@@ -312,8 +312,6 @@ extern uint brcms_c_detach(struct brcms_c_info *wlc);
extern int brcms_c_up(struct brcms_c_info *wlc);
extern uint brcms_c_down(struct brcms_c_info *wlc);

-extern int brcms_c_set(struct brcms_c_info *wlc, int cmd, int arg);
-extern int brcms_c_get(struct brcms_c_info *wlc, int cmd, int *arg);
extern bool brcms_c_chipmatch(u16 vendor, u16 device);
extern void brcms_c_init(struct brcms_c_info *wlc);
extern void brcms_c_reset(struct brcms_c_info *wlc);
@@ -327,7 +325,6 @@ extern bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded);
extern void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc,
struct sk_buff *sdu,
struct ieee80211_hw *hw);
-extern int brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len);
extern bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid);

/* helper functions */
@@ -382,6 +379,15 @@ extern int brcms_c_get_curband(struct brcms_c_info *wlc);
extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc,
bool drop);

+int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
+int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
+void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
+ struct brcm_rateset *currs);
+int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs);
+int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period);
+u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx);
+int brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override);
+
/* helper functions */
extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
extern bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc);
diff --git a/drivers/staging/brcm80211/include/defs.h b/drivers/staging/brcm80211/include/defs.h
index c745b7e..3438c54 100644
--- a/drivers/staging/brcm80211/include/defs.h
+++ b/drivers/staging/brcm80211/include/defs.h
@@ -57,14 +57,13 @@ struct brcm_rateset {

#define BRCM_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */

-#define BRCM_SET_CHANNEL 30
-#define BRCM_SET_SRL 32
-#define BRCM_SET_LRL 34
-
-#define BRCM_SET_RATESET 72
-#define BRCM_SET_BCNPRD 76
-#define BRCM_GET_CURR_RATESET 114 /* current rateset */
-#define BRCM_GET_PHYLIST 180
+#define BRCM_SET_CHANNEL 30
+#define BRCM_SET_SRL 32
+#define BRCM_SET_LRL 34
+#define BRCM_SET_BCNPRD 76
+
+#define BRCM_GET_CURR_RATESET 114 /* current rateset */
+#define BRCM_GET_PHYLIST 180

/* Bit masks for radio disabled status - returned by WL_GET_RADIO */

--
1.7.4.1



2011-09-13 07:50:18

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 06/17] staging: brcm80211: cleanup of softmac macro EDCF_ENAB()

Since structure member pub->_wme is set to AUTO early in init, macro
EDCF_ENAB is always 'true' after that. All code that uses ECDF_ENAB()
appears in the code flow after the init.

Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/main.c | 53 ++++-------------------------
drivers/staging/brcm80211/brcmsmac/main.h | 2 -
drivers/staging/brcm80211/brcmsmac/pub.h | 4 --
drivers/staging/brcm80211/brcmsmac/scb.h | 2 +-
4 files changed, 8 insertions(+), 53 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/main.c b/drivers/staging/brcm80211/brcmsmac/main.c
index bf3634e..9921af2 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.c
+++ b/drivers/staging/brcm80211/brcmsmac/main.c
@@ -3579,19 +3579,10 @@ static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc)
wlc->tx_prec_map = BRCMS_PREC_BMP_ALL;
memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16));

- /*
- * For non-WME, both fifos have overlapping MAXPRIO. So just
- * disable all precedences if either is full.
- */
- if (!EDCF_ENAB(wlc->pub)) {
- wlc->fifo2prec_map[TX_DATA_FIFO] = BRCMS_PREC_BMP_ALL;
- wlc->fifo2prec_map[TX_CTL_FIFO] = BRCMS_PREC_BMP_ALL;
- } else {
- wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK;
- wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE;
- wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI;
- wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO;
- }
+ wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK;
+ wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE;
+ wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI;
+ wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO;
}

static void
@@ -3698,10 +3689,8 @@ void brcms_c_init(struct brcms_c_info *wlc)
brcms_c_bsinit(wlc);

/* Enable EDCF mode (while the MAC is suspended) */
- if (EDCF_ENAB(wlc->pub)) {
- OR_REG(&regs->ifs_ctl, IFS_USEEDCF);
- brcms_c_edcf_setparams(wlc, false);
- }
+ OR_REG(&regs->ifs_ctl, IFS_USEEDCF);
+ brcms_c_edcf_setparams(wlc, false);

/* Init precedence maps for empty FIFOs */
brcms_c_tx_prec_map_init(wlc);
@@ -4538,7 +4527,6 @@ void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
wlc->LRL = RETRY_LONG_DEF;

/* WME QoS mode is Auto by default */
- wlc->pub->_wme = AUTO;
wlc->pub->_ampdu = AMPDU_AGG_HOST;
wlc->pub->bcmerror = 0;

@@ -5745,10 +5733,7 @@ int brcms_c_up(struct brcms_c_info *wlc)
brcms_c_radio_monitor_stop(wlc);

/* Set EDCF hostflags */
- if (EDCF_ENAB(wlc->pub))
- brcms_c_mhf(wlc, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL);
- else
- brcms_c_mhf(wlc, MHF1, MHF1_EDCF, 0, BRCM_BAND_ALL);
+ brcms_c_mhf(wlc, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL);

if (BRCMS_WAR16165(wlc))
brcms_c_mhf(wlc, MHF2, MHF2_PCISLOWCLKWAR, MHF2_PCISLOWCLKWAR,
@@ -6715,27 +6700,12 @@ void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
prio = sdu->priority;

if (!brcms_c_prec_enq(wlc, q, sdu, prec)) {
- if (!EDCF_ENAB(wlc->pub))
- wiphy_err(wlc->wiphy, "wl%d: txq_enq: txq overflow"
- "\n", wlc->pub->unit);
-
/*
* we might hit this condtion in case
* packet flooding from mac80211 stack
*/
brcmu_pkt_buf_free_skb(sdu);
}
-
- /*
- * Check if flow control needs to be turned on after enqueuing the
- * packet. Don't turn on flow control if EDCF is enabled. Driver
- * would make the decision on what to drop instead of relying on
- * stack to make the right decision
- */
- if (!EDCF_ENAB(wlc->pub)) {
- if (pktq_len(q) >= BRCMS_DATAHIWAT)
- brcms_c_txflowcontrol(wlc, qi, ON, ALLPRIO);
- }
}

/*
@@ -7729,15 +7699,6 @@ void brcms_c_send_q(struct brcms_c_info *wlc)
}
}

- /*
- * Check if flow control needs to be turned off after
- * sending the packet
- */
- if (!EDCF_ENAB(wlc->pub)) {
- if (brcms_c_txflowcontrol_prio_isset(wlc, qi, ALLPRIO)
- && (pktq_len(q) < BRCMS_DATAHIWAT / 2))
- brcms_c_txflowcontrol(wlc, qi, OFF, ALLPRIO);
- }
in_send_q = false;
}

diff --git a/drivers/staging/brcm80211/brcmsmac/main.h b/drivers/staging/brcm80211/brcmsmac/main.h
index ed8369f..0462250 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.h
+++ b/drivers/staging/brcm80211/brcmsmac/main.h
@@ -849,8 +849,6 @@ extern void brcms_c_set_home_chanspec(struct brcms_c_info *wlc,
u16 chanspec);
extern bool brcms_c_ps_allowed(struct brcms_c_info *wlc);
extern bool brcms_c_stay_awake(struct brcms_c_info *wlc);
-extern void brcms_c_wme_initparams_sta(struct brcms_c_info *wlc,
- struct wme_param_ie *pe);

extern void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw,
u8 antsel_type);
diff --git a/drivers/staging/brcm80211/brcmsmac/pub.h b/drivers/staging/brcm80211/brcmsmac/pub.h
index 2069d16..6230350 100644
--- a/drivers/staging/brcm80211/brcmsmac/pub.h
+++ b/drivers/staging/brcm80211/brcmsmac/pub.h
@@ -153,7 +153,6 @@ struct brcms_pub {

bool promisc; /* promiscuous destination address */
bool delayed_down; /* down delayed */
- int _wme; /* WME QoS mode */
bool associated; /* true:part of [I]BSS, false: not */
/* (union of stas_associated, aps_associated) */
bool _ampdu; /* ampdu enabled or not */
@@ -197,9 +196,6 @@ enum wlc_par_id {
/* WL11N Support */
#define AMPDU_AGG_HOST 1

-#define EDCF_ENAB(pub) ((pub)->_wme != OFF)
-#define QOS_ENAB(pub) ((pub)->_wme != OFF || (pub)->_n_enab & SUPPORT_11N)
-
/* pri is priority encoded in the packet. This maps the Packet priority to
* enqueue precedence as defined in wlc_prec_map
*/
diff --git a/drivers/staging/brcm80211/brcmsmac/scb.h b/drivers/staging/brcm80211/brcmsmac/scb.h
index b2aacf3..122d3c3 100644
--- a/drivers/staging/brcm80211/brcmsmac/scb.h
+++ b/drivers/staging/brcm80211/brcmsmac/scb.h
@@ -27,7 +27,7 @@
#define AMPDU_MAX_SCB_TID NUMPRIO

/* scb flags */
-#define SCB_WMECAP 0x0040 /* may ONLY be set if pub->_wme!=OFF */
+#define SCB_WMECAP 0x0040
#define SCB_HTCAP 0x10000 /* HT (MIMO) capable device */
#define SCB_IS40 0x80000 /* 40MHz capable */
#define SCB_STBCCAP 0x40000000 /* STBC Capable */
--
1.7.4.1



2011-09-16 18:49:52

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH 00/17] staging: brcm80211: 5th reaction to mainline patch #2

On Tue, Sep 13, 2011 at 09:49:40AM +0200, Roland Vossen wrote:
> Code cleanup, and one fix for a build problem.
>
> This series applies to staging-next and depends on the following patch set:
>
> Message-ID: <[email protected]>

All queued up, with 2 replacement patches used instead of their
originals.

greg k-h

2011-09-13 07:50:22

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 13/17] staging: brcm80211: separated public from private ioctl functions

net_device ioctl handler was called both by the OS as by the driver
itself. Split the ioctl handler into two functions to make code paths
more clear.

Reviewed-by: Arend van Spriel <[email protected]>
Reviewed-by: Franky Lin <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmfmac/dhd.h | 2 +
drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 24 ++++++++++++++-------
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 2 +-
3 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h
index 9f84837..93a1bfc 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd.h
@@ -715,6 +715,8 @@ extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus,
extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx);
extern int brcmf_netdev_wait_pend8021x(struct net_device *dev);

+extern int brcmf_netdev_ioctl_priv(struct net_device *net, struct ifreq *ifr);
+
/* Indication from bus module regarding removal/absence of dongle */
extern void brcmf_detach(struct brcmf_pub *drvr);

diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
index cfdd645..4bc231e 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
@@ -950,13 +950,7 @@ static int brcmf_netdev_ioctl_entry(struct net_device *net, struct ifreq *ifr,
int cmd)
{
struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
- struct brcmf_c_ioctl ioc;
- int bcmerror = 0;
- int buflen = 0;
- void *buf = NULL;
- uint driver = 0;
int ifidx;
- bool is_set_key_cmd;

ifidx = brcmf_net2idx(drvr_priv, net);
brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd);
@@ -967,8 +961,22 @@ static int brcmf_netdev_ioctl_entry(struct net_device *net, struct ifreq *ifr,
if (cmd == SIOCETHTOOL)
return brcmf_ethtool(drvr_priv, ifr->ifr_data);

- if (cmd != SIOCDEVPRIVATE)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
+}
+
+/* called only from within this driver, handles cmd == SIOCDEVPRIVATE */
+int brcmf_netdev_ioctl_priv(struct net_device *net, struct ifreq *ifr)
+{
+ struct brcmf_c_ioctl ioc;
+ int bcmerror = 0;
+ int buflen = 0;
+ void *buf = NULL;
+ uint driver = 0;
+ bool is_set_key_cmd;
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
+ int ifidx;
+
+ ifidx = brcmf_net2idx(drvr_priv, net);

memset(&ioc, 0, sizeof(ioc));

diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
index 198f0cc..3fa0c1b 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
@@ -286,7 +286,7 @@ brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)

fs = get_fs();
set_fs(get_ds());
- err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
+ err = brcmf_netdev_ioctl_priv(dev, &ifr);
set_fs(fs);

return err;
--
1.7.4.1



2011-09-13 07:50:18

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 01/17] staging: brcm80211: remove static function declaration in dhd_sdio

From: Franky Lin <[email protected]>

Reshuffle function order in dhd_sdio of fullmac to get rid of
static function declaration

Reported-by: Johannes Berg <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Reviewed-by: Roland Vossen <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 6392 ++++++++++++-------------
1 files changed, 3169 insertions(+), 3223 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
index 0de4dc6..680b232 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
@@ -855,58 +855,6 @@ w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)

#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)

-#ifdef BCMDBG
-static int brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, u8 *data, uint size);
-static int brcmf_sdbrcm_mem_dump(struct brcmf_bus *bus);
-#endif /* BCMDBG */
-static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter);
-
-static void brcmf_sdbrcm_release(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus);
-static bool brcmf_sdbrcm_chipmatch(u16 chipid);
-static bool brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva);
-static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus);
-static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus);
-
-static uint brcmf_process_nvram_vars(char *varbuf, uint len);
-
-static void brcmf_sdbrcm_setmemsize(struct brcmf_bus *bus, int mem_size);
-static int brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn,
- uint flags, u8 *buf, uint nbytes,
- struct sk_buff *pkt);
-
-static bool brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus);
-static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus);
-
-static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus);
-static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus);
-
-static void
-brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase);
-
-static int brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs);
-
-static void
-brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase);
-
-static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
- u32 drivestrength);
-static void brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar);
-static void brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_watchdog(unsigned long data);
-static int brcmf_sdbrcm_watchdog_thread(void *data);
-static int brcmf_sdbrcm_dpc_thread(void *data);
-static void brcmf_sdbrcm_dpc_tasklet(unsigned long data);
-static void brcmf_sdbrcm_sched_dpc(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_sdlock(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_sdunlock(struct brcmf_bus *bus);
-static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus);
-static int brcmf_sdbrcm_ioctl_resp_wait(struct brcmf_bus *bus, uint *condition,
- bool *pending);
-static int brcmf_sdbrcm_ioctl_resp_wake(struct brcmf_bus *bus);
-
/* Packet free applicable unconditionally for sdio and sdspi.
* Conditional if bufpool was present for gspi bus.
*/
@@ -927,6 +875,22 @@ static void brcmf_sdbrcm_setmemsize(struct brcmf_bus *bus, int mem_size)
bus->ramsize = brcmf_dongle_memsize;
}

+static void brcmf_sdbrcm_sdlock(struct brcmf_bus *bus)
+{
+ if (bus->threads_only)
+ down(&bus->sdsem);
+ else
+ spin_lock_bh(&bus->sdlock);
+}
+
+static void brcmf_sdbrcm_sdunlock(struct brcmf_bus *bus)
+{
+ if (bus->threads_only)
+ up(&bus->sdsem);
+ else
+ spin_unlock_bh(&bus->sdlock);
+}
+
/* Turn backplane clock on or off */
static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
{
@@ -1217,2991 +1181,2799 @@ static void bus_wake(struct brcmf_bus *bus)
brcmf_sdbrcm_bussleep(bus, false);
}

-/* 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,
- uint chan, bool free_pkt)
+static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus)
{
- int ret;
- u8 *frame;
- u16 len, pad = 0;
- u32 swheader;
+ u32 intstatus = 0;
+ u32 hmb_data;
+ u8 fcbits;
uint retries = 0;
- struct sk_buff *new;
- int i;

brcmf_dbg(TRACE, "Enter\n");

- if (bus->drvr->dongle_reset) {
- ret = -EPERM;
- goto done;
- }
+ /* Read mailbox data and ack that we did so */
+ r_sdreg32(bus, &hmb_data,
+ offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries);

- frame = (u8 *) (pkt->data);
+ if (retries <= retry_limit)
+ w_sdreg32(bus, SMB_INT_ACK,
+ offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
+ bus->f1regdata += 2;

- /* Add alignment padding, allocate new packet if needed */
- pad = ((unsigned long)frame % BRCMF_SDALIGN);
- if (pad) {
- if (skb_headroom(pkt) < pad) {
- brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n",
- skb_headroom(pkt), pad);
- bus->drvr->tx_realloc++;
- new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);
- if (!new) {
- brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n",
- pkt->len + BRCMF_SDALIGN);
- ret = -ENOMEM;
- goto done;
- }
+ /* Dongle recomposed rx frames, accept them again */
+ if (hmb_data & HMB_DATA_NAKHANDLED) {
+ brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n",
+ bus->rx_seq);
+ if (!bus->rxskip)
+ brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n");

- pkt_align(new, pkt->len, BRCMF_SDALIGN);
- memcpy(new->data, pkt->data, pkt->len);
- if (free_pkt)
- brcmu_pkt_buf_free_skb(pkt);
- /* free the pkt if canned one is not used */
- free_pkt = true;
- pkt = new;
- frame = (u8 *) (pkt->data);
- /* precondition: (frame % BRCMF_SDALIGN) == 0) */
- pad = 0;
- } else {
- skb_push(pkt, pad);
- frame = (u8 *) (pkt->data);
- /* precondition: pad + SDPCM_HDRLEN <= pkt->len */
- memset(frame, 0, pad + SDPCM_HDRLEN);
- }
+ bus->rxskip = false;
+ intstatus |= I_HMB_FRAME_IND;
}
- /* precondition: pad < BRCMF_SDALIGN */

- /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
- len = (u16) (pkt->len);
- *(u16 *) frame = cpu_to_le16(len);
- *(((u16 *) frame) + 1) = cpu_to_le16(~len);
+ /*
+ * DEVREADY does not occur with gSPI.
+ */
+ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
+ bus->sdpcm_ver =
+ (hmb_data & HMB_DATA_VERSION_MASK) >>
+ HMB_DATA_VERSION_SHIFT;
+ if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
+ brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, "
+ "expecting %d\n",
+ bus->sdpcm_ver, SDPCM_PROT_VERSION);
+ else
+ brcmf_dbg(INFO, "Dongle ready, protocol version %d\n",
+ bus->sdpcm_ver);
+ }

- /* Software tag: channel, sequence number, data offset */
- swheader =
- ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
- (((pad +
- SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
+ /*
+ * Flow Control has been moved into the RX headers and this out of band
+ * method isn't used any more.
+ * remaining backward compatible with older dongles.
+ */
+ if (hmb_data & HMB_DATA_FC) {
+ fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
+ HMB_DATA_FCDATA_SHIFT;

- put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
- put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+ if (fcbits & ~bus->flowcontrol)
+ bus->fc_xoff++;

-#ifdef BCMDBG
- tx_packets[pkt->priority]++;
- if (BRCMF_BYTES_ON() &&
- (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
- (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
- printk(KERN_DEBUG "Tx Frame:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len);
- } else if (BRCMF_HDRS_ON()) {
- printk(KERN_DEBUG "TxHdr:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- frame, min_t(u16, len, 16));
- }
-#endif
+ if (bus->flowcontrol & ~fcbits)
+ bus->fc_xon++;

- /* Raise len to next SDIO block to eliminate tail command */
- if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
- u16 pad = bus->blocksize - (len % bus->blocksize);
- if ((pad <= bus->roundup) && (pad < bus->blocksize))
- len += pad;
- } else if (len % BRCMF_SDALIGN) {
- len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
+ bus->fc_rcvd++;
+ bus->flowcontrol = fcbits;
}

- /* Some controllers have trouble with odd bytes -- round to even */
- if (forcealign && (len & (ALIGNMENT - 1)))
- len = roundup(len, ALIGNMENT);
+ /* Shouldn't be any others */
+ if (hmb_data & ~(HMB_DATA_DEVREADY |
+ HMB_DATA_NAKHANDLED |
+ HMB_DATA_FC |
+ HMB_DATA_FWREADY |
+ HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
+ brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n",
+ hmb_data);

- do {
- ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
- SDIO_FUNC_2, F2SYNC, frame,
- len, pkt);
- bus->f2txdata++;
+ return intstatus;
+}

- if (ret < 0) {
- /* On failure, abort the command
- and terminate the frame */
- brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
- ret);
- bus->tx_sderrs++;
+static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
+{
+ uint retries = 0;
+ u16 lastrbc;
+ u8 hi, lo;
+ int err;

- brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
- NULL);
- bus->f1regdata++;
+ brcmf_dbg(ERROR, "%sterminate frame%s\n",
+ abort ? "abort command, " : "",
+ rtx ? ", send NAK" : "");

- for (i = 0; i < 3; i++) {
- u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI,
- NULL);
- lo = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO,
- NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
+ if (abort)
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);

- }
- if (ret == 0)
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL,
+ SFC_RF_TERM, &err);
+ bus->f1regdata++;

- } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
+ /* Wait until the packet has been flushed (device/FIFO stable) */
+ for (lastrbc = retries = 0xffff; retries > 0; retries--) {
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_RFRAMEBCHI, NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_RFRAMEBCLO, NULL);
+ bus->f1regdata += 2;

-done:
- /* restore pkt buffer pointer before calling tx complete routine */
- skb_pull(pkt, SDPCM_HDRLEN + pad);
- brcmf_sdbrcm_sdunlock(bus);
- brcmf_txcomplete(bus->drvr, pkt, ret != 0);
- brcmf_sdbrcm_sdlock(bus);
+ if ((hi == 0) && (lo == 0))
+ break;

- if (free_pkt)
- brcmu_pkt_buf_free_skb(pkt);
+ if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
+ brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n",
+ lastrbc, (hi << 8) + lo);
+ }
+ lastrbc = (hi << 8) + lo;
+ }

- return ret;
-}
+ if (!retries)
+ brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc);
+ else
+ brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);

-int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt)
-{
- int ret = -EBADE;
- uint datalen, prec;
+ if (rtx) {
+ bus->rxrtx++;
+ w_sdreg32(bus, SMB_NAK,
+ offsetof(struct sdpcmd_regs, tosbmailbox), &retries);

- brcmf_dbg(TRACE, "Enter\n");
-
- datalen = pkt->len;
+ bus->f1regdata++;
+ if (retries <= retry_limit)
+ bus->rxskip = true;
+ }

- /* Add space for the header */
- skb_push(pkt, SDPCM_HDRLEN);
- /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
+ /* Clear partial in any case */
+ bus->nextlen = 0;

- prec = prio2prec((pkt->priority & PRIOMASK));
+ /* If we can't reach the device, signal failure */
+ if (err || brcmf_sdcard_regfail(bus->sdiodev))
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+}

- /* Check for existing queue, current flow-control,
- pending event, or pending clock */
- if (brcmf_deferred_tx || bus->fcstate || pktq_len(&bus->txq)
- || bus->dpc_sched || (!data_ok(bus))
- || (bus->flowcontrol & NBITVAL(prec))
- || (bus->clkstate != CLK_AVAIL)) {
- brcmf_dbg(TRACE, "deferring pktq len %d\n",
- pktq_len(&bus->txq));
- bus->fcqueued++;
+static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
+{
+ u16 dlen, totlen;
+ u8 *dptr, num = 0;

- /* Priority based enq */
- spin_lock_bh(&bus->txqlock);
- if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) ==
- false) {
- skb_pull(pkt, SDPCM_HDRLEN);
- brcmf_txcomplete(bus->drvr, pkt, false);
- brcmu_pkt_buf_free_skb(pkt);
- brcmf_dbg(ERROR, "out of bus->txq !!!\n");
- ret = -ENOSR;
- } else {
- ret = 0;
- }
- spin_unlock_bh(&bus->txqlock);
+ u16 sublen, check;
+ struct sk_buff *pfirst, *plast, *pnext, *save_pfirst;

- if (pktq_len(&bus->txq) >= TXHI)
- brcmf_txflowcontrol(bus->drvr, 0, ON);
+ int errcode;
+ u8 chan, seq, doff, sfdoff;
+ u8 txmax;

-#ifdef BCMDBG
- if (pktq_plen(&bus->txq, prec) > qcount[prec])
- qcount[prec] = pktq_plen(&bus->txq, prec);
-#endif
- /* Schedule DPC if needed to send queued packet(s) */
- if (brcmf_deferred_tx && !bus->dpc_sched) {
- bus->dpc_sched = true;
- brcmf_sdbrcm_sched_dpc(bus);
- }
- } else {
- /* Lock: we're about to use shared data/code (and SDIO) */
- brcmf_sdbrcm_sdlock(bus);
+ int ifidx = 0;
+ bool usechain = bus->use_rxchain;

- /* Otherwise, send it now */
- bus_wake(bus);
- /* Make sure back plane ht clk is on, no pending allowed */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
+ /* If packets, issue read(s) and send up packet chain */
+ /* Return sequence numbers consumed? */

- brcmf_dbg(TRACE, "calling txpkt\n");
- ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
- if (ret)
- bus->drvr->tx_errors++;
- else
- bus->drvr->dstats.tx_bytes += datalen;
+ brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom);

- if (bus->idletime == BRCMF_IDLE_IMMEDIATE &&
- !bus->dpc_sched) {
- bus->activity = false;
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
+ /* If there's a descriptor, generate the packet chain */
+ if (bus->glomd) {
+ pfirst = plast = pnext = NULL;
+ dlen = (u16) (bus->glomd->len);
+ dptr = bus->glomd->data;
+ if (!dlen || (dlen & 1)) {
+ brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n",
+ dlen);
+ dlen = 0;
}

- brcmf_sdbrcm_sdunlock(bus);
- }
+ for (totlen = num = 0; dlen; num++) {
+ /* Get (and move past) next length */
+ sublen = get_unaligned_le16(dptr);
+ dlen -= sizeof(u16);
+ dptr += sizeof(u16);
+ if ((sublen < SDPCM_HDRLEN) ||
+ ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
+ brcmf_dbg(ERROR, "descriptor len %d bad: %d\n",
+ num, sublen);
+ pnext = NULL;
+ break;
+ }
+ if (sublen % BRCMF_SDALIGN) {
+ brcmf_dbg(ERROR, "sublen %d not multiple of %d\n",
+ sublen, BRCMF_SDALIGN);
+ usechain = false;
+ }
+ totlen += sublen;

- return ret;
-}
+ /* For last frame, adjust read len so total
+ is a block multiple */
+ if (!dlen) {
+ sublen +=
+ (roundup(totlen, bus->blocksize) - totlen);
+ totlen = roundup(totlen, bus->blocksize);
+ }

-static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes)
-{
- struct sk_buff *pkt;
- u32 intstatus = 0;
- uint retries = 0;
- int ret = 0, prec_out;
- uint cnt = 0;
- uint datalen;
- u8 tx_prec_map;
+ /* Allocate/chain packet for next subframe */
+ pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN);
+ if (pnext == NULL) {
+ brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n",
+ num, sublen);
+ break;
+ }
+ if (!pfirst) {
+ pfirst = plast = pnext;
+ } else {
+ plast->next = pnext;
+ plast = pnext;
+ }

- struct brcmf_pub *drvr = bus->drvr;
+ /* Adhere to start alignment requirements */
+ pkt_align(pnext, sublen, BRCMF_SDALIGN);
+ }

- brcmf_dbg(TRACE, "Enter\n");
+ /* If all allocations succeeded, save packet chain
+ in bus structure */
+ if (pnext) {
+ brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n",
+ totlen, num);
+ if (BRCMF_GLOM_ON() && bus->nextlen) {
+ if (totlen != bus->nextlen) {
+ brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
+ bus->nextlen, totlen, rxseq);
+ }
+ }
+ bus->glom = pfirst;
+ pfirst = pnext = NULL;
+ } else {
+ if (pfirst)
+ brcmu_pkt_buf_free_skb(pfirst);
+ bus->glom = NULL;
+ num = 0;
+ }

- tx_prec_map = ~bus->flowcontrol;
+ /* Done with descriptor packet */
+ brcmu_pkt_buf_free_skb(bus->glomd);
+ bus->glomd = NULL;
+ bus->nextlen = 0;
+ }

- /* Send frames until the limit or some other event */
- for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) {
- spin_lock_bh(&bus->txqlock);
- pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
- if (pkt == NULL) {
- spin_unlock_bh(&bus->txqlock);
- break;
+ /* Ok -- either we just generated a packet chain,
+ or had one from before */
+ if (bus->glom) {
+ if (BRCMF_GLOM_ON()) {
+ brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
+ for (pnext = bus->glom; pnext; pnext = pnext->next) {
+ brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n",
+ pnext, (u8 *) (pnext->data),
+ pnext->len, pnext->len);
+ }
}
- spin_unlock_bh(&bus->txqlock);
- datalen = pkt->len - SDPCM_HDRLEN;

- ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
- if (ret)
- bus->drvr->tx_errors++;
- else
- bus->drvr->dstats.tx_bytes += datalen;
+ pfirst = bus->glom;
+ dlen = (u16) brcmu_pkttotlen(pfirst);

- /* In poll mode, need to check for other events */
- if (!bus->intr && cnt) {
- /* Check device status, signal pending interrupt */
- r_sdreg32(bus, &intstatus,
- offsetof(struct sdpcmd_regs, intstatus),
- &retries);
- bus->f2txdata++;
- if (brcmf_sdcard_regfail(bus->sdiodev))
- break;
- if (intstatus & bus->hostintmask)
- bus->ipend = true;
+ /* Do an SDIO read for the superframe. Configurable iovar to
+ * read directly into the chained packet, or allocate a large
+ * packet and and copy into the chain.
+ */
+ if (usechain) {
+ errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
+ bus->sdiodev->sbwad,
+ SDIO_FUNC_2,
+ F2SYNC, (u8 *) pfirst->data, dlen,
+ pfirst);
+ } else if (bus->dataptr) {
+ errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
+ bus->sdiodev->sbwad,
+ SDIO_FUNC_2,
+ F2SYNC, bus->dataptr, dlen,
+ NULL);
+ sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen,
+ bus->dataptr);
+ if (sublen != dlen) {
+ brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
+ dlen, sublen);
+ errcode = -1;
+ }
+ pnext = NULL;
+ } else {
+ brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n",
+ dlen);
+ errcode = -1;
}
- }
-
- /* Deflow-control stack if needed */
- if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) &&
- drvr->txoff && (pktq_len(&bus->txq) < TXLOW))
- brcmf_txflowcontrol(drvr, 0, OFF);
+ bus->f2rxdata++;

- return cnt;
-}
+ /* On failure, kill the superframe, allow a couple retries */
+ if (errcode < 0) {
+ brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n",
+ dlen, errcode);
+ bus->drvr->rx_errors++;

-int
-brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
-{
- u8 *frame;
- u16 len;
- u32 swheader;
- uint retries = 0;
- u8 doff = 0;
- int ret = -1;
- int i;
-
- brcmf_dbg(TRACE, "Enter\n");
+ if (bus->glomerr++ < 3) {
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ } else {
+ bus->glomerr = 0;
+ brcmf_sdbrcm_rxfail(bus, true, false);
+ brcmu_pkt_buf_free_skb(bus->glom);
+ bus->rxglomfail++;
+ bus->glom = NULL;
+ }
+ return 0;
+ }
+#ifdef BCMDBG
+ if (BRCMF_GLOM_ON()) {
+ printk(KERN_DEBUG "SUPERFRAME:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ pfirst->data, min_t(int, pfirst->len, 48));
+ }
+#endif

- if (bus->drvr->dongle_reset)
- return -EIO;
+ /* Validate the superframe header */
+ dptr = (u8 *) (pfirst->data);
+ sublen = get_unaligned_le16(dptr);
+ check = get_unaligned_le16(dptr + sizeof(u16));

- /* Back the pointer to make a room for bus header */
- frame = msg - SDPCM_HDRLEN;
- len = (msglen += SDPCM_HDRLEN);
+ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
+ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
+ bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
+ if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
+ brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n",
+ bus->nextlen, seq);
+ bus->nextlen = 0;
+ }
+ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
+ txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);

- /* Add alignment padding (optional for ctl frames) */
- if (brcmf_alignctl) {
- doff = ((unsigned long)frame % BRCMF_SDALIGN);
- if (doff) {
- frame -= doff;
- len += doff;
- msglen += doff;
- memset(frame, 0, doff + SDPCM_HDRLEN);
+ errcode = 0;
+ if ((u16)~(sublen ^ check)) {
+ brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
+ sublen, check);
+ errcode = -1;
+ } else if (roundup(sublen, bus->blocksize) != dlen) {
+ brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
+ sublen, roundup(sublen, bus->blocksize),
+ dlen);
+ errcode = -1;
+ } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) !=
+ SDPCM_GLOM_CHANNEL) {
+ brcmf_dbg(ERROR, "(superframe): bad channel %d\n",
+ SDPCM_PACKET_CHANNEL(
+ &dptr[SDPCM_FRAMETAG_LEN]));
+ errcode = -1;
+ } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
+ brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n");
+ errcode = -1;
+ } else if ((doff < SDPCM_HDRLEN) ||
+ (doff > (pfirst->len - SDPCM_HDRLEN))) {
+ brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n",
+ doff, sublen, pfirst->len, SDPCM_HDRLEN);
+ errcode = -1;
}
- /* precondition: doff < BRCMF_SDALIGN */
- }
- doff += SDPCM_HDRLEN;

- /* Round send length to next SDIO block */
- if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
- u16 pad = bus->blocksize - (len % bus->blocksize);
- if ((pad <= bus->roundup) && (pad < bus->blocksize))
- len += pad;
- } else if (len % BRCMF_SDALIGN) {
- len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
- }
+ /* Check sequence number of superframe SW header */
+ if (rxseq != seq) {
+ brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
+ seq, rxseq);
+ bus->rx_badseq++;
+ rxseq = seq;
+ }

- /* Satisfy length-alignment requirements */
- if (forcealign && (len & (ALIGNMENT - 1)))
- len = roundup(len, ALIGNMENT);
+ /* Check window for sanity */
+ if ((u8) (txmax - bus->tx_seq) > 0x40) {
+ brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
+ txmax, bus->tx_seq);
+ txmax = bus->tx_seq + 2;
+ }
+ bus->tx_max = txmax;

- /* precondition: IS_ALIGNED((unsigned long)frame, 2) */
+ /* Remove superframe header, remember offset */
+ skb_pull(pfirst, doff);
+ sfdoff = doff;

- /* Need to lock here to protect txseq and SDIO tx calls */
- brcmf_sdbrcm_sdlock(bus);
+ /* Validate all the subframe headers */
+ for (num = 0, pnext = pfirst; pnext && !errcode;
+ num++, pnext = pnext->next) {
+ dptr = (u8 *) (pnext->data);
+ dlen = (u16) (pnext->len);
+ sublen = get_unaligned_le16(dptr);
+ check = get_unaligned_le16(dptr + sizeof(u16));
+ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
+ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
+#ifdef BCMDBG
+ if (BRCMF_GLOM_ON()) {
+ printk(KERN_DEBUG "subframe:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ dptr, 32);
+ }
+#endif

- bus_wake(bus);
+ if ((u16)~(sublen ^ check)) {
+ brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n",
+ num, sublen, check);
+ errcode = -1;
+ } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
+ brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n",
+ num, sublen, dlen);
+ errcode = -1;
+ } else if ((chan != SDPCM_DATA_CHANNEL) &&
+ (chan != SDPCM_EVENT_CHANNEL)) {
+ brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n",
+ num, chan);
+ errcode = -1;
+ } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
+ brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n",
+ num, doff, sublen, SDPCM_HDRLEN);
+ errcode = -1;
+ }
+ }

- /* Make sure backplane clock is on */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ if (errcode) {
+ /* Terminate frame on error, request
+ a couple retries */
+ if (bus->glomerr++ < 3) {
+ /* Restore superframe header space */
+ skb_push(pfirst, sfdoff);
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ } else {
+ bus->glomerr = 0;
+ brcmf_sdbrcm_rxfail(bus, true, false);
+ brcmu_pkt_buf_free_skb(bus->glom);
+ bus->rxglomfail++;
+ bus->glom = NULL;
+ }
+ bus->nextlen = 0;
+ return 0;
+ }

- /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
- *(u16 *) frame = cpu_to_le16((u16) msglen);
- *(((u16 *) frame) + 1) = cpu_to_le16(~msglen);
+ /* Basic SD framing looks ok - process each packet (header) */
+ save_pfirst = pfirst;
+ bus->glom = NULL;
+ plast = NULL;

- /* Software tag: channel, sequence number, data offset */
- swheader =
- ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
- SDPCM_CHANNEL_MASK)
- | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) &
- SDPCM_DOFFSET_MASK);
- put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
- put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+ for (num = 0; pfirst; rxseq++, pfirst = pnext) {
+ pnext = pfirst->next;
+ pfirst->next = NULL;

- if (!data_ok(bus)) {
- brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
- bus->tx_max, bus->tx_seq);
- bus->ctrl_frame_stat = true;
- /* Send from dpc */
- bus->ctrl_frame_buf = frame;
- bus->ctrl_frame_len = len;
+ dptr = (u8 *) (pfirst->data);
+ sublen = get_unaligned_le16(dptr);
+ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
+ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
+ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);

- brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat);
+ brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
+ num, pfirst, pfirst->data,
+ pfirst->len, sublen, chan, seq);

- if (bus->ctrl_frame_stat == false) {
- brcmf_dbg(INFO, "ctrl_frame_stat == false\n");
- ret = 0;
- } else {
- brcmf_dbg(INFO, "ctrl_frame_stat == true\n");
- ret = -1;
- }
- }
+ /* precondition: chan == SDPCM_DATA_CHANNEL ||
+ chan == SDPCM_EVENT_CHANNEL */

- if (ret == -1) {
+ if (rxseq != seq) {
+ brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
+ seq, rxseq);
+ bus->rx_badseq++;
+ rxseq = seq;
+ }
#ifdef BCMDBG
- if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
- printk(KERN_DEBUG "Tx Frame:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- frame, len);
- } else if (BRCMF_HDRS_ON()) {
- printk(KERN_DEBUG "TxHdr:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- frame, min_t(u16, len, 16));
- }
+ if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
+ printk(KERN_DEBUG "Rx Subframe Data:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ dptr, dlen);
+ }
#endif

- do {
- bus->ctrl_frame_stat = false;
- ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
- SDIO_FUNC_2, F2SYNC, frame, len, NULL);
-
- if (ret < 0) {
- /* On failure, abort the command and
- terminate the frame */
- brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
- ret);
- bus->tx_sderrs++;
-
- brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+ __skb_trim(pfirst, sublen);
+ skb_pull(pfirst, doff);

- brcmf_sdcard_cfg_write(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, NULL);
- bus->f1regdata++;
+ if (pfirst->len == 0) {
+ brcmu_pkt_buf_free_skb(pfirst);
+ if (plast)
+ plast->next = pnext;
+ else
+ save_pfirst = pnext;

- for (i = 0; i < 3; i++) {
- u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI,
- NULL);
- lo = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO,
- NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
+ continue;
+ } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx,
+ pfirst) != 0) {
+ brcmf_dbg(ERROR, "rx protocol error\n");
+ bus->drvr->rx_errors++;
+ brcmu_pkt_buf_free_skb(pfirst);
+ if (plast)
+ plast->next = pnext;
+ else
+ save_pfirst = pnext;

+ continue;
}
- if (ret == 0)
- bus->tx_seq =
- (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
-
- } while ((ret < 0) && retries++ < TXRETRIES);
- }
-
- if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) {
- bus->activity = false;
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
- }

- brcmf_sdbrcm_sdunlock(bus);
+ /* this packet will go up, link back into
+ chain and count it */
+ pfirst->next = pnext;
+ plast = pfirst;
+ num++;

- if (ret)
- bus->drvr->tx_ctlerrs++;
- else
- bus->drvr->tx_ctlpkts++;
+#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,
+ pfirst->len, pfirst->next,
+ pfirst->prev);
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ pfirst->data,
+ min_t(int, pfirst->len, 32));
+ }
+#endif /* BCMDBG */
+ }
+ if (num) {
+ brcmf_sdbrcm_sdunlock(bus);
+ brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num);
+ brcmf_sdbrcm_sdlock(bus);
+ }

- return ret ? -EIO : 0;
+ bus->rxglomframes++;
+ bus->rxglompkts += num;
+ }
+ return num;
}

-int
-brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
+static int brcmf_sdbrcm_ioctl_resp_wait(struct brcmf_bus *bus, uint *condition,
+ bool *pending)
{
- int timeleft;
- uint rxlen = 0;
- bool pending;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- if (bus->drvr->dongle_reset)
- return -EIO;
+ DECLARE_WAITQUEUE(wait, current);
+ int timeout = msecs_to_jiffies(brcmf_ioctl_timeout_msec);

/* Wait until control frame is available */
- timeleft = brcmf_sdbrcm_ioctl_resp_wait(bus, &bus->rxlen, &pending);
+ add_wait_queue(&bus->ioctl_resp_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);

- brcmf_sdbrcm_sdlock(bus);
- rxlen = bus->rxlen;
- memcpy(msg, bus->rxctl, min(msglen, rxlen));
- bus->rxlen = 0;
- brcmf_sdbrcm_sdunlock(bus);
+ while (!(*condition) && (!signal_pending(current) && timeout))
+ timeout = schedule_timeout(timeout);

- if (rxlen) {
- brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
- rxlen, msglen);
- } else if (timeleft == 0) {
- brcmf_dbg(ERROR, "resumed on timeout\n");
-#ifdef BCMDBG
- brcmf_sdbrcm_sdlock(bus);
- brcmf_sdbrcm_checkdied(bus, NULL, 0);
- brcmf_sdbrcm_sdunlock(bus);
-#endif /* BCMDBG */
- } else if (pending == true) {
- brcmf_dbg(CTL, "cancelled\n");
- return -ERESTARTSYS;
- } else {
- brcmf_dbg(CTL, "resumed for unknown reason?\n");
-#ifdef BCMDBG
- brcmf_sdbrcm_sdlock(bus);
- brcmf_sdbrcm_checkdied(bus, NULL, 0);
- brcmf_sdbrcm_sdunlock(bus);
-#endif /* BCMDBG */
- }
+ if (signal_pending(current))
+ *pending = true;

- if (rxlen)
- bus->drvr->rx_ctlpkts++;
- else
- bus->drvr->rx_ctlerrs++;
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&bus->ioctl_resp_wait, &wait);

- return rxlen ? (int)rxlen : -ETIMEDOUT;
+ return timeout;
}

-static int
-brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data,
- uint size)
+static int brcmf_sdbrcm_ioctl_resp_wake(struct brcmf_bus *bus)
{
- int bcmerror = 0;
- u32 sdaddr;
- uint dsize;
+ if (waitqueue_active(&bus->ioctl_resp_wait))
+ wake_up_interruptible(&bus->ioctl_resp_wait);

- /* Determine initial transfer parameters */
- sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
- if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
- dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
- else
- dsize = size;
+ return 0;
+}
+static void
+brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff)
+{
+ uint rdlen, pad;

- /* Set the backplane window to include the start address */
- bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address);
- if (bcmerror) {
- brcmf_dbg(ERROR, "window change failed\n");
- goto xfer_done;
+ int sdret;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Set rxctl for frame (w/optional alignment) */
+ bus->rxctl = bus->rxbuf;
+ if (brcmf_alignctl) {
+ bus->rxctl += firstread;
+ pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN);
+ if (pad)
+ bus->rxctl += (BRCMF_SDALIGN - pad);
+ bus->rxctl -= firstread;
}

- /* Do the transfer(s) */
- while (size) {
- brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
- write ? "write" : "read", dsize,
- sdaddr, address & SBSDIO_SBWINDOW_MASK);
- bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write,
- sdaddr, data, dsize);
- if (bcmerror) {
- brcmf_dbg(ERROR, "membytes transfer failed\n");
- break;
- }
+ /* Copy the already-read portion over */
+ memcpy(bus->rxctl, hdr, firstread);
+ if (len <= firstread)
+ goto gotpkt;

- /* Adjust for next transfer (if any) */
- size -= dsize;
- if (size) {
- data += dsize;
- address += dsize;
- bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev,
- address);
- if (bcmerror) {
- brcmf_dbg(ERROR, "window change failed\n");
- break;
- }
- sdaddr = 0;
- dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
- }
+ /* Raise rdlen to next SDIO block to avoid tail command */
+ rdlen = len - firstread;
+ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
+ pad = bus->blocksize - (rdlen % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
+ ((len + pad) < bus->drvr->maxctl))
+ rdlen += pad;
+ } else if (rdlen % BRCMF_SDALIGN) {
+ rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
}

-xfer_done:
- /* Return the window to backplane enumeration space for core access */
- if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad))
- brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n",
- bus->sdiodev->sbwad);
+ /* Satisfy length-alignment requirements */
+ if (forcealign && (rdlen & (ALIGNMENT - 1)))
+ rdlen = roundup(rdlen, ALIGNMENT);

- return bcmerror;
-}
+ /* Drop if the read is too big or it exceeds our maximum */
+ if ((rdlen + firstread) > bus->drvr->maxctl) {
+ brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n",
+ rdlen, bus->drvr->maxctl);
+ bus->drvr->rx_errors++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ goto done;
+ }

-#ifdef BCMDBG
-static int
-brcmf_sdbrcm_readshared(struct brcmf_bus *bus, struct sdpcm_shared *sh)
-{
- u32 addr;
- int rv;
+ if ((len - doff) > bus->drvr->maxctl) {
+ brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
+ len, len - doff, bus->drvr->maxctl);
+ bus->drvr->rx_errors++;
+ bus->rx_toolong++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ goto done;
+ }

- /* Read last word in memory to determine address of
- sdpcm_shared structure */
- rv = brcmf_sdbrcm_membytes(bus, false, bus->ramsize - 4, (u8 *)&addr,
- 4);
- if (rv < 0)
- return rv;
+ /* Read remainder of frame body into the rxctl buffer */
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
+ bus->sdiodev->sbwad,
+ SDIO_FUNC_2,
+ F2SYNC, (bus->rxctl + firstread), rdlen,
+ NULL);
+ bus->f2rxdata++;

- addr = le32_to_cpu(addr);
+ /* Control frame failures need retransmission */
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "read %d control bytes failed: %d\n",
+ rdlen, sdret);
+ bus->rxc_errors++;
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ goto done;
+ }

- brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr);
+gotpkt:

- /*
- * Check if addr is valid.
- * NVRAM length at the end of memory should have been overwritten.
- */
- if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
- brcmf_dbg(ERROR, "address (0x%08x) of sdpcm_shared invalid\n",
- addr);
- return -EBADE;
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
+ printk(KERN_DEBUG "RxCtrl:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len);
}
+#endif

- /* Read rte_shared structure */
- rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *) sh,
- sizeof(struct sdpcm_shared));
- if (rv < 0)
- return rv;
-
- /* Endianness */
- sh->flags = le32_to_cpu(sh->flags);
- sh->trap_addr = le32_to_cpu(sh->trap_addr);
- sh->assert_exp_addr = le32_to_cpu(sh->assert_exp_addr);
- sh->assert_file_addr = le32_to_cpu(sh->assert_file_addr);
- sh->assert_line = le32_to_cpu(sh->assert_line);
- sh->console_addr = le32_to_cpu(sh->console_addr);
- sh->msgtrace_addr = le32_to_cpu(sh->msgtrace_addr);
-
- if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
- brcmf_dbg(ERROR, "sdpcm_shared version %d in brcmf is different than sdpcm_shared version %d in dongle\n",
- SDPCM_SHARED_VERSION,
- sh->flags & SDPCM_SHARED_VERSION_MASK);
- return -EBADE;
- }
+ /* Point to valid data and indicate its length */
+ bus->rxctl += doff;
+ bus->rxlen = len - doff;

- return 0;
+done:
+ /* Awake any waiters */
+ brcmf_sdbrcm_ioctl_resp_wake(bus);
}

-static int brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, u8 *data, uint size)
+/* Return true if there may be more frames to read */
+static uint
+brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
{
- int bcmerror = 0;
- uint msize = 512;
- char *mbuffer = NULL;
- uint maxstrlen = 256;
- char *str = NULL;
- struct brcmf_trap tr;
- struct sdpcm_shared sdpcm_shared;
- struct brcmu_strbuf strbuf;
-
- brcmf_dbg(TRACE, "Enter\n");
+ u16 len, check; /* Extracted hardware header fields */
+ u8 chan, seq, doff; /* Extracted software header fields */
+ u8 fcbits; /* Extracted fcbits from software header */

- if (data == NULL) {
- /*
- * Called after a rx ctrl timeout. "data" is NULL.
- * allocate memory to trace the trap or assert.
- */
- size = msize;
- mbuffer = data = kmalloc(msize, GFP_ATOMIC);
- if (mbuffer == NULL) {
- brcmf_dbg(ERROR, "kmalloc(%d) failed\n", msize);
- bcmerror = -ENOMEM;
- goto done;
- }
- }
+ struct sk_buff *pkt; /* Packet for event or data frames */
+ u16 pad; /* Number of pad bytes to read */
+ u16 rdlen; /* Total number of bytes to read */
+ u8 rxseq; /* Next sequence number to expect */
+ uint rxleft = 0; /* Remaining number of frames allowed */
+ int sdret; /* Return code from calls */
+ u8 txmax; /* Maximum tx sequence offered */
+ bool len_consistent; /* Result of comparing readahead len and
+ len from hw-hdr */
+ u8 *rxbuf;
+ int ifidx = 0;
+ uint rxcount = 0; /* Total frames read */

- str = kmalloc(maxstrlen, GFP_ATOMIC);
- if (str == NULL) {
- brcmf_dbg(ERROR, "kmalloc(%d) failed\n", maxstrlen);
- bcmerror = -ENOMEM;
- goto done;
- }
+ brcmf_dbg(TRACE, "Enter\n");

- bcmerror = brcmf_sdbrcm_readshared(bus, &sdpcm_shared);
- if (bcmerror < 0)
- goto done;
+ /* Not finished unless we encounter no more frames indication */
+ *finished = false;

- brcmu_binit(&strbuf, data, size);
+ for (rxseq = bus->rx_seq, rxleft = maxframes;
+ !bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN;
+ rxseq++, rxleft--) {

- brcmu_bprintf(&strbuf,
- "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
- sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
+ /* Handle glomming separately */
+ if (bus->glom || bus->glomd) {
+ u8 cnt;
+ brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
+ bus->glomd, bus->glom);
+ cnt = brcmf_sdbrcm_rxglom(bus, rxseq);
+ brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
+ rxseq += cnt - 1;
+ rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
+ continue;
+ }

- if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)
- /* NOTE: Misspelled assert is intentional - DO NOT FIX.
- * (Avoids conflict with real asserts for programmatic
- * parsing of output.)
- */
- brcmu_bprintf(&strbuf, "Assrt not built in dongle\n");
+ /* Try doing single read if we can */
+ if (brcmf_readahead && bus->nextlen) {
+ u16 nextlen = bus->nextlen;
+ bus->nextlen = 0;

- if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) ==
- 0) {
- /* NOTE: Misspelled assert is intentional - DO NOT FIX.
- * (Avoids conflict with real asserts for programmatic
- * parsing of output.)
- */
- brcmu_bprintf(&strbuf, "No trap%s in dongle",
- (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
- ? "/assrt" : "");
- } else {
- if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
- /* Download assert */
- brcmu_bprintf(&strbuf, "Dongle assert");
- if (sdpcm_shared.assert_exp_addr != 0) {
- str[0] = '\0';
- bcmerror = brcmf_sdbrcm_membytes(bus, false,
- sdpcm_shared.assert_exp_addr,
- (u8 *) str, maxstrlen);
- if (bcmerror < 0)
- goto done;
+ rdlen = len = nextlen << 4;

- str[maxstrlen - 1] = '\0';
- brcmu_bprintf(&strbuf, " expr \"%s\"", str);
+ /* Pad read to blocksize for efficiency */
+ if (bus->roundup && bus->blocksize
+ && (rdlen > bus->blocksize)) {
+ pad =
+ bus->blocksize -
+ (rdlen % bus->blocksize);
+ if ((pad <= bus->roundup)
+ && (pad < bus->blocksize)
+ && ((rdlen + pad + firstread) <
+ MAX_RX_DATASZ))
+ rdlen += pad;
+ } else if (rdlen % BRCMF_SDALIGN) {
+ rdlen += BRCMF_SDALIGN -
+ (rdlen % BRCMF_SDALIGN);
}

- if (sdpcm_shared.assert_file_addr != 0) {
- str[0] = '\0';
- bcmerror = brcmf_sdbrcm_membytes(bus, false,
- sdpcm_shared.assert_file_addr,
- (u8 *) str, maxstrlen);
- if (bcmerror < 0)
- goto done;
+ /* We use bus->rxctl buffer in WinXP for initial
+ * control pkt receives.
+ * Later we use buffer-poll for data as well
+ * as control packets.
+ * This is required because dhd receives full
+ * frame in gSPI unlike SDIO.
+ * After the frame is received we have to
+ * distinguish whether it is data
+ * or non-data frame.
+ */
+ /* Allocate a packet buffer */
+ pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN);
+ if (!pkt) {
+ /* Give up on data, request rtx of events */
+ brcmf_dbg(ERROR, "(nextlen): brcmu_pkt_buf_get_skb failed: len %d rdlen %d expected rxseq %d\n",
+ len, rdlen, rxseq);
+ continue;
+ } else {
+ 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);
+ bus->f2rxdata++;

- str[maxstrlen - 1] = '\0';
- brcmu_bprintf(&strbuf, " file \"%s\"", str);
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n",
+ rdlen, sdret);
+ brcmu_pkt_buf_free_skb(pkt);
+ bus->drvr->rx_errors++;
+ /* Force retry w/normal header read.
+ * Don't attempt NAK for
+ * gSPI
+ */
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ continue;
+ }
}

- brcmu_bprintf(&strbuf, " line %d ",
- sdpcm_shared.assert_line);
- }
-
- if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
- bcmerror = brcmf_sdbrcm_membytes(bus, false,
- sdpcm_shared.trap_addr, (u8 *)&tr,
- sizeof(struct brcmf_trap));
- if (bcmerror < 0)
- goto done;
-
- brcmu_bprintf(&strbuf,
- "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
- "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
- "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
- tr.type, tr.epc, tr.cpsr, tr.spsr, tr.r13,
- tr.r14, tr.pc, sdpcm_shared.trap_addr,
- tr.r0, tr.r1, tr.r2, tr.r3, tr.r4, tr.r5,
- tr.r6, tr.r7);
- }
- }
+ /* Now check the header */
+ memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN);

- if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP))
- brcmf_dbg(ERROR, "%s\n", strbuf.origbuf);
+ /* Extract hardware header fields */
+ len = get_unaligned_le16(bus->rxhdr);
+ check = get_unaligned_le16(bus->rxhdr + sizeof(u16));

-#ifdef BCMDBG
- if (sdpcm_shared.flags & SDPCM_SHARED_TRAP)
- /* Mem dump to a file on device */
- brcmf_sdbrcm_mem_dump(bus);
+ /* All zeros means readahead info was bad */
+ if (!(len | check)) {
+ brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n");
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ continue;
+ }

-#endif /* BCMDBG */
+ /* Validate check bytes */
+ if ((u16)~(len ^ check)) {
+ brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n",
+ nextlen, len, check);
+ bus->rx_badhdr++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ continue;
+ }

-done:
- kfree(mbuffer);
- kfree(str);
+ /* Validate frame length */
+ if (len < SDPCM_HDRLEN) {
+ brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n",
+ len);
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ continue;
+ }

- return bcmerror;
-}
+ /* Check for consistency withreadahead info */
+ len_consistent = (nextlen != (roundup(len, 16) >> 4));
+ if (len_consistent) {
+ /* Mismatch, force retry w/normal
+ header (may be >4K) */
+ brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n",
+ nextlen, len, roundup(len, 16),
+ rxseq);
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ continue;
+ }

-static int brcmf_sdbrcm_mem_dump(struct brcmf_bus *bus)
-{
- int ret = 0;
- int size; /* Full mem size */
- int start = 0; /* Start address */
- int read_size = 0; /* Read size of each iteration */
- u8 *buf = NULL, *databuf = NULL;
+ /* Extract software header fields */
+ chan = SDPCM_PACKET_CHANNEL(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ seq = SDPCM_PACKET_SEQUENCE(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ doff = SDPCM_DOFFSET_VALUE(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ txmax = SDPCM_WINDOW_VALUE(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);

- /* Get full mem size */
- size = bus->ramsize;
- buf = kmalloc(size, GFP_ATOMIC);
- if (!buf) {
- brcmf_dbg(ERROR, "Out of memory (%d bytes)\n", size);
- return -1;
- }
+ bus->nextlen =
+ bus->rxhdr[SDPCM_FRAMETAG_LEN +
+ SDPCM_NEXTLEN_OFFSET];
+ if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
+ brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
+ bus->nextlen, seq);
+ bus->nextlen = 0;
+ }

- /* Read mem content */
- printk(KERN_DEBUG "Dump dongle memory");
- databuf = buf;
- while (size) {
- read_size = min(MEMBLOCK, size);
- ret = brcmf_sdbrcm_membytes(bus, false, start, databuf,
- read_size);
- if (ret) {
- brcmf_dbg(ERROR, "Error membytes %d\n", ret);
- kfree(buf);
- return -1;
- }
- printk(".");
+ bus->drvr->rx_readahead_cnt++;

- /* Decrement size and increment start address */
- size -= read_size;
- start += read_size;
- databuf += read_size;
- }
- printk(KERN_DEBUG "Done\n");
+ /* Handle Flow Control */
+ fcbits = SDPCM_FCMASK_VALUE(
+ &bus->rxhdr[SDPCM_FRAMETAG_LEN]);

- /* free buf before return !!! */
- if (brcmf_write_to_file(bus->drvr, buf, bus->ramsize)) {
- brcmf_dbg(ERROR, "Error writing to files\n");
- return -1;
- }
+ if (bus->flowcontrol != fcbits) {
+ if (~bus->flowcontrol & fcbits)
+ bus->fc_xoff++;

- /* buf free handled in brcmf_write_to_file, not here */
- return 0;
-}
+ if (bus->flowcontrol & ~fcbits)
+ bus->fc_xon++;

-#define CONSOLE_LINE_MAX 192
+ bus->fc_rcvd++;
+ bus->flowcontrol = fcbits;
+ }

-static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus)
-{
- struct brcmf_console *c = &bus->console;
- u8 line[CONSOLE_LINE_MAX], ch;
- u32 n, idx, addr;
- int rv;
+ /* Check and update sequence number */
+ if (rxseq != seq) {
+ brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n",
+ seq, rxseq);
+ bus->rx_badseq++;
+ rxseq = seq;
+ }

- /* Don't do anything until FWREADY updates console address */
- if (bus->console_addr == 0)
- return 0;
+ /* Check window for sanity */
+ if ((u8) (txmax - bus->tx_seq) > 0x40) {
+ brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n",
+ txmax, bus->tx_seq);
+ txmax = bus->tx_seq + 2;
+ }
+ bus->tx_max = txmax;

- /* Read console log struct */
- addr = bus->console_addr + offsetof(struct rte_console, log);
- rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log,
- sizeof(c->log));
- if (rv < 0)
- return rv;
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
+ printk(KERN_DEBUG "Rx Data:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ rxbuf, len);
+ } else if (BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "RxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ bus->rxhdr, SDPCM_HDRLEN);
+ }
+#endif

- /* Allocate console buffer (one time only) */
- if (c->buf == NULL) {
- c->bufsize = le32_to_cpu(c->log.buf_size);
- c->buf = kmalloc(c->bufsize, GFP_ATOMIC);
- if (c->buf == NULL)
- return -ENOMEM;
- }
+ if (chan == SDPCM_CONTROL_CHANNEL) {
+ brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n",
+ seq);
+ /* Force retry w/normal header read */
+ bus->nextlen = 0;
+ brcmf_sdbrcm_rxfail(bus, false, true);
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ continue;
+ }

- idx = le32_to_cpu(c->log.idx);
+ /* Validate data offset */
+ if ((doff < SDPCM_HDRLEN) || (doff > len)) {
+ brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n",
+ doff, len, SDPCM_HDRLEN);
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ continue;
+ }

- /* Protect against corrupt value */
- if (idx > c->bufsize)
- return -EBADE;
+ /* All done with this one -- now deliver the packet */
+ goto deliver;
+ }

- /* Skip reading the console buffer if the index pointer
- has not moved */
- if (idx == c->last)
- return 0;
+ /* Read frame header (hardware and software) */
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, bus->rxhdr, firstread,
+ NULL);
+ bus->f2rxhdrs++;

- /* Read the console buffer */
- addr = le32_to_cpu(c->log.buf);
- rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize);
- if (rv < 0)
- return rv;
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret);
+ bus->rx_hdrfail++;
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ continue;
+ }
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() || BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "RxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ bus->rxhdr, SDPCM_HDRLEN);
+ }
+#endif

- while (c->last != idx) {
- for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
- if (c->last == idx) {
- /* This would output a partial line.
- * Instead, back up
- * the buffer pointer and output this
- * line next time around.
- */
- if (c->last >= n)
- c->last -= n;
- else
- c->last = c->bufsize - n;
- goto break2;
- }
- ch = c->buf[c->last];
- c->last = (c->last + 1) % c->bufsize;
- if (ch == '\n')
- break;
- line[n] = ch;
+ /* Extract hardware header fields */
+ len = get_unaligned_le16(bus->rxhdr);
+ check = get_unaligned_le16(bus->rxhdr + sizeof(u16));
+
+ /* All zeros means no more frames */
+ if (!(len | check)) {
+ *finished = true;
+ break;
}

- if (n > 0) {
- if (line[n - 1] == '\r')
- n--;
- line[n] = 0;
- printk(KERN_DEBUG "CONSOLE: %s\n", line);
+ /* Validate check bytes */
+ if ((u16) ~(len ^ check)) {
+ brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n",
+ len, check);
+ bus->rx_badhdr++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ continue;
}
- }
-break2:

- return 0;
-}
-#endif /* BCMDBG */
+ /* Validate frame length */
+ if (len < SDPCM_HDRLEN) {
+ brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len);
+ continue;
+ }

-static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len)
-{
- int bcmerror = 0;
+ /* Extract software header fields */
+ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);

- brcmf_dbg(TRACE, "Enter\n");
+ /* Validate data offset */
+ if ((doff < SDPCM_HDRLEN) || (doff > len)) {
+ brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n",
+ doff, len, SDPCM_HDRLEN, seq);
+ bus->rx_badhdr++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ continue;
+ }

- /* Basic sanity checks */
- if (bus->drvr->up) {
- bcmerror = -EISCONN;
- goto err;
- }
- if (!len) {
- bcmerror = -EOVERFLOW;
- goto err;
- }
-
- /* Free the old ones and replace with passed variables */
- kfree(bus->vars);
-
- bus->vars = kmalloc(len, GFP_ATOMIC);
- bus->varsz = bus->vars ? len : 0;
- if (bus->vars == NULL) {
- bcmerror = -ENOMEM;
- goto err;
- }
-
- /* Copy the passed variables, which should include the
- terminating double-null */
- memcpy(bus->vars, arg, bus->varsz);
-err:
- return bcmerror;
-}
-
-static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
-{
- int bcmerror = 0;
- u32 varsize;
- u32 varaddr;
- u8 *vbuffer;
- u32 varsizew;
-#ifdef BCMDBG
- char *nvram_ularray;
-#endif /* BCMDBG */
+ /* Save the readahead length if there is one */
+ bus->nextlen =
+ bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
+ if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
+ brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
+ bus->nextlen, seq);
+ bus->nextlen = 0;
+ }

- /* Even if there are no vars are to be written, we still
- need to set the ramsize. */
- varsize = bus->varsz ? roundup(bus->varsz, 4) : 0;
- varaddr = (bus->ramsize - 4) - varsize;
+ /* Handle Flow Control */
+ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);

- if (bus->vars) {
- vbuffer = kzalloc(varsize, GFP_ATOMIC);
- if (!vbuffer)
- return -ENOMEM;
+ if (bus->flowcontrol != fcbits) {
+ if (~bus->flowcontrol & fcbits)
+ bus->fc_xoff++;

- memcpy(vbuffer, bus->vars, bus->varsz);
+ if (bus->flowcontrol & ~fcbits)
+ bus->fc_xon++;

- /* Write the vars list */
- bcmerror =
- brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize);
-#ifdef BCMDBG
- /* Verify NVRAM bytes */
- brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize);
- nvram_ularray = kmalloc(varsize, GFP_ATOMIC);
- if (!nvram_ularray)
- return -ENOMEM;
+ bus->fc_rcvd++;
+ bus->flowcontrol = fcbits;
+ }

- /* Upload image to verify downloaded contents. */
- memset(nvram_ularray, 0xaa, varsize);
+ /* Check and update sequence number */
+ if (rxseq != seq) {
+ brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq);
+ bus->rx_badseq++;
+ rxseq = seq;
+ }

- /* Read the vars list to temp buffer for comparison */
- bcmerror =
- brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray,
- varsize);
- if (bcmerror) {
- brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n",
- bcmerror, varsize, varaddr);
+ /* Check window for sanity */
+ if ((u8) (txmax - bus->tx_seq) > 0x40) {
+ brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
+ txmax, bus->tx_seq);
+ txmax = bus->tx_seq + 2;
}
- /* Compare the org NVRAM with the one read from RAM */
- if (memcmp(vbuffer, nvram_ularray, varsize))
- brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n");
- else
- brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n");
+ bus->tx_max = txmax;

- kfree(nvram_ularray);
-#endif /* BCMDBG */
+ /* Call a separate function for control frames */
+ if (chan == SDPCM_CONTROL_CHANNEL) {
+ brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff);
+ continue;
+ }

- kfree(vbuffer);
- }
+ /* precondition: chan is either SDPCM_DATA_CHANNEL,
+ SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or
+ SDPCM_GLOM_CHANNEL */

- /* adjust to the user specified RAM */
- brcmf_dbg(INFO, "Physical memory size: %d, usable memory size: %d\n",
- bus->orig_ramsize, bus->ramsize);
- brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n",
- varaddr, varsize);
- varsize = ((bus->orig_ramsize - 4) - varaddr);
+ /* Length to read */
+ rdlen = (len > firstread) ? (len - firstread) : 0;

- /*
- * Determine the length token:
- * Varsize, converted to words, in lower 16-bits, checksum
- * in upper 16-bits.
- */
- if (bcmerror) {
- varsizew = 0;
- } else {
- varsizew = varsize / 4;
- varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
- varsizew = cpu_to_le32(varsizew);
- }
+ /* May pad read to blocksize for efficiency */
+ if (bus->roundup && bus->blocksize &&
+ (rdlen > bus->blocksize)) {
+ pad = bus->blocksize - (rdlen % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
+ ((rdlen + pad + firstread) < MAX_RX_DATASZ))
+ rdlen += pad;
+ } else if (rdlen % BRCMF_SDALIGN) {
+ rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
+ }

- brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n",
- varsize, varsizew);
+ /* Satisfy length-alignment requirements */
+ if (forcealign && (rdlen & (ALIGNMENT - 1)))
+ rdlen = roundup(rdlen, ALIGNMENT);

- /* Write the length token to the last word */
- bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->orig_ramsize - 4),
- (u8 *)&varsizew, 4);
+ if ((rdlen + firstread) > MAX_RX_DATASZ) {
+ /* Too long -- skip this frame */
+ brcmf_dbg(ERROR, "too long: len %d rdlen %d\n",
+ len, rdlen);
+ bus->drvr->rx_errors++;
+ bus->rx_toolong++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ continue;
+ }

- return bcmerror;
-}
+ pkt = brcmu_pkt_buf_get_skb(rdlen + firstread + BRCMF_SDALIGN);
+ if (!pkt) {
+ /* Give up on data, request rtx of events */
+ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n",
+ rdlen, chan);
+ bus->drvr->rx_dropped++;
+ brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan));
+ continue;
+ }

-static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
-{
- uint retries;
- u32 regdata;
- int bcmerror = 0;
+ /* Leave room for what we already read, and align remainder */
+ skb_pull(pkt, firstread);
+ pkt_align(pkt, rdlen, BRCMF_SDALIGN);

- /* To enter download state, disable ARM and reset SOCRAM.
- * To exit download state, simply reset ARM (default is RAM boot).
- */
- if (enter) {
- bus->alp_only = true;
+ /* Read the remaining frame data */
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)),
+ rdlen, pkt);
+ bus->f2rxdata++;

- brcmf_sdbrcm_chip_disablecore(bus->sdiodev,
- bus->ci->armcorebase);
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen,
+ ((chan == SDPCM_EVENT_CHANNEL) ? "event"
+ : ((chan == SDPCM_DATA_CHANNEL) ? "data"
+ : "test")), sdret);
+ brcmu_pkt_buf_free_skb(pkt);
+ bus->drvr->rx_errors++;
+ brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan));
+ continue;
+ }

- brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase);
+ /* Copy the already-read portion */
+ skb_push(pkt, firstread);
+ memcpy(pkt->data, bus->rxhdr, firstread);

- /* Clear the top bit of memory */
- if (bus->ramsize) {
- u32 zeros = 0;
- brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4,
- (u8 *)&zeros, 4);
- }
- } else {
- regdata = brcmf_sdcard_reg_read(bus->sdiodev,
- CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4);
- regdata &= (SBTML_RESET | SBTML_REJ_MASK |
- (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
- if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) {
- brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n");
- bcmerror = -EBADE;
- goto fail;
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
+ printk(KERN_DEBUG "Rx Data:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ pkt->data, len);
}
+#endif

- bcmerror = brcmf_sdbrcm_write_vars(bus);
- if (bcmerror) {
- brcmf_dbg(ERROR, "no vars written to RAM\n");
- bcmerror = 0;
+deliver:
+ /* Save superframe descriptor and allocate packet frame */
+ if (chan == SDPCM_GLOM_CHANNEL) {
+ if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
+ brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n",
+ len);
+#ifdef BCMDBG
+ if (BRCMF_GLOM_ON()) {
+ printk(KERN_DEBUG "Glom Data:\n");
+ print_hex_dump_bytes("",
+ DUMP_PREFIX_OFFSET,
+ pkt->data, len);
+ }
+#endif
+ __skb_trim(pkt, len);
+ skb_pull(pkt, SDPCM_HDRLEN);
+ bus->glomd = pkt;
+ } else {
+ brcmf_dbg(ERROR, "%s: glom superframe w/o "
+ "descriptor!\n", __func__);
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ }
+ continue;
}

- w_sdreg32(bus, 0xFFFFFFFF,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
+ /* Fill in packet len and prio, deliver upward */
+ __skb_trim(pkt, len);
+ skb_pull(pkt, doff);

- brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase);
-
- /* Allow HT Clock now that the ARM is running. */
- bus->alp_only = false;
+ if (pkt->len == 0) {
+ brcmu_pkt_buf_free_skb(pkt);
+ continue;
+ } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pkt) != 0) {
+ brcmf_dbg(ERROR, "rx protocol error\n");
+ brcmu_pkt_buf_free_skb(pkt);
+ bus->drvr->rx_errors++;
+ continue;
+ }

- bus->drvr->busstate = BRCMF_BUS_LOAD;
+ /* Unlock during rx call */
+ brcmf_sdbrcm_sdunlock(bus);
+ brcmf_rx_frame(bus->drvr, ifidx, pkt, 1);
+ brcmf_sdbrcm_sdlock(bus);
}
-fail:
- return bcmerror;
+ rxcount = maxframes - rxleft;
+#ifdef BCMDBG
+ /* Message if we hit the limit */
+ if (!rxleft)
+ brcmf_dbg(DATA, "hit rx limit of %d frames\n",
+ maxframes);
+ else
+#endif /* BCMDBG */
+ brcmf_dbg(DATA, "processed %d frames\n", rxcount);
+ /* Back off rxseq if awaiting rtx, update rx_seq */
+ if (bus->rxskip)
+ rxseq--;
+ bus->rx_seq = rxseq;
+
+ return rxcount;
}

-void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus, bool enforce_mutex)
+static int
+brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags,
+ u8 *buf, uint nbytes, struct sk_buff *pkt)
{
- u32 local_hostintmask;
- u8 saveclk;
- uint retries;
- int err;
+ 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_sdunlock(bus);
+ wait_event_interruptible_timeout(bus->ctrl_wait,
+ (*lockvar == false), HZ * 2);
+ brcmf_sdbrcm_sdlock(bus);
+ return;
+}
+
+static void
+brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus)
+{
+ if (waitqueue_active(&bus->ctrl_wait))
+ wake_up_interruptible(&bus->ctrl_wait);
+ return;
+}
+
+/* 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,
+ uint chan, bool free_pkt)
+{
+ int ret;
+ u8 *frame;
+ u16 len, pad = 0;
+ u32 swheader;
+ uint retries = 0;
+ struct sk_buff *new;
+ int i;

brcmf_dbg(TRACE, "Enter\n");

- if (enforce_mutex)
- brcmf_sdbrcm_sdlock(bus);
+ if (bus->drvr->dongle_reset) {
+ ret = -EPERM;
+ goto done;
+ }

- bus_wake(bus);
+ frame = (u8 *) (pkt->data);

- /* Enable clock for device interrupts */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ /* Add alignment padding, allocate new packet if needed */
+ pad = ((unsigned long)frame % BRCMF_SDALIGN);
+ if (pad) {
+ if (skb_headroom(pkt) < pad) {
+ brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n",
+ skb_headroom(pkt), pad);
+ bus->drvr->tx_realloc++;
+ new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);
+ if (!new) {
+ brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n",
+ pkt->len + BRCMF_SDALIGN);
+ ret = -ENOMEM;
+ goto done;
+ }

- if (bus->watchdog_tsk) {
- send_sig(SIGTERM, bus->watchdog_tsk, 1);
- kthread_stop(bus->watchdog_tsk);
- bus->watchdog_tsk = NULL;
+ pkt_align(new, pkt->len, BRCMF_SDALIGN);
+ memcpy(new->data, pkt->data, pkt->len);
+ if (free_pkt)
+ brcmu_pkt_buf_free_skb(pkt);
+ /* free the pkt if canned one is not used */
+ free_pkt = true;
+ pkt = new;
+ frame = (u8 *) (pkt->data);
+ /* precondition: (frame % BRCMF_SDALIGN) == 0) */
+ pad = 0;
+ } else {
+ skb_push(pkt, pad);
+ frame = (u8 *) (pkt->data);
+ /* precondition: pad + SDPCM_HDRLEN <= pkt->len */
+ memset(frame, 0, pad + SDPCM_HDRLEN);
+ }
}
+ /* precondition: pad < BRCMF_SDALIGN */

- if (bus->dpc_tsk) {
- send_sig(SIGTERM, bus->dpc_tsk, 1);
- kthread_stop(bus->dpc_tsk);
- bus->dpc_tsk = NULL;
- } else
- tasklet_kill(&bus->tasklet);
+ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
+ len = (u16) (pkt->len);
+ *(u16 *) frame = cpu_to_le16(len);
+ *(((u16 *) frame) + 1) = cpu_to_le16(~len);

- /* Disable and clear interrupts at the chip level also */
- w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
- local_hostintmask = bus->hostintmask;
- bus->hostintmask = 0;
+ /* Software tag: channel, sequence number, data offset */
+ swheader =
+ ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
+ (((pad +
+ SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);

- /* Change our idea of bus state */
- bus->drvr->busstate = BRCMF_BUS_DOWN;
+ put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
+ put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));

- /* Force clocks on backplane to be sure F2 interrupt propagates */
- saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
- if (!err) {
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- (saveclk | SBSDIO_FORCE_HT), &err);
+#ifdef BCMDBG
+ tx_packets[pkt->priority]++;
+ if (BRCMF_BYTES_ON() &&
+ (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
+ (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
+ printk(KERN_DEBUG "Tx Frame:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len);
+ } else if (BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "TxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ frame, min_t(u16, len, 16));
}
- if (err)
- brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
+#endif

- /* Turn off the bus (F2), free any pending packets */
- brcmf_dbg(INTR, "disable SDIO interrupts\n");
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- SDIO_FUNC_ENABLE_1, NULL);
+ /* Raise len to next SDIO block to eliminate tail command */
+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
+ u16 pad = bus->blocksize - (len % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize))
+ len += pad;
+ } else if (len % BRCMF_SDALIGN) {
+ len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
+ }

- /* Clear any pending interrupts now that F2 is disabled */
- w_sdreg32(bus, local_hostintmask,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
+ /* Some controllers have trouble with odd bytes -- round to even */
+ if (forcealign && (len & (ALIGNMENT - 1)))
+ len = roundup(len, ALIGNMENT);

- /* Turn off the backplane clock (only) */
- brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+ do {
+ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, frame,
+ len, pkt);
+ bus->f2txdata++;

- /* Clear the data packet queues */
- brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
+ if (ret < 0) {
+ /* On failure, abort the command
+ and terminate the frame */
+ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
+ ret);
+ bus->tx_sderrs++;

- /* Clear any held glomming stuff */
- if (bus->glomd)
- brcmu_pkt_buf_free_skb(bus->glomd);
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
+ NULL);
+ bus->f1regdata++;

- if (bus->glom)
- brcmu_pkt_buf_free_skb(bus->glom);
+ for (i = 0; i < 3; i++) {
+ u8 hi, lo;
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCHI,
+ NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCLO,
+ NULL);
+ bus->f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
+ }

- bus->glom = bus->glomd = NULL;
+ }
+ if (ret == 0)
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;

- /* Clear rx control and wake any waiters */
- bus->rxlen = 0;
- brcmf_sdbrcm_ioctl_resp_wake(bus);
+ } while ((ret < 0) && retrydata && retries++ < TXRETRIES);

- /* Reset some F2 state stuff */
- bus->rxskip = false;
- bus->tx_seq = bus->rx_seq = 0;
+done:
+ /* restore pkt buffer pointer before calling tx complete routine */
+ skb_pull(pkt, SDPCM_HDRLEN + pad);
+ brcmf_sdbrcm_sdunlock(bus);
+ brcmf_txcomplete(bus->drvr, pkt, ret != 0);
+ brcmf_sdbrcm_sdlock(bus);

- if (enforce_mutex)
- brcmf_sdbrcm_sdunlock(bus);
+ if (free_pkt)
+ brcmu_pkt_buf_free_skb(pkt);
+
+ return ret;
}

-int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr, bool enforce_mutex)
+static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes)
{
- struct brcmf_bus *bus = drvr->bus;
- unsigned long timeout;
+ struct sk_buff *pkt;
+ u32 intstatus = 0;
uint retries = 0;
- u8 ready, enable;
- int err, ret = 0;
- u8 saveclk;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* try to download image and nvram to the dongle */
- if (drvr->busstate == BRCMF_BUS_DOWN) {
- if (!(brcmf_sdbrcm_download_firmware(bus)))
- return -1;
- }
-
- if (!bus->drvr)
- return 0;
-
- /* Start the watchdog timer */
- bus->drvr->tickcnt = 0;
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
-
- if (enforce_mutex)
- brcmf_sdbrcm_sdlock(bus);
-
- /* Make sure backplane clock is on, needed to generate F2 interrupt */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- if (bus->clkstate != CLK_AVAIL)
- goto exit;
+ int ret = 0, prec_out;
+ uint cnt = 0;
+ uint datalen;
+ u8 tx_prec_map;

- /* Force clocks on backplane to be sure F2 interrupt propagates */
- saveclk =
- brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
- if (!err) {
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- (saveclk | SBSDIO_FORCE_HT), &err);
- }
- if (err) {
- brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
- goto exit;
- }
+ struct brcmf_pub *drvr = bus->drvr;

- /* Enable function 2 (frame transfers) */
- w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
- offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries);
- enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
+ brcmf_dbg(TRACE, "Enter\n");

- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- enable, NULL);
+ tx_prec_map = ~bus->flowcontrol;

- timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY);
- ready = 0;
- while (enable != ready) {
- ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0,
- SDIO_CCCR_IORx, NULL);
- if (time_after(jiffies, timeout))
+ /* Send frames until the limit or some other event */
+ for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) {
+ spin_lock_bh(&bus->txqlock);
+ pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
+ if (pkt == NULL) {
+ spin_unlock_bh(&bus->txqlock);
break;
- else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
- /* prevent busy waiting if it takes too long */
- msleep_interruptible(20);
- }
-
- brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready);
-
- /* If F2 successfully enabled, set core and enable interrupts */
- if (ready == enable) {
- /* Set up the interrupt mask and enable interrupts */
- bus->hostintmask = HOSTINTMASK;
- w_sdreg32(bus, bus->hostintmask,
- offsetof(struct sdpcmd_regs, hostintmask), &retries);
-
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_WATERMARK, 8, &err);
+ }
+ spin_unlock_bh(&bus->txqlock);
+ datalen = pkt->len - SDPCM_HDRLEN;

- /* Set bus state according to enable result */
- drvr->busstate = BRCMF_BUS_DATA;
- }
+ ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
+ if (ret)
+ bus->drvr->tx_errors++;
+ else
+ bus->drvr->dstats.tx_bytes += datalen;

- else {
- /* Disable F2 again */
- enable = SDIO_FUNC_ENABLE_1;
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
- SDIO_CCCR_IOEx, enable, NULL);
+ /* In poll mode, need to check for other events */
+ if (!bus->intr && cnt) {
+ /* Check device status, signal pending interrupt */
+ r_sdreg32(bus, &intstatus,
+ offsetof(struct sdpcmd_regs, intstatus),
+ &retries);
+ bus->f2txdata++;
+ if (brcmf_sdcard_regfail(bus->sdiodev))
+ break;
+ if (intstatus & bus->hostintmask)
+ bus->ipend = true;
+ }
}

- /* Restore previous clock setting */
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
-
- /* If we didn't come up, turn off backplane clock */
- if (drvr->busstate != BRCMF_BUS_DATA)
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
-
-exit:
- if (enforce_mutex)
- brcmf_sdbrcm_sdunlock(bus);
+ /* Deflow-control stack if needed */
+ if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) &&
+ drvr->txoff && (pktq_len(&bus->txq) < TXLOW))
+ brcmf_txflowcontrol(drvr, 0, OFF);

- return ret;
+ return cnt;
}

-static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
+static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
{
+ u32 intstatus, newstatus = 0;
uint retries = 0;
- u16 lastrbc;
- u8 hi, lo;
- int err;
+ uint rxlimit = brcmf_rxbound; /* Rx frames to read before resched */
+ uint txlimit = brcmf_txbound; /* Tx frames to send before resched */
+ uint framecnt = 0; /* Temporary counter of tx/rx frames */
+ bool rxdone = true; /* Flag for no more read data */
+ bool resched = false; /* Flag indicating resched wanted */

- brcmf_dbg(ERROR, "%sterminate frame%s\n",
- abort ? "abort command, " : "",
- rtx ? ", send NAK" : "");
+ brcmf_dbg(TRACE, "Enter\n");

- if (abort)
- brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+ /* Start with leftover status bits */
+ intstatus = bus->intstatus;

- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL,
- SFC_RF_TERM, &err);
- bus->f1regdata++;
+ brcmf_sdbrcm_sdlock(bus);

- /* Wait until the packet has been flushed (device/FIFO stable) */
- for (lastrbc = retries = 0xffff; retries > 0; retries--) {
- hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_RFRAMEBCHI, NULL);
- lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_RFRAMEBCLO, NULL);
- bus->f1regdata += 2;
+ /* If waiting for HTAVAIL, check status */
+ if (bus->clkstate == CLK_PENDING) {
+ int err;
+ u8 clkctl, devctl = 0;

- if ((hi == 0) && (lo == 0))
- break;
+#ifdef BCMDBG
+ /* Check for inconsistent device control */
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ }
+#endif /* BCMDBG */

- if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
- brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n",
- lastrbc, (hi << 8) + lo);
+ /* Read CSR, if clock on switch to AVAIL, else ignore */
+ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error reading CSR: %d\n",
+ err);
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ }
+
+ brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
+ devctl, clkctl);
+
+ if (SBSDIO_HTAV(clkctl)) {
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
+ err);
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ }
+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_DEVICE_CTL, devctl, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
+ err);
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ }
+ bus->clkstate = CLK_AVAIL;
+ } else {
+ goto clkwait;
}
- lastrbc = (hi << 8) + lo;
}

- if (!retries)
- brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc);
- else
- brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
+ bus_wake(bus);

- if (rtx) {
- bus->rxrtx++;
- w_sdreg32(bus, SMB_NAK,
- offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
+ /* Make sure backplane clock is on */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
+ if (bus->clkstate == CLK_PENDING)
+ goto clkwait;

+ /* Pending interrupt indicates new device status */
+ if (bus->ipend) {
+ bus->ipend = false;
+ r_sdreg32(bus, &newstatus,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
bus->f1regdata++;
- if (retries <= retry_limit)
- bus->rxskip = true;
+ if (brcmf_sdcard_regfail(bus->sdiodev))
+ newstatus = 0;
+ newstatus &= bus->hostintmask;
+ bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
+ if (newstatus) {
+ w_sdreg32(bus, newstatus,
+ offsetof(struct sdpcmd_regs, intstatus),
+ &retries);
+ bus->f1regdata++;
+ }
}

- /* Clear partial in any case */
- bus->nextlen = 0;
-
- /* If we can't reach the device, signal failure */
- if (err || brcmf_sdcard_regfail(bus->sdiodev))
- bus->drvr->busstate = BRCMF_BUS_DOWN;
-}
+ /* Merge new bits with previous */
+ intstatus |= newstatus;
+ bus->intstatus = 0;

-static void
-brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff)
-{
- uint rdlen, pad;
+ /* Handle flow-control change: read new state in case our ack
+ * crossed another change interrupt. If change still set, assume
+ * FC ON for safety, let next loop through do the debounce.
+ */
+ if (intstatus & I_HMB_FC_CHANGE) {
+ intstatus &= ~I_HMB_FC_CHANGE;
+ w_sdreg32(bus, I_HMB_FC_CHANGE,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);

- int sdret;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- /* Set rxctl for frame (w/optional alignment) */
- bus->rxctl = bus->rxbuf;
- if (brcmf_alignctl) {
- bus->rxctl += firstread;
- pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN);
- if (pad)
- bus->rxctl += (BRCMF_SDALIGN - pad);
- bus->rxctl -= firstread;
- }
-
- /* Copy the already-read portion over */
- memcpy(bus->rxctl, hdr, firstread);
- if (len <= firstread)
- goto gotpkt;
-
- /* Raise rdlen to next SDIO block to avoid tail command */
- rdlen = len - firstread;
- if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
- pad = bus->blocksize - (rdlen % bus->blocksize);
- if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
- ((len + pad) < bus->drvr->maxctl))
- rdlen += pad;
- } else if (rdlen % BRCMF_SDALIGN) {
- rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
- }
-
- /* Satisfy length-alignment requirements */
- if (forcealign && (rdlen & (ALIGNMENT - 1)))
- rdlen = roundup(rdlen, ALIGNMENT);
-
- /* Drop if the read is too big or it exceeds our maximum */
- if ((rdlen + firstread) > bus->drvr->maxctl) {
- brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n",
- rdlen, bus->drvr->maxctl);
- bus->drvr->rx_errors++;
- brcmf_sdbrcm_rxfail(bus, false, false);
- goto done;
- }
-
- if ((len - doff) > bus->drvr->maxctl) {
- brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
- len, len - doff, bus->drvr->maxctl);
- bus->drvr->rx_errors++;
- bus->rx_toolong++;
- brcmf_sdbrcm_rxfail(bus, false, false);
- goto done;
- }
-
- /* Read remainder of frame body into the rxctl buffer */
- sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
- bus->sdiodev->sbwad,
- SDIO_FUNC_2,
- F2SYNC, (bus->rxctl + firstread), rdlen,
- NULL);
- bus->f2rxdata++;
-
- /* Control frame failures need retransmission */
- if (sdret < 0) {
- brcmf_dbg(ERROR, "read %d control bytes failed: %d\n",
- rdlen, sdret);
- bus->rxc_errors++;
- brcmf_sdbrcm_rxfail(bus, true, true);
- goto done;
- }
-
-gotpkt:
-
-#ifdef BCMDBG
- if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
- printk(KERN_DEBUG "RxCtrl:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len);
- }
-#endif
-
- /* Point to valid data and indicate its length */
- bus->rxctl += doff;
- bus->rxlen = len - doff;
-
-done:
- /* Awake any waiters */
- brcmf_sdbrcm_ioctl_resp_wake(bus);
-}
-
-static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
-{
- u16 dlen, totlen;
- u8 *dptr, num = 0;
-
- u16 sublen, check;
- struct sk_buff *pfirst, *plast, *pnext, *save_pfirst;
-
- int errcode;
- u8 chan, seq, doff, sfdoff;
- u8 txmax;
-
- int ifidx = 0;
- bool usechain = bus->use_rxchain;
-
- /* If packets, issue read(s) and send up packet chain */
- /* Return sequence numbers consumed? */
-
- brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom);
-
- /* If there's a descriptor, generate the packet chain */
- if (bus->glomd) {
- pfirst = plast = pnext = NULL;
- dlen = (u16) (bus->glomd->len);
- dptr = bus->glomd->data;
- if (!dlen || (dlen & 1)) {
- brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n",
- dlen);
- dlen = 0;
- }
-
- for (totlen = num = 0; dlen; num++) {
- /* Get (and move past) next length */
- sublen = get_unaligned_le16(dptr);
- dlen -= sizeof(u16);
- dptr += sizeof(u16);
- if ((sublen < SDPCM_HDRLEN) ||
- ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
- brcmf_dbg(ERROR, "descriptor len %d bad: %d\n",
- num, sublen);
- pnext = NULL;
- break;
- }
- if (sublen % BRCMF_SDALIGN) {
- brcmf_dbg(ERROR, "sublen %d not multiple of %d\n",
- sublen, BRCMF_SDALIGN);
- usechain = false;
- }
- totlen += sublen;
-
- /* For last frame, adjust read len so total
- is a block multiple */
- if (!dlen) {
- sublen +=
- (roundup(totlen, bus->blocksize) - totlen);
- totlen = roundup(totlen, bus->blocksize);
- }
-
- /* Allocate/chain packet for next subframe */
- pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN);
- if (pnext == NULL) {
- brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n",
- num, sublen);
- break;
- }
- if (!pfirst) {
- pfirst = plast = pnext;
- } else {
- plast->next = pnext;
- plast = pnext;
- }
-
- /* Adhere to start alignment requirements */
- pkt_align(pnext, sublen, BRCMF_SDALIGN);
- }
-
- /* If all allocations succeeded, save packet chain
- in bus structure */
- if (pnext) {
- brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n",
- totlen, num);
- if (BRCMF_GLOM_ON() && bus->nextlen) {
- if (totlen != bus->nextlen) {
- brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
- bus->nextlen, totlen, rxseq);
- }
- }
- bus->glom = pfirst;
- pfirst = pnext = NULL;
- } else {
- if (pfirst)
- brcmu_pkt_buf_free_skb(pfirst);
- bus->glom = NULL;
- num = 0;
- }
-
- /* Done with descriptor packet */
- brcmu_pkt_buf_free_skb(bus->glomd);
- bus->glomd = NULL;
- bus->nextlen = 0;
+ r_sdreg32(bus, &newstatus,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
+ bus->f1regdata += 2;
+ bus->fcstate =
+ !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
+ intstatus |= (newstatus & bus->hostintmask);
}

- /* Ok -- either we just generated a packet chain,
- or had one from before */
- if (bus->glom) {
- if (BRCMF_GLOM_ON()) {
- brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
- for (pnext = bus->glom; pnext; pnext = pnext->next) {
- brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n",
- pnext, (u8 *) (pnext->data),
- pnext->len, pnext->len);
- }
- }
-
- pfirst = bus->glom;
- dlen = (u16) brcmu_pkttotlen(pfirst);
-
- /* Do an SDIO read for the superframe. Configurable iovar to
- * read directly into the chained packet, or allocate a large
- * packet and and copy into the chain.
- */
- if (usechain) {
- errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
- bus->sdiodev->sbwad,
- SDIO_FUNC_2,
- F2SYNC, (u8 *) pfirst->data, dlen,
- pfirst);
- } else if (bus->dataptr) {
- errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
- bus->sdiodev->sbwad,
- SDIO_FUNC_2,
- F2SYNC, bus->dataptr, dlen,
- NULL);
- sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen,
- bus->dataptr);
- if (sublen != dlen) {
- brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
- dlen, sublen);
- errcode = -1;
- }
- pnext = NULL;
- } else {
- brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n",
- dlen);
- errcode = -1;
- }
- bus->f2rxdata++;
-
- /* On failure, kill the superframe, allow a couple retries */
- if (errcode < 0) {
- brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n",
- dlen, errcode);
- bus->drvr->rx_errors++;
-
- if (bus->glomerr++ < 3) {
- brcmf_sdbrcm_rxfail(bus, true, true);
- } else {
- bus->glomerr = 0;
- brcmf_sdbrcm_rxfail(bus, true, false);
- brcmu_pkt_buf_free_skb(bus->glom);
- bus->rxglomfail++;
- bus->glom = NULL;
- }
- return 0;
- }
-#ifdef BCMDBG
- if (BRCMF_GLOM_ON()) {
- printk(KERN_DEBUG "SUPERFRAME:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- pfirst->data, min_t(int, pfirst->len, 48));
- }
-#endif
-
- /* Validate the superframe header */
- dptr = (u8 *) (pfirst->data);
- sublen = get_unaligned_le16(dptr);
- check = get_unaligned_le16(dptr + sizeof(u16));
-
- chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
- seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
- bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
- if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
- brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n",
- bus->nextlen, seq);
- bus->nextlen = 0;
- }
- doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
- txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
-
- errcode = 0;
- if ((u16)~(sublen ^ check)) {
- brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
- sublen, check);
- errcode = -1;
- } else if (roundup(sublen, bus->blocksize) != dlen) {
- brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
- sublen, roundup(sublen, bus->blocksize),
- dlen);
- errcode = -1;
- } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) !=
- SDPCM_GLOM_CHANNEL) {
- brcmf_dbg(ERROR, "(superframe): bad channel %d\n",
- SDPCM_PACKET_CHANNEL(
- &dptr[SDPCM_FRAMETAG_LEN]));
- errcode = -1;
- } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
- brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n");
- errcode = -1;
- } else if ((doff < SDPCM_HDRLEN) ||
- (doff > (pfirst->len - SDPCM_HDRLEN))) {
- brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n",
- doff, sublen, pfirst->len, SDPCM_HDRLEN);
- errcode = -1;
- }
-
- /* Check sequence number of superframe SW header */
- if (rxseq != seq) {
- brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
- seq, rxseq);
- bus->rx_badseq++;
- rxseq = seq;
- }
-
- /* Check window for sanity */
- if ((u8) (txmax - bus->tx_seq) > 0x40) {
- brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
- txmax, bus->tx_seq);
- txmax = bus->tx_seq + 2;
- }
- bus->tx_max = txmax;
-
- /* Remove superframe header, remember offset */
- skb_pull(pfirst, doff);
- sfdoff = doff;
-
- /* Validate all the subframe headers */
- for (num = 0, pnext = pfirst; pnext && !errcode;
- num++, pnext = pnext->next) {
- dptr = (u8 *) (pnext->data);
- dlen = (u16) (pnext->len);
- sublen = get_unaligned_le16(dptr);
- check = get_unaligned_le16(dptr + sizeof(u16));
- chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
- doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
-#ifdef BCMDBG
- if (BRCMF_GLOM_ON()) {
- printk(KERN_DEBUG "subframe:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- dptr, 32);
- }
-#endif
-
- if ((u16)~(sublen ^ check)) {
- brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n",
- num, sublen, check);
- errcode = -1;
- } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
- brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n",
- num, sublen, dlen);
- errcode = -1;
- } else if ((chan != SDPCM_DATA_CHANNEL) &&
- (chan != SDPCM_EVENT_CHANNEL)) {
- brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n",
- num, chan);
- errcode = -1;
- } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
- brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n",
- num, doff, sublen, SDPCM_HDRLEN);
- errcode = -1;
- }
- }
-
- if (errcode) {
- /* Terminate frame on error, request
- a couple retries */
- if (bus->glomerr++ < 3) {
- /* Restore superframe header space */
- skb_push(pfirst, sfdoff);
- brcmf_sdbrcm_rxfail(bus, true, true);
- } else {
- bus->glomerr = 0;
- brcmf_sdbrcm_rxfail(bus, true, false);
- brcmu_pkt_buf_free_skb(bus->glom);
- bus->rxglomfail++;
- bus->glom = NULL;
- }
- bus->nextlen = 0;
- return 0;
- }
-
- /* Basic SD framing looks ok - process each packet (header) */
- save_pfirst = pfirst;
- bus->glom = NULL;
- plast = NULL;
-
- for (num = 0; pfirst; rxseq++, pfirst = pnext) {
- pnext = pfirst->next;
- pfirst->next = NULL;
-
- dptr = (u8 *) (pfirst->data);
- sublen = get_unaligned_le16(dptr);
- chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
- seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
- doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
-
- brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
- num, pfirst, pfirst->data,
- pfirst->len, sublen, chan, seq);
-
- /* precondition: chan == SDPCM_DATA_CHANNEL ||
- chan == SDPCM_EVENT_CHANNEL */
-
- if (rxseq != seq) {
- brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
- seq, rxseq);
- bus->rx_badseq++;
- rxseq = seq;
- }
-#ifdef BCMDBG
- if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
- printk(KERN_DEBUG "Rx Subframe Data:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- dptr, dlen);
- }
-#endif
-
- __skb_trim(pfirst, sublen);
- skb_pull(pfirst, doff);
-
- if (pfirst->len == 0) {
- 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++;
- 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,
- pfirst->len, pfirst->next,
- pfirst->prev);
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- pfirst->data,
- min_t(int, pfirst->len, 32));
- }
-#endif /* BCMDBG */
- }
- if (num) {
- brcmf_sdbrcm_sdunlock(bus);
- brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num);
- brcmf_sdbrcm_sdlock(bus);
- }
+ /* Handle host mailbox indication */
+ if (intstatus & I_HMB_HOST_INT) {
+ intstatus &= ~I_HMB_HOST_INT;
+ intstatus |= brcmf_sdbrcm_hostmail(bus);
+ }

- bus->rxglomframes++;
- bus->rxglompkts += num;
+ /* Generally don't ask for these, can get CRC errors... */
+ if (intstatus & I_WR_OOSYNC) {
+ brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n");
+ intstatus &= ~I_WR_OOSYNC;
}
- return num;
-}

-/* Return true if there may be more frames to read */
-static uint
-brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
-{
- u16 len, check; /* Extracted hardware header fields */
- u8 chan, seq, doff; /* Extracted software header fields */
- u8 fcbits; /* Extracted fcbits from software header */
+ if (intstatus & I_RD_OOSYNC) {
+ brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n");
+ intstatus &= ~I_RD_OOSYNC;
+ }

- struct sk_buff *pkt; /* Packet for event or data frames */
- u16 pad; /* Number of pad bytes to read */
- u16 rdlen; /* Total number of bytes to read */
- u8 rxseq; /* Next sequence number to expect */
- uint rxleft = 0; /* Remaining number of frames allowed */
- int sdret; /* Return code from calls */
- u8 txmax; /* Maximum tx sequence offered */
- bool len_consistent; /* Result of comparing readahead len and
- len from hw-hdr */
- u8 *rxbuf;
- int ifidx = 0;
- uint rxcount = 0; /* Total frames read */
+ if (intstatus & I_SBINT) {
+ brcmf_dbg(ERROR, "Dongle reports SBINT\n");
+ intstatus &= ~I_SBINT;
+ }

- brcmf_dbg(TRACE, "Enter\n");
+ /* Would be active due to wake-wlan in gSPI */
+ if (intstatus & I_CHIPACTIVE) {
+ brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n");
+ intstatus &= ~I_CHIPACTIVE;
+ }

- /* Not finished unless we encounter no more frames indication */
- *finished = false;
+ /* Ignore frame indications if rxskip is set */
+ if (bus->rxskip)
+ intstatus &= ~I_HMB_FRAME_IND;

- for (rxseq = bus->rx_seq, rxleft = maxframes;
- !bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN;
- rxseq++, rxleft--) {
+ /* On frame indication, read available frames */
+ if (PKT_AVAILABLE()) {
+ framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone);
+ if (rxdone || bus->rxskip)
+ intstatus &= ~I_HMB_FRAME_IND;
+ rxlimit -= min(framecnt, rxlimit);
+ }

- /* Handle glomming separately */
- if (bus->glom || bus->glomd) {
- u8 cnt;
- brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
- bus->glomd, bus->glom);
- cnt = brcmf_sdbrcm_rxglom(bus, rxseq);
- brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
- rxseq += cnt - 1;
- rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
- continue;
- }
+ /* Keep still-pending events for next scheduling */
+ bus->intstatus = intstatus;

- /* Try doing single read if we can */
- if (brcmf_readahead && bus->nextlen) {
- u16 nextlen = bus->nextlen;
- bus->nextlen = 0;
+clkwait:
+ if (data_ok(bus) && bus->ctrl_frame_stat &&
+ (bus->clkstate == CLK_AVAIL)) {
+ int ret, i;

- rdlen = len = nextlen << 4;
+ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf,
+ (u32) bus->ctrl_frame_len, NULL);

- /* Pad read to blocksize for efficiency */
- if (bus->roundup && bus->blocksize
- && (rdlen > bus->blocksize)) {
- pad =
- bus->blocksize -
- (rdlen % bus->blocksize);
- if ((pad <= bus->roundup)
- && (pad < bus->blocksize)
- && ((rdlen + pad + firstread) <
- MAX_RX_DATASZ))
- rdlen += pad;
- } else if (rdlen % BRCMF_SDALIGN) {
- rdlen += BRCMF_SDALIGN -
- (rdlen % BRCMF_SDALIGN);
- }
+ if (ret < 0) {
+ /* On failure, abort the command and
+ terminate the frame */
+ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
+ ret);
+ bus->tx_sderrs++;

- /* We use bus->rxctl buffer in WinXP for initial
- * control pkt receives.
- * Later we use buffer-poll for data as well
- * as control packets.
- * This is required because dhd receives full
- * frame in gSPI unlike SDIO.
- * After the frame is received we have to
- * distinguish whether it is data
- * or non-data frame.
- */
- /* Allocate a packet buffer */
- pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN);
- if (!pkt) {
- /* Give up on data, request rtx of events */
- brcmf_dbg(ERROR, "(nextlen): brcmu_pkt_buf_get_skb failed: len %d rdlen %d expected rxseq %d\n",
- len, rdlen, rxseq);
- continue;
- } else {
- 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);
- bus->f2rxdata++;
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);

- if (sdret < 0) {
- brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n",
- rdlen, sdret);
- brcmu_pkt_buf_free_skb(pkt);
- bus->drvr->rx_errors++;
- /* Force retry w/normal header read.
- * Don't attempt NAK for
- * gSPI
- */
- brcmf_sdbrcm_rxfail(bus, true, true);
- continue;
- }
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
+ NULL);
+ bus->f1regdata++;
+
+ for (i = 0; i < 3; i++) {
+ u8 hi, lo;
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCHI,
+ NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCLO,
+ NULL);
+ bus->f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
}

- /* Now check the header */
- memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN);
+ }
+ if (ret == 0)
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;

- /* Extract hardware header fields */
- len = get_unaligned_le16(bus->rxhdr);
- check = get_unaligned_le16(bus->rxhdr + sizeof(u16));
+ brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret);
+ bus->ctrl_frame_stat = false;
+ brcmf_sdbrcm_wait_event_wakeup(bus);
+ }
+ /* Send queued frames (limit 1 if rx may still be pending) */
+ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
+ brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit
+ && data_ok(bus)) {
+ framecnt = rxdone ? txlimit : min(txlimit, brcmf_txminmax);
+ framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt);
+ txlimit -= framecnt;
+ }

- /* All zeros means readahead info was bad */
- if (!(len | check)) {
- brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n");
- brcmf_sdbrcm_pktfree2(bus, pkt);
- continue;
- }
+ /* Resched if events or tx frames are pending,
+ else await next interrupt */
+ /* On failed register access, all bets are off:
+ no resched or interrupts */
+ if ((bus->drvr->busstate == 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->intstatus = 0;
+ } else if (bus->clkstate == CLK_PENDING) {
+ brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n");
+ resched = true;
+ } else if (bus->intstatus || bus->ipend ||
+ (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)
+ && data_ok(bus)) || PKT_AVAILABLE()) {
+ resched = true;
+ }

- /* Validate check bytes */
- if ((u16)~(len ^ check)) {
- brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n",
- nextlen, len, check);
- bus->rx_badhdr++;
- brcmf_sdbrcm_rxfail(bus, false, false);
- brcmf_sdbrcm_pktfree2(bus, pkt);
- continue;
- }
+ bus->dpc_sched = resched;

- /* Validate frame length */
- if (len < SDPCM_HDRLEN) {
- brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n",
- len);
- brcmf_sdbrcm_pktfree2(bus, pkt);
- continue;
- }
+ /* If we're done for now, turn off clock request. */
+ if ((bus->clkstate != CLK_PENDING)
+ && bus->idletime == BRCMF_IDLE_IMMEDIATE) {
+ bus->activity = false;
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ }

- /* Check for consistency withreadahead info */
- len_consistent = (nextlen != (roundup(len, 16) >> 4));
- if (len_consistent) {
- /* Mismatch, force retry w/normal
- header (may be >4K) */
- brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n",
- nextlen, len, roundup(len, 16),
- rxseq);
- brcmf_sdbrcm_rxfail(bus, true, true);
- brcmf_sdbrcm_pktfree2(bus, pkt);
- continue;
- }
+ brcmf_sdbrcm_sdunlock(bus);

- /* Extract software header fields */
- chan = SDPCM_PACKET_CHANNEL(
- &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
- seq = SDPCM_PACKET_SEQUENCE(
- &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
- doff = SDPCM_DOFFSET_VALUE(
- &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
- txmax = SDPCM_WINDOW_VALUE(
- &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ return resched;
+}
+
+static int brcmf_sdbrcm_dpc_thread(void *data)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *) data;

- bus->nextlen =
- bus->rxhdr[SDPCM_FRAMETAG_LEN +
- SDPCM_NEXTLEN_OFFSET];
- if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
- brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
- bus->nextlen, seq);
- bus->nextlen = 0;
+ /* This thread doesn't need any user-level access,
+ * so get rid of all our resources
+ */
+ if (brcmf_dpc_prio > 0) {
+ struct sched_param param;
+ param.sched_priority = (brcmf_dpc_prio < MAX_RT_PRIO) ?
+ brcmf_dpc_prio : (MAX_RT_PRIO - 1);
+ sched_setscheduler(current, SCHED_FIFO, &param);
+ }
+
+ allow_signal(SIGTERM);
+ /* Run until signal received */
+ while (1) {
+ if (kthread_should_stop())
+ break;
+ 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 (brcmf_sdbrcm_dpc(bus))
+ complete(&bus->dpc_wait);
+ } else {
+ brcmf_sdbrcm_bus_stop(bus, true);
}
+ } else
+ break;
+ }
+ return 0;
+}

- bus->drvr->rx_readahead_cnt++;
+static void brcmf_sdbrcm_dpc_tasklet(unsigned long data)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *) data;

- /* Handle Flow Control */
- fcbits = SDPCM_FCMASK_VALUE(
- &bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ /* Call bus dpc unless it indicated down (then clean stop) */
+ if (bus->drvr->busstate != BRCMF_BUS_DOWN) {
+ if (brcmf_sdbrcm_dpc(bus))
+ tasklet_schedule(&bus->tasklet);
+ } else
+ brcmf_sdbrcm_bus_stop(bus, true);
+}

- if (bus->flowcontrol != fcbits) {
- if (~bus->flowcontrol & fcbits)
- bus->fc_xoff++;
+static void brcmf_sdbrcm_sched_dpc(struct brcmf_bus *bus)
+{
+ if (bus->dpc_tsk) {
+ complete(&bus->dpc_wait);
+ return;
+ }

- if (bus->flowcontrol & ~fcbits)
- bus->fc_xon++;
+ tasklet_schedule(&bus->tasklet);
+}

- bus->fc_rcvd++;
- bus->flowcontrol = fcbits;
- }
+int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt)
+{
+ int ret = -EBADE;
+ uint datalen, prec;

- /* Check and update sequence number */
- if (rxseq != seq) {
- brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n",
- seq, rxseq);
- bus->rx_badseq++;
- rxseq = seq;
- }
+ brcmf_dbg(TRACE, "Enter\n");

- /* Check window for sanity */
- if ((u8) (txmax - bus->tx_seq) > 0x40) {
- brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n",
- txmax, bus->tx_seq);
- txmax = bus->tx_seq + 2;
- }
- bus->tx_max = txmax;
+ datalen = pkt->len;

-#ifdef BCMDBG
- if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
- printk(KERN_DEBUG "Rx Data:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- rxbuf, len);
- } else if (BRCMF_HDRS_ON()) {
- printk(KERN_DEBUG "RxHdr:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- bus->rxhdr, SDPCM_HDRLEN);
- }
-#endif
+ /* Add space for the header */
+ skb_push(pkt, SDPCM_HDRLEN);
+ /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */

- if (chan == SDPCM_CONTROL_CHANNEL) {
- brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n",
- seq);
- /* Force retry w/normal header read */
- bus->nextlen = 0;
- brcmf_sdbrcm_rxfail(bus, false, true);
- brcmf_sdbrcm_pktfree2(bus, pkt);
- continue;
- }
+ prec = prio2prec((pkt->priority & PRIOMASK));

- /* Validate data offset */
- if ((doff < SDPCM_HDRLEN) || (doff > len)) {
- brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n",
- doff, len, SDPCM_HDRLEN);
- brcmf_sdbrcm_rxfail(bus, false, false);
- brcmf_sdbrcm_pktfree2(bus, pkt);
- continue;
- }
+ /* Check for existing queue, current flow-control,
+ pending event, or pending clock */
+ if (brcmf_deferred_tx || bus->fcstate || pktq_len(&bus->txq)
+ || bus->dpc_sched || (!data_ok(bus))
+ || (bus->flowcontrol & NBITVAL(prec))
+ || (bus->clkstate != CLK_AVAIL)) {
+ brcmf_dbg(TRACE, "deferring pktq len %d\n",
+ pktq_len(&bus->txq));
+ bus->fcqueued++;

- /* All done with this one -- now deliver the packet */
- goto deliver;
+ /* Priority based enq */
+ spin_lock_bh(&bus->txqlock);
+ if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) ==
+ false) {
+ skb_pull(pkt, SDPCM_HDRLEN);
+ brcmf_txcomplete(bus->drvr, pkt, false);
+ brcmu_pkt_buf_free_skb(pkt);
+ brcmf_dbg(ERROR, "out of bus->txq !!!\n");
+ ret = -ENOSR;
+ } else {
+ ret = 0;
}
+ spin_unlock_bh(&bus->txqlock);

- /* Read frame header (hardware and software) */
- sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
- SDIO_FUNC_2, F2SYNC, bus->rxhdr, firstread,
- NULL);
- bus->f2rxhdrs++;
+ if (pktq_len(&bus->txq) >= TXHI)
+ brcmf_txflowcontrol(bus->drvr, 0, ON);

- if (sdret < 0) {
- brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret);
- bus->rx_hdrfail++;
- brcmf_sdbrcm_rxfail(bus, true, true);
- continue;
- }
#ifdef BCMDBG
- if (BRCMF_BYTES_ON() || BRCMF_HDRS_ON()) {
- printk(KERN_DEBUG "RxHdr:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- bus->rxhdr, SDPCM_HDRLEN);
- }
+ if (pktq_plen(&bus->txq, prec) > qcount[prec])
+ qcount[prec] = pktq_plen(&bus->txq, prec);
#endif
+ /* Schedule DPC if needed to send queued packet(s) */
+ if (brcmf_deferred_tx && !bus->dpc_sched) {
+ bus->dpc_sched = true;
+ brcmf_sdbrcm_sched_dpc(bus);
+ }
+ } else {
+ /* Lock: we're about to use shared data/code (and SDIO) */
+ brcmf_sdbrcm_sdlock(bus);

- /* Extract hardware header fields */
- len = get_unaligned_le16(bus->rxhdr);
- check = get_unaligned_le16(bus->rxhdr + sizeof(u16));
+ /* Otherwise, send it now */
+ bus_wake(bus);
+ /* Make sure back plane ht clk is on, no pending allowed */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);

- /* All zeros means no more frames */
- if (!(len | check)) {
- *finished = true;
- break;
- }
+ brcmf_dbg(TRACE, "calling txpkt\n");
+ ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
+ if (ret)
+ bus->drvr->tx_errors++;
+ else
+ bus->drvr->dstats.tx_bytes += datalen;

- /* Validate check bytes */
- if ((u16) ~(len ^ check)) {
- brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n",
- len, check);
- bus->rx_badhdr++;
- brcmf_sdbrcm_rxfail(bus, false, false);
- continue;
+ if (bus->idletime == BRCMF_IDLE_IMMEDIATE &&
+ !bus->dpc_sched) {
+ bus->activity = false;
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
}

- /* Validate frame length */
- if (len < SDPCM_HDRLEN) {
- brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len);
- continue;
- }
+ brcmf_sdbrcm_sdunlock(bus);
+ }

- /* Extract software header fields */
- chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
- seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
- doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
- txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
+ return ret;
+}

- /* Validate data offset */
- if ((doff < SDPCM_HDRLEN) || (doff > len)) {
- brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n",
- doff, len, SDPCM_HDRLEN, seq);
- bus->rx_badhdr++;
- brcmf_sdbrcm_rxfail(bus, false, false);
- continue;
- }
+static int
+brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data,
+ uint size)
+{
+ int bcmerror = 0;
+ u32 sdaddr;
+ uint dsize;

- /* Save the readahead length if there is one */
- bus->nextlen =
- bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
- if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
- brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
- bus->nextlen, seq);
- bus->nextlen = 0;
+ /* Determine initial transfer parameters */
+ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
+ if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
+ dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
+ else
+ dsize = size;
+
+ /* Set the backplane window to include the start address */
+ bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "window change failed\n");
+ goto xfer_done;
+ }
+
+ /* Do the transfer(s) */
+ while (size) {
+ brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
+ write ? "write" : "read", dsize,
+ sdaddr, address & SBSDIO_SBWINDOW_MASK);
+ bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write,
+ sdaddr, data, dsize);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "membytes transfer failed\n");
+ break;
}

- /* Handle Flow Control */
- fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
-
- if (bus->flowcontrol != fcbits) {
- if (~bus->flowcontrol & fcbits)
- bus->fc_xoff++;
+ /* Adjust for next transfer (if any) */
+ size -= dsize;
+ if (size) {
+ data += dsize;
+ address += dsize;
+ bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev,
+ address);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "window change failed\n");
+ break;
+ }
+ sdaddr = 0;
+ dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
+ }
+ }

- if (bus->flowcontrol & ~fcbits)
- bus->fc_xon++;
+xfer_done:
+ /* Return the window to backplane enumeration space for core access */
+ if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad))
+ brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n",
+ bus->sdiodev->sbwad);

- bus->fc_rcvd++;
- bus->flowcontrol = fcbits;
- }
+ return bcmerror;
+}

- /* Check and update sequence number */
- if (rxseq != seq) {
- brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq);
- bus->rx_badseq++;
- rxseq = seq;
- }
+#ifdef BCMDBG
+static int
+brcmf_sdbrcm_readshared(struct brcmf_bus *bus, struct sdpcm_shared *sh)
+{
+ u32 addr;
+ int rv;

- /* Check window for sanity */
- if ((u8) (txmax - bus->tx_seq) > 0x40) {
- brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
- txmax, bus->tx_seq);
- txmax = bus->tx_seq + 2;
- }
- bus->tx_max = txmax;
+ /* Read last word in memory to determine address of
+ sdpcm_shared structure */
+ rv = brcmf_sdbrcm_membytes(bus, false, bus->ramsize - 4, (u8 *)&addr,
+ 4);
+ if (rv < 0)
+ return rv;

- /* Call a separate function for control frames */
- if (chan == SDPCM_CONTROL_CHANNEL) {
- brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff);
- continue;
- }
+ addr = le32_to_cpu(addr);

- /* precondition: chan is either SDPCM_DATA_CHANNEL,
- SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or
- SDPCM_GLOM_CHANNEL */
+ brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr);

- /* Length to read */
- rdlen = (len > firstread) ? (len - firstread) : 0;
+ /*
+ * Check if addr is valid.
+ * NVRAM length at the end of memory should have been overwritten.
+ */
+ if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
+ brcmf_dbg(ERROR, "address (0x%08x) of sdpcm_shared invalid\n",
+ addr);
+ return -EBADE;
+ }

- /* May pad read to blocksize for efficiency */
- if (bus->roundup && bus->blocksize &&
- (rdlen > bus->blocksize)) {
- pad = bus->blocksize - (rdlen % bus->blocksize);
- if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
- ((rdlen + pad + firstread) < MAX_RX_DATASZ))
- rdlen += pad;
- } else if (rdlen % BRCMF_SDALIGN) {
- rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
- }
+ /* Read rte_shared structure */
+ rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *) sh,
+ sizeof(struct sdpcm_shared));
+ if (rv < 0)
+ return rv;

- /* Satisfy length-alignment requirements */
- if (forcealign && (rdlen & (ALIGNMENT - 1)))
- rdlen = roundup(rdlen, ALIGNMENT);
+ /* Endianness */
+ sh->flags = le32_to_cpu(sh->flags);
+ sh->trap_addr = le32_to_cpu(sh->trap_addr);
+ sh->assert_exp_addr = le32_to_cpu(sh->assert_exp_addr);
+ sh->assert_file_addr = le32_to_cpu(sh->assert_file_addr);
+ sh->assert_line = le32_to_cpu(sh->assert_line);
+ sh->console_addr = le32_to_cpu(sh->console_addr);
+ sh->msgtrace_addr = le32_to_cpu(sh->msgtrace_addr);

- if ((rdlen + firstread) > MAX_RX_DATASZ) {
- /* Too long -- skip this frame */
- brcmf_dbg(ERROR, "too long: len %d rdlen %d\n",
- len, rdlen);
- bus->drvr->rx_errors++;
- bus->rx_toolong++;
- brcmf_sdbrcm_rxfail(bus, false, false);
- continue;
- }
+ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
+ brcmf_dbg(ERROR, "sdpcm_shared version %d in brcmf is different than sdpcm_shared version %d in dongle\n",
+ SDPCM_SHARED_VERSION,
+ sh->flags & SDPCM_SHARED_VERSION_MASK);
+ return -EBADE;
+ }

- pkt = brcmu_pkt_buf_get_skb(rdlen + firstread + BRCMF_SDALIGN);
- if (!pkt) {
- /* Give up on data, request rtx of events */
- brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n",
- rdlen, chan);
- bus->drvr->rx_dropped++;
- brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan));
- continue;
- }
+ return 0;
+}

- /* Leave room for what we already read, and align remainder */
- skb_pull(pkt, firstread);
- pkt_align(pkt, rdlen, BRCMF_SDALIGN);
+static int brcmf_sdbrcm_mem_dump(struct brcmf_bus *bus)
+{
+ int ret = 0;
+ int size; /* Full mem size */
+ int start = 0; /* Start address */
+ int read_size = 0; /* Read size of each iteration */
+ u8 *buf = NULL, *databuf = NULL;

- /* Read the remaining frame data */
- sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
- SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)),
- rdlen, pkt);
- bus->f2rxdata++;
+ /* Get full mem size */
+ size = bus->ramsize;
+ buf = kmalloc(size, GFP_ATOMIC);
+ if (!buf) {
+ brcmf_dbg(ERROR, "Out of memory (%d bytes)\n", size);
+ return -1;
+ }

- if (sdret < 0) {
- brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen,
- ((chan == SDPCM_EVENT_CHANNEL) ? "event"
- : ((chan == SDPCM_DATA_CHANNEL) ? "data"
- : "test")), sdret);
- brcmu_pkt_buf_free_skb(pkt);
- bus->drvr->rx_errors++;
- brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan));
- continue;
+ /* Read mem content */
+ printk(KERN_DEBUG "Dump dongle memory");
+ databuf = buf;
+ while (size) {
+ read_size = min(MEMBLOCK, size);
+ ret = brcmf_sdbrcm_membytes(bus, false, start, databuf,
+ read_size);
+ if (ret) {
+ brcmf_dbg(ERROR, "Error membytes %d\n", ret);
+ kfree(buf);
+ return -1;
}
+ printk(".");

- /* Copy the already-read portion */
- skb_push(pkt, firstread);
- memcpy(pkt->data, bus->rxhdr, firstread);
+ /* Decrement size and increment start address */
+ size -= read_size;
+ start += read_size;
+ databuf += read_size;
+ }
+ printk(KERN_DEBUG "Done\n");

-#ifdef BCMDBG
- if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
- printk(KERN_DEBUG "Rx Data:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- pkt->data, len);
- }
-#endif
+ /* free buf before return !!! */
+ if (brcmf_write_to_file(bus->drvr, buf, bus->ramsize)) {
+ brcmf_dbg(ERROR, "Error writing to files\n");
+ return -1;
+ }

-deliver:
- /* Save superframe descriptor and allocate packet frame */
- if (chan == SDPCM_GLOM_CHANNEL) {
- if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
- brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n",
- len);
-#ifdef BCMDBG
- if (BRCMF_GLOM_ON()) {
- printk(KERN_DEBUG "Glom Data:\n");
- print_hex_dump_bytes("",
- DUMP_PREFIX_OFFSET,
- pkt->data, len);
- }
-#endif
- __skb_trim(pkt, len);
- skb_pull(pkt, SDPCM_HDRLEN);
- bus->glomd = pkt;
- } else {
- brcmf_dbg(ERROR, "%s: glom superframe w/o "
- "descriptor!\n", __func__);
- brcmf_sdbrcm_rxfail(bus, false, false);
- }
- continue;
- }
+ /* buf free handled in brcmf_write_to_file, not here */
+ return 0;
+}

- /* Fill in packet len and prio, deliver upward */
- __skb_trim(pkt, len);
- skb_pull(pkt, doff);
+static int brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, u8 *data, uint size)
+{
+ int bcmerror = 0;
+ uint msize = 512;
+ char *mbuffer = NULL;
+ uint maxstrlen = 256;
+ char *str = NULL;
+ struct brcmf_trap tr;
+ struct sdpcm_shared sdpcm_shared;
+ struct brcmu_strbuf strbuf;

- if (pkt->len == 0) {
- brcmu_pkt_buf_free_skb(pkt);
- continue;
- } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pkt) != 0) {
- brcmf_dbg(ERROR, "rx protocol error\n");
- brcmu_pkt_buf_free_skb(pkt);
- bus->drvr->rx_errors++;
- continue;
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (data == NULL) {
+ /*
+ * Called after a rx ctrl timeout. "data" is NULL.
+ * allocate memory to trace the trap or assert.
+ */
+ size = msize;
+ mbuffer = data = kmalloc(msize, GFP_ATOMIC);
+ if (mbuffer == NULL) {
+ brcmf_dbg(ERROR, "kmalloc(%d) failed\n", msize);
+ bcmerror = -ENOMEM;
+ goto done;
}
-
- /* Unlock during rx call */
- brcmf_sdbrcm_sdunlock(bus);
- brcmf_rx_frame(bus->drvr, ifidx, pkt, 1);
- brcmf_sdbrcm_sdlock(bus);
}
- rxcount = maxframes - rxleft;
-#ifdef BCMDBG
- /* Message if we hit the limit */
- if (!rxleft)
- brcmf_dbg(DATA, "hit rx limit of %d frames\n",
- maxframes);
- else
-#endif /* BCMDBG */
- brcmf_dbg(DATA, "processed %d frames\n", rxcount);
- /* Back off rxseq if awaiting rtx, update rx_seq */
- if (bus->rxskip)
- rxseq--;
- bus->rx_seq = rxseq;

- return rxcount;
-}
+ str = kmalloc(maxstrlen, GFP_ATOMIC);
+ if (str == NULL) {
+ brcmf_dbg(ERROR, "kmalloc(%d) failed\n", maxstrlen);
+ bcmerror = -ENOMEM;
+ goto done;
+ }

-static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus)
-{
- u32 intstatus = 0;
- u32 hmb_data;
- u8 fcbits;
- uint retries = 0;
+ bcmerror = brcmf_sdbrcm_readshared(bus, &sdpcm_shared);
+ if (bcmerror < 0)
+ goto done;

- brcmf_dbg(TRACE, "Enter\n");
+ brcmu_binit(&strbuf, data, size);

- /* Read mailbox data and ack that we did so */
- r_sdreg32(bus, &hmb_data,
- offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries);
+ brcmu_bprintf(&strbuf,
+ "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
+ sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);

- if (retries <= retry_limit)
- w_sdreg32(bus, SMB_INT_ACK,
- offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
- bus->f1regdata += 2;
+ if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)
+ /* NOTE: Misspelled assert is intentional - DO NOT FIX.
+ * (Avoids conflict with real asserts for programmatic
+ * parsing of output.)
+ */
+ brcmu_bprintf(&strbuf, "Assrt not built in dongle\n");

- /* Dongle recomposed rx frames, accept them again */
- if (hmb_data & HMB_DATA_NAKHANDLED) {
- brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n",
- bus->rx_seq);
- if (!bus->rxskip)
- brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n");
+ if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) ==
+ 0) {
+ /* NOTE: Misspelled assert is intentional - DO NOT FIX.
+ * (Avoids conflict with real asserts for programmatic
+ * parsing of output.)
+ */
+ brcmu_bprintf(&strbuf, "No trap%s in dongle",
+ (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
+ ? "/assrt" : "");
+ } else {
+ if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
+ /* Download assert */
+ brcmu_bprintf(&strbuf, "Dongle assert");
+ if (sdpcm_shared.assert_exp_addr != 0) {
+ str[0] = '\0';
+ bcmerror = brcmf_sdbrcm_membytes(bus, false,
+ sdpcm_shared.assert_exp_addr,
+ (u8 *) str, maxstrlen);
+ if (bcmerror < 0)
+ goto done;

- bus->rxskip = false;
- intstatus |= I_HMB_FRAME_IND;
- }
+ str[maxstrlen - 1] = '\0';
+ brcmu_bprintf(&strbuf, " expr \"%s\"", str);
+ }

- /*
- * DEVREADY does not occur with gSPI.
- */
- if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
- bus->sdpcm_ver =
- (hmb_data & HMB_DATA_VERSION_MASK) >>
- HMB_DATA_VERSION_SHIFT;
- if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
- brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, "
- "expecting %d\n",
- bus->sdpcm_ver, SDPCM_PROT_VERSION);
- else
- brcmf_dbg(INFO, "Dongle ready, protocol version %d\n",
- bus->sdpcm_ver);
- }
+ if (sdpcm_shared.assert_file_addr != 0) {
+ str[0] = '\0';
+ bcmerror = brcmf_sdbrcm_membytes(bus, false,
+ sdpcm_shared.assert_file_addr,
+ (u8 *) str, maxstrlen);
+ if (bcmerror < 0)
+ goto done;

- /*
- * Flow Control has been moved into the RX headers and this out of band
- * method isn't used any more.
- * remaining backward compatible with older dongles.
- */
- if (hmb_data & HMB_DATA_FC) {
- fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
- HMB_DATA_FCDATA_SHIFT;
+ str[maxstrlen - 1] = '\0';
+ brcmu_bprintf(&strbuf, " file \"%s\"", str);
+ }

- if (fcbits & ~bus->flowcontrol)
- bus->fc_xoff++;
+ brcmu_bprintf(&strbuf, " line %d ",
+ sdpcm_shared.assert_line);
+ }

- if (bus->flowcontrol & ~fcbits)
- bus->fc_xon++;
+ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
+ bcmerror = brcmf_sdbrcm_membytes(bus, false,
+ sdpcm_shared.trap_addr, (u8 *)&tr,
+ sizeof(struct brcmf_trap));
+ if (bcmerror < 0)
+ goto done;

- bus->fc_rcvd++;
- bus->flowcontrol = fcbits;
+ brcmu_bprintf(&strbuf,
+ "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
+ "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
+ "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
+ tr.type, tr.epc, tr.cpsr, tr.spsr, tr.r13,
+ tr.r14, tr.pc, sdpcm_shared.trap_addr,
+ tr.r0, tr.r1, tr.r2, tr.r3, tr.r4, tr.r5,
+ tr.r6, tr.r7);
+ }
}

- /* Shouldn't be any others */
- if (hmb_data & ~(HMB_DATA_DEVREADY |
- HMB_DATA_NAKHANDLED |
- HMB_DATA_FC |
- HMB_DATA_FWREADY |
- HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
- brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n",
- hmb_data);
+ if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP))
+ brcmf_dbg(ERROR, "%s\n", strbuf.origbuf);

- return intstatus;
+#ifdef BCMDBG
+ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP)
+ /* Mem dump to a file on device */
+ brcmf_sdbrcm_mem_dump(bus);
+
+#endif /* BCMDBG */
+
+done:
+ kfree(mbuffer);
+ kfree(str);
+
+ return bcmerror;
}

-static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
+#define CONSOLE_LINE_MAX 192
+
+static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus)
{
- u32 intstatus, newstatus = 0;
- uint retries = 0;
- uint rxlimit = brcmf_rxbound; /* Rx frames to read before resched */
- uint txlimit = brcmf_txbound; /* Tx frames to send before resched */
- uint framecnt = 0; /* Temporary counter of tx/rx frames */
- bool rxdone = true; /* Flag for no more read data */
- bool resched = false; /* Flag indicating resched wanted */
+ struct brcmf_console *c = &bus->console;
+ u8 line[CONSOLE_LINE_MAX], ch;
+ u32 n, idx, addr;
+ int rv;

- brcmf_dbg(TRACE, "Enter\n");
+ /* Don't do anything until FWREADY updates console address */
+ if (bus->console_addr == 0)
+ return 0;

- /* Start with leftover status bits */
- intstatus = bus->intstatus;
+ /* Read console log struct */
+ addr = bus->console_addr + offsetof(struct rte_console, log);
+ rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log,
+ sizeof(c->log));
+ if (rv < 0)
+ return rv;

- brcmf_sdbrcm_sdlock(bus);
+ /* Allocate console buffer (one time only) */
+ if (c->buf == NULL) {
+ c->bufsize = le32_to_cpu(c->log.buf_size);
+ c->buf = kmalloc(c->bufsize, GFP_ATOMIC);
+ if (c->buf == NULL)
+ return -ENOMEM;
+ }

- /* If waiting for HTAVAIL, check status */
- if (bus->clkstate == CLK_PENDING) {
- int err;
- u8 clkctl, devctl = 0;
+ idx = le32_to_cpu(c->log.idx);

-#ifdef BCMDBG
- /* Check for inconsistent device control */
- devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, &err);
- if (err) {
- brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
- bus->drvr->busstate = BRCMF_BUS_DOWN;
- }
-#endif /* BCMDBG */
+ /* Protect against corrupt value */
+ if (idx > c->bufsize)
+ return -EBADE;

- /* Read CSR, if clock on switch to AVAIL, else ignore */
- clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
- if (err) {
- brcmf_dbg(ERROR, "error reading CSR: %d\n",
- err);
- bus->drvr->busstate = BRCMF_BUS_DOWN;
- }
+ /* Skip reading the console buffer if the index pointer
+ has not moved */
+ if (idx == c->last)
+ return 0;

- brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
- devctl, clkctl);
+ /* Read the console buffer */
+ addr = le32_to_cpu(c->log.buf);
+ rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize);
+ if (rv < 0)
+ return rv;

- if (SBSDIO_HTAV(clkctl)) {
- devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, &err);
- if (err) {
- brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
- err);
- bus->drvr->busstate = BRCMF_BUS_DOWN;
- }
- devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, devctl, &err);
- if (err) {
- brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
- err);
- bus->drvr->busstate = BRCMF_BUS_DOWN;
+ while (c->last != idx) {
+ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
+ if (c->last == idx) {
+ /* This would output a partial line.
+ * Instead, back up
+ * the buffer pointer and output this
+ * line next time around.
+ */
+ if (c->last >= n)
+ c->last -= n;
+ else
+ c->last = c->bufsize - n;
+ goto break2;
}
- bus->clkstate = CLK_AVAIL;
- } else {
- goto clkwait;
+ ch = c->buf[c->last];
+ c->last = (c->last + 1) % c->bufsize;
+ if (ch == '\n')
+ break;
+ line[n] = ch;
}
- }
-
- bus_wake(bus);
-
- /* Make sure backplane clock is on */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
- if (bus->clkstate == CLK_PENDING)
- goto clkwait;

- /* Pending interrupt indicates new device status */
- if (bus->ipend) {
- bus->ipend = false;
- r_sdreg32(bus, &newstatus,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
- bus->f1regdata++;
- if (brcmf_sdcard_regfail(bus->sdiodev))
- newstatus = 0;
- newstatus &= bus->hostintmask;
- bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
- if (newstatus) {
- w_sdreg32(bus, newstatus,
- offsetof(struct sdpcmd_regs, intstatus),
- &retries);
- bus->f1regdata++;
+ if (n > 0) {
+ if (line[n - 1] == '\r')
+ n--;
+ line[n] = 0;
+ printk(KERN_DEBUG "CONSOLE: %s\n", line);
}
}
+break2:

- /* Merge new bits with previous */
- intstatus |= newstatus;
- bus->intstatus = 0;
+ return 0;
+}
+#endif /* BCMDBG */

- /* Handle flow-control change: read new state in case our ack
- * crossed another change interrupt. If change still set, assume
- * FC ON for safety, let next loop through do the debounce.
- */
- if (intstatus & I_HMB_FC_CHANGE) {
- intstatus &= ~I_HMB_FC_CHANGE;
- w_sdreg32(bus, I_HMB_FC_CHANGE,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
+int
+brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
+{
+ u8 *frame;
+ u16 len;
+ u32 swheader;
+ uint retries = 0;
+ u8 doff = 0;
+ int ret = -1;
+ int i;

- r_sdreg32(bus, &newstatus,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
- bus->f1regdata += 2;
- bus->fcstate =
- !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
- intstatus |= (newstatus & bus->hostintmask);
- }
+ brcmf_dbg(TRACE, "Enter\n");

- /* Handle host mailbox indication */
- if (intstatus & I_HMB_HOST_INT) {
- intstatus &= ~I_HMB_HOST_INT;
- intstatus |= brcmf_sdbrcm_hostmail(bus);
- }
+ if (bus->drvr->dongle_reset)
+ return -EIO;

- /* Generally don't ask for these, can get CRC errors... */
- if (intstatus & I_WR_OOSYNC) {
- brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n");
- intstatus &= ~I_WR_OOSYNC;
- }
+ /* Back the pointer to make a room for bus header */
+ frame = msg - SDPCM_HDRLEN;
+ len = (msglen += SDPCM_HDRLEN);

- if (intstatus & I_RD_OOSYNC) {
- brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n");
- intstatus &= ~I_RD_OOSYNC;
+ /* Add alignment padding (optional for ctl frames) */
+ if (brcmf_alignctl) {
+ doff = ((unsigned long)frame % BRCMF_SDALIGN);
+ if (doff) {
+ frame -= doff;
+ len += doff;
+ msglen += doff;
+ memset(frame, 0, doff + SDPCM_HDRLEN);
+ }
+ /* precondition: doff < BRCMF_SDALIGN */
}
+ doff += SDPCM_HDRLEN;

- if (intstatus & I_SBINT) {
- brcmf_dbg(ERROR, "Dongle reports SBINT\n");
- intstatus &= ~I_SBINT;
+ /* Round send length to next SDIO block */
+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
+ u16 pad = bus->blocksize - (len % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize))
+ len += pad;
+ } else if (len % BRCMF_SDALIGN) {
+ len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
}

- /* Would be active due to wake-wlan in gSPI */
- if (intstatus & I_CHIPACTIVE) {
- brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n");
- intstatus &= ~I_CHIPACTIVE;
- }
+ /* Satisfy length-alignment requirements */
+ if (forcealign && (len & (ALIGNMENT - 1)))
+ len = roundup(len, ALIGNMENT);

- /* Ignore frame indications if rxskip is set */
- if (bus->rxskip)
- intstatus &= ~I_HMB_FRAME_IND;
+ /* precondition: IS_ALIGNED((unsigned long)frame, 2) */

- /* On frame indication, read available frames */
- if (PKT_AVAILABLE()) {
- framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone);
- if (rxdone || bus->rxskip)
- intstatus &= ~I_HMB_FRAME_IND;
- rxlimit -= min(framecnt, rxlimit);
- }
+ /* Need to lock here to protect txseq and SDIO tx calls */
+ brcmf_sdbrcm_sdlock(bus);

- /* Keep still-pending events for next scheduling */
- bus->intstatus = intstatus;
+ bus_wake(bus);

-clkwait:
- if (data_ok(bus) && bus->ctrl_frame_stat &&
- (bus->clkstate == CLK_AVAIL)) {
- int ret, i;
+ /* Make sure backplane clock is on */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);

- ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
- SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf,
- (u32) bus->ctrl_frame_len, NULL);
+ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
+ *(u16 *) frame = cpu_to_le16((u16) msglen);
+ *(((u16 *) frame) + 1) = cpu_to_le16(~msglen);

- if (ret < 0) {
- /* On failure, abort the command and
- terminate the frame */
- brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
- ret);
- bus->tx_sderrs++;
+ /* Software tag: channel, sequence number, data offset */
+ swheader =
+ ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
+ SDPCM_CHANNEL_MASK)
+ | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) &
+ SDPCM_DOFFSET_MASK);
+ put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
+ put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));

- brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+ if (!data_ok(bus)) {
+ brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
+ bus->tx_max, bus->tx_seq);
+ bus->ctrl_frame_stat = true;
+ /* Send from dpc */
+ bus->ctrl_frame_buf = frame;
+ bus->ctrl_frame_len = len;

- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
- NULL);
- bus->f1regdata++;
+ brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat);

- for (i = 0; i < 3; i++) {
- u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI,
- NULL);
- lo = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO,
- NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
+ if (bus->ctrl_frame_stat == false) {
+ brcmf_dbg(INFO, "ctrl_frame_stat == false\n");
+ ret = 0;
+ } else {
+ brcmf_dbg(INFO, "ctrl_frame_stat == true\n");
+ ret = -1;
+ }
+ }

+ if (ret == -1) {
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
+ printk(KERN_DEBUG "Tx Frame:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ frame, len);
+ } else if (BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "TxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ frame, min_t(u16, len, 16));
}
- if (ret == 0)
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+#endif

- brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret);
- bus->ctrl_frame_stat = false;
- brcmf_sdbrcm_wait_event_wakeup(bus);
- }
- /* Send queued frames (limit 1 if rx may still be pending) */
- else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
- brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit
- && data_ok(bus)) {
- framecnt = rxdone ? txlimit : min(txlimit, brcmf_txminmax);
- framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt);
- txlimit -= framecnt;
- }
+ do {
+ bus->ctrl_frame_stat = false;
+ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, frame, len, NULL);
+
+ if (ret < 0) {
+ /* On failure, abort the command and
+ terminate the frame */
+ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
+ ret);
+ bus->tx_sderrs++;
+
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL,
+ SFC_WF_TERM, NULL);
+ bus->f1regdata++;
+
+ for (i = 0; i < 3; i++) {
+ u8 hi, lo;
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCHI,
+ NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCLO,
+ NULL);
+ bus->f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
+ }

- /* Resched if events or tx frames are pending,
- else await next interrupt */
- /* On failed register access, all bets are off:
- no resched or interrupts */
- if ((bus->drvr->busstate == 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->intstatus = 0;
- } else if (bus->clkstate == CLK_PENDING) {
- brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n");
- resched = true;
- } else if (bus->intstatus || bus->ipend ||
- (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)
- && data_ok(bus)) || PKT_AVAILABLE()) {
- resched = true;
- }
+ }
+ if (ret == 0)
+ bus->tx_seq =
+ (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;

- bus->dpc_sched = resched;
+ } while ((ret < 0) && retries++ < TXRETRIES);
+ }

- /* If we're done for now, turn off clock request. */
- if ((bus->clkstate != CLK_PENDING)
- && bus->idletime == BRCMF_IDLE_IMMEDIATE) {
+ if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) {
bus->activity = false;
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
}

brcmf_sdbrcm_sdunlock(bus);

- return resched;
+ if (ret)
+ bus->drvr->tx_ctlerrs++;
+ else
+ bus->drvr->tx_ctlpkts++;
+
+ return ret ? -EIO : 0;
}

-void brcmf_sdbrcm_isr(void *arg)
+int
+brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
{
- struct brcmf_bus *bus = (struct brcmf_bus *) arg;
+ int timeleft;
+ uint rxlen = 0;
+ bool pending;

brcmf_dbg(TRACE, "Enter\n");

- if (!bus) {
- brcmf_dbg(ERROR, "bus is null pointer, exiting\n");
- return;
- }
+ if (bus->drvr->dongle_reset)
+ return -EIO;

- if (bus->drvr->busstate == BRCMF_BUS_DOWN) {
- brcmf_dbg(ERROR, "bus is down. we have nothing to do\n");
- return;
- }
- /* Count the interrupt call */
- bus->intrcount++;
- bus->ipend = true;
+ /* Wait until control frame is available */
+ timeleft = brcmf_sdbrcm_ioctl_resp_wait(bus, &bus->rxlen, &pending);

- /* Shouldn't get this interrupt if we're sleeping? */
- if (bus->sleeping) {
- brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n");
- return;
+ brcmf_sdbrcm_sdlock(bus);
+ rxlen = bus->rxlen;
+ memcpy(msg, bus->rxctl, min(msglen, rxlen));
+ bus->rxlen = 0;
+ brcmf_sdbrcm_sdunlock(bus);
+
+ if (rxlen) {
+ brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
+ rxlen, msglen);
+ } else if (timeleft == 0) {
+ brcmf_dbg(ERROR, "resumed on timeout\n");
+#ifdef BCMDBG
+ brcmf_sdbrcm_sdlock(bus);
+ brcmf_sdbrcm_checkdied(bus, NULL, 0);
+ brcmf_sdbrcm_sdunlock(bus);
+#endif /* BCMDBG */
+ } else if (pending == true) {
+ brcmf_dbg(CTL, "cancelled\n");
+ return -ERESTARTSYS;
+ } else {
+ brcmf_dbg(CTL, "resumed for unknown reason?\n");
+#ifdef BCMDBG
+ brcmf_sdbrcm_sdlock(bus);
+ brcmf_sdbrcm_checkdied(bus, NULL, 0);
+ brcmf_sdbrcm_sdunlock(bus);
+#endif /* BCMDBG */
}

- /* Disable additional interrupts (is this needed now)? */
- if (!bus->intr)
- brcmf_dbg(ERROR, "isr w/o interrupt configured!\n");
+ if (rxlen)
+ bus->drvr->rx_ctlpkts++;
+ else
+ bus->drvr->rx_ctlerrs++;

- bus->dpc_sched = true;
- brcmf_sdbrcm_sched_dpc(bus);
+ return rxlen ? (int)rxlen : -ETIMEDOUT;
}

-static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr)
+static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len)
{
- struct brcmf_bus *bus;
+ int bcmerror = 0;

- brcmf_dbg(TIMER, "Enter\n");
+ brcmf_dbg(TRACE, "Enter\n");

- bus = drvr->bus;
+ /* Basic sanity checks */
+ if (bus->drvr->up) {
+ bcmerror = -EISCONN;
+ goto err;
+ }
+ if (!len) {
+ bcmerror = -EOVERFLOW;
+ goto err;
+ }

- if (bus->drvr->dongle_reset)
- return false;
+ /* Free the old ones and replace with passed variables */
+ kfree(bus->vars);

- /* Ignore the timer if simulating bus down */
- if (bus->sleeping)
- return false;
+ bus->vars = kmalloc(len, GFP_ATOMIC);
+ bus->varsz = bus->vars ? len : 0;
+ if (bus->vars == NULL) {
+ bcmerror = -ENOMEM;
+ goto err;
+ }

- brcmf_sdbrcm_sdlock(bus);
+ /* Copy the passed variables, which should include the
+ terminating double-null */
+ memcpy(bus->vars, arg, bus->varsz);
+err:
+ return bcmerror;
+}

- /* Poll period: check device if appropriate. */
- if (bus->poll && (++bus->polltick >= bus->pollrate)) {
- u32 intstatus = 0;
+static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
+{
+ int bcmerror = 0;
+ u32 varsize;
+ u32 varaddr;
+ u8 *vbuffer;
+ u32 varsizew;
+#ifdef BCMDBG
+ char *nvram_ularray;
+#endif /* BCMDBG */

- /* Reset poll tick */
- bus->polltick = 0;
+ /* Even if there are no vars are to be written, we still
+ need to set the ramsize. */
+ varsize = bus->varsz ? roundup(bus->varsz, 4) : 0;
+ varaddr = (bus->ramsize - 4) - varsize;

- /* Check device if no interrupts */
- if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
+ if (bus->vars) {
+ vbuffer = kzalloc(varsize, GFP_ATOMIC);
+ if (!vbuffer)
+ return -ENOMEM;

- if (!bus->dpc_sched) {
- u8 devpend;
- devpend = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_0, SDIO_CCCR_INTx,
- NULL);
- intstatus =
- devpend & (INTR_STATUS_FUNC1 |
- INTR_STATUS_FUNC2);
- }
+ memcpy(vbuffer, bus->vars, bus->varsz);

- /* If there is something, make like the ISR and
- schedule the DPC */
- if (intstatus) {
- bus->pollcnt++;
- bus->ipend = true;
+ /* Write the vars list */
+ bcmerror =
+ brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize);
+#ifdef BCMDBG
+ /* Verify NVRAM bytes */
+ brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize);
+ nvram_ularray = kmalloc(varsize, GFP_ATOMIC);
+ if (!nvram_ularray)
+ return -ENOMEM;

- bus->dpc_sched = true;
- brcmf_sdbrcm_sched_dpc(bus);
+ /* Upload image to verify downloaded contents. */
+ memset(nvram_ularray, 0xaa, varsize);

- }
+ /* Read the vars list to temp buffer for comparison */
+ bcmerror =
+ brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray,
+ varsize);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n",
+ bcmerror, varsize, varaddr);
}
+ /* Compare the org NVRAM with the one read from RAM */
+ if (memcmp(vbuffer, nvram_ularray, varsize))
+ brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n");
+ else
+ brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n");

- /* Update interrupt tracking */
- bus->lastintrs = bus->intrcount;
- }
-#ifdef BCMDBG
- /* Poll for console output periodically */
- if (drvr->busstate == BRCMF_BUS_DATA && brcmf_console_ms != 0) {
- bus->console.count += brcmf_watchdog_ms;
- if (bus->console.count >= brcmf_console_ms) {
- bus->console.count -= brcmf_console_ms;
- /* Make sure backplane clock is on */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- if (brcmf_sdbrcm_readconsole(bus) < 0)
- brcmf_console_ms = 0; /* On error,
- stop trying */
- }
- }
+ kfree(nvram_ularray);
#endif /* BCMDBG */

- /* On idle timeout clear activity flag and/or turn off clock */
- if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
- if (++bus->idlecount >= bus->idletime) {
- bus->idlecount = 0;
- if (bus->activity) {
- bus->activity = false;
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
- } else {
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
- }
- }
+ kfree(vbuffer);
+ }
+
+ /* adjust to the user specified RAM */
+ brcmf_dbg(INFO, "Physical memory size: %d, usable memory size: %d\n",
+ bus->orig_ramsize, bus->ramsize);
+ brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n",
+ varaddr, varsize);
+ varsize = ((bus->orig_ramsize - 4) - varaddr);
+
+ /*
+ * Determine the length token:
+ * Varsize, converted to words, in lower 16-bits, checksum
+ * in upper 16-bits.
+ */
+ if (bcmerror) {
+ varsizew = 0;
+ } else {
+ varsizew = varsize / 4;
+ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
+ varsizew = cpu_to_le32(varsizew);
}

- brcmf_sdbrcm_sdunlock(bus);
+ brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n",
+ varsize, varsizew);

- return bus->ipend;
-}
+ /* Write the length token to the last word */
+ bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->orig_ramsize - 4),
+ (u8 *)&varsizew, 4);

-static bool brcmf_sdbrcm_chipmatch(u16 chipid)
-{
- if (chipid == BCM4329_CHIP_ID)
- return true;
- return false;
+ return bcmerror;
}

-void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
- u32 regsva, struct brcmf_sdio_dev *sdiodev)
+static void
+brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
{
- int ret;
- struct brcmf_bus *bus;
+ u32 regdata;

- /* 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_txbound = BRCMF_TXBOUND;
- brcmf_rxbound = BRCMF_RXBOUND;
- brcmf_alignctl = true;
- brcmf_readahead = true;
- retrydata = false;
- brcmf_dongle_memsize = 0;
- brcmf_txminmax = BRCMF_TXMINMAX;
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ if (regdata & SBTML_RESET)
+ return;

- forcealign = true;
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
+ /*
+ * set target reject and spin until busy is clear
+ * (preserve core-specific bits)
+ */
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow),
+ 4, regdata | SBTML_REJ);

- brcmf_c_init();
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ udelay(1);
+ SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4) &
+ SBTMH_BUSY), 100000);

- brcmf_dbg(TRACE, "Enter\n");
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4);
+ if (regdata & SBTMH_BUSY)
+ brcmf_dbg(ERROR, "ARM core still busy\n");

- /* We make an assumption about address window mappings:
- * regsva == SI_ENUM_BASE*/
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbidlow), 4);
+ if (regdata & SBIDL_INIT) {
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4) |
+ SBIM_RJ;
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbimstate), 4,
+ regdata);
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4);
+ udelay(1);
+ SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4) &
+ SBIM_BY), 100000);
+ }

- /* Allocate private bus interface state */
- bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
- if (!bus) {
- brcmf_dbg(ERROR, "kmalloc of struct dhd_bus failed\n");
- goto fail;
- }
- bus->sdiodev = sdiodev;
- sdiodev->bus = bus;
- bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
- bus->usebufpool = false; /* Use bufpool if allocated,
- else use locally malloced rxbuf */
+ /* set reset and reject while enabling the clocks */
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4,
+ (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
+ SBTML_REJ | SBTML_RESET));
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ udelay(10);

- /* attempt to attach to the dongle */
- if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
- brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n");
- goto fail;
+ /* clear the initiator reject bit */
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbidlow), 4);
+ if (regdata & SBIDL_INIT) {
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4) &
+ ~SBIM_RJ;
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbimstate), 4,
+ regdata);
+ }
}

- spin_lock_init(&bus->txqlock);
- init_waitqueue_head(&bus->ctrl_wait);
- init_waitqueue_head(&bus->ioctl_resp_wait);
+ /* leave reset and reject asserted */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ (SBTML_REJ | SBTML_RESET));
+ udelay(1);
+}

- /* Set up the watchdog timer */
- init_timer(&bus->timer);
- bus->timer.data = (unsigned long)bus;
- bus->timer.function = brcmf_sdbrcm_watchdog;
+static void
+brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
+{
+ u32 regdata;

- /* Initialize thread based operation and lock */
- if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)) {
- bus->threads_only = true;
- sema_init(&bus->sdsem, 1);
- } else {
- bus->threads_only = false;
- spin_lock_init(&bus->sdlock);
- }
+ /*
+ * Must do the disable sequence first to work for
+ * arbitrary current core state.
+ */
+ brcmf_sdbrcm_chip_disablecore(sdiodev, corebase);

- if (brcmf_dpc_prio >= 0) {
- /* Initialize watchdog thread */
- init_completion(&bus->watchdog_wait);
- bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
- bus, "brcmf_watchdog");
- if (IS_ERR(bus->watchdog_tsk)) {
- printk(KERN_WARNING
- "brcmf_watchdog thread failed to start\n");
- bus->watchdog_tsk = NULL;
- }
- } else
- bus->watchdog_tsk = NULL;
+ /*
+ * Now do the initialization sequence.
+ * set reset while enabling the clock and
+ * forcing them on throughout the core
+ */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
+ SBTML_RESET);
+ udelay(1);

- /* Set up the bottom half handler */
- if (brcmf_dpc_prio >= 0) {
- /* Initialize DPC thread */
- init_completion(&bus->dpc_wait);
- bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread,
- bus, "brcmf_dpc");
- if (IS_ERR(bus->dpc_tsk)) {
- printk(KERN_WARNING
- "brcmf_dpc thread failed to start\n");
- bus->dpc_tsk = NULL;
- }
- } else {
- tasklet_init(&bus->tasklet, brcmf_sdbrcm_dpc_tasklet,
- (unsigned long)bus);
- bus->dpc_tsk = NULL;
- }
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4);
+ if (regdata & SBTMH_SERR)
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4, 0);

- /* Attach to the brcmf/OS/network interface */
- bus->drvr = brcmf_attach(bus, SDPCM_RESERVE);
- if (!bus->drvr) {
- brcmf_dbg(ERROR, "brcmf_attach failed\n");
- goto fail;
- }
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4);
+ if (regdata & (SBIM_IBE | SBIM_TO))
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4,
+ regdata & ~(SBIM_IBE | SBIM_TO));

- /* Allocate buffers */
- if (!(brcmf_sdbrcm_probe_malloc(bus))) {
- brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n");
- goto fail;
- }
+ /* clear reset and allow it to propagate throughout the core */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ (SICF_FGC << SBTML_SICF_SHIFT) |
+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
+ udelay(1);

- if (!(brcmf_sdbrcm_probe_init(bus))) {
- brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n");
- goto fail;
- }
+ /* leave clock enabled */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
+ udelay(1);
+}

- /* Register interrupt callback, but mask it (not operational yet). */
- brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n");
- ret = brcmf_sdcard_intr_reg(bus->sdiodev);
- if (ret != 0) {
- brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret);
- goto fail;
- }
- brcmf_dbg(INTR, "registered SDIO interrupt function ok\n");
+static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
+{
+ uint retries;
+ u32 regdata;
+ int bcmerror = 0;

- brcmf_dbg(INFO, "completed!!\n");
+ /* To enter download state, disable ARM and reset SOCRAM.
+ * To exit download state, simply reset ARM (default is RAM boot).
+ */
+ if (enter) {
+ bus->alp_only = true;

- /* if firmware path present try to download and bring up bus */
- ret = brcmf_bus_start(bus->drvr);
- if (ret != 0) {
- if (ret == -ENOLINK) {
- brcmf_dbg(ERROR, "dongle is not responding\n");
+ brcmf_sdbrcm_chip_disablecore(bus->sdiodev,
+ bus->ci->armcorebase);
+
+ brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase);
+
+ /* Clear the top bit of memory */
+ if (bus->ramsize) {
+ u32 zeros = 0;
+ brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4,
+ (u8 *)&zeros, 4);
+ }
+ } else {
+ regdata = brcmf_sdcard_reg_read(bus->sdiodev,
+ CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4);
+ regdata &= (SBTML_RESET | SBTML_REJ_MASK |
+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
+ if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) {
+ brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n");
+ bcmerror = -EBADE;
goto fail;
}
- }
- /* Ok, have the per-port tell the stack we're open for business */
- if (brcmf_net_attach(bus->drvr, 0) != 0) {
- brcmf_dbg(ERROR, "Net attach failed!!\n");
- goto fail;
- }

- return bus;
+ bcmerror = brcmf_sdbrcm_write_vars(bus);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "no vars written to RAM\n");
+ bcmerror = 0;
+ }
+
+ w_sdreg32(bus, 0xFFFFFFFF,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
+
+ brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase);
+
+ /* Allow HT Clock now that the ARM is running. */
+ bus->alp_only = false;

+ bus->drvr->busstate = BRCMF_BUS_LOAD;
+ }
fail:
- brcmf_sdbrcm_release(bus);
- return NULL;
+ return bcmerror;
}

-static bool
-brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
+static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus)
{
- u8 clkctl = 0;
- int err = 0;
- int reg_addr;
- u32 reg_val;
-
- bus->alp_only = true;
-
- /* Return the window to backplane enumeration space for core access */
- if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE))
- brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n");
+ if (bus->firmware->size < bus->fw_ptr + len)
+ len = bus->firmware->size - bus->fw_ptr;

-#ifdef BCMDBG
- printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n",
- brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4));
+ memcpy(buf, &bus->firmware->data[bus->fw_ptr], len);
+ bus->fw_ptr += len;
+ return len;
+}

-#endif /* BCMDBG */
+MODULE_FIRMWARE(BCM4329_FW_NAME);
+MODULE_FIRMWARE(BCM4329_NV_NAME);

- /*
- * Force PLL off until brcmf_sdbrcm_chip_attach()
- * programs PLL control regs
- */
+static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
+{
+ int offset = 0;
+ uint len;
+ u8 *memblock = NULL, *memptr;
+ int ret;

- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- BRCMF_INIT_CLKCTL1, &err);
- if (!err)
- clkctl =
- brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ brcmf_dbg(INFO, "Enter\n");

- if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
- brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
- err, BRCMF_INIT_CLKCTL1, clkctl);
- goto fail;
+ bus->fw_name = BCM4329_FW_NAME;
+ ret = request_firmware(&bus->firmware, bus->fw_name,
+ &bus->sdiodev->func[2]->dev);
+ if (ret) {
+ brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
+ return ret;
}
+ bus->fw_ptr = 0;

- if (brcmf_sdbrcm_chip_attach(bus, regsva)) {
- brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n");
- goto fail;
+ memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC);
+ if (memblock == NULL) {
+ brcmf_dbg(ERROR, "Failed to allocate memory %d bytes\n",
+ MEMBLOCK);
+ ret = -ENOMEM;
+ goto err;
}
+ if ((u32)(unsigned long)memblock % BRCMF_SDALIGN)
+ memptr += (BRCMF_SDALIGN -
+ ((u32)(unsigned long)memblock % BRCMF_SDALIGN));

- if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) {
- brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip);
- goto fail;
+ /* Download image */
+ while ((len =
+ brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) {
+ ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len);
+ if (ret) {
+ brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n",
+ ret, MEMBLOCK, offset);
+ goto err;
+ }
+
+ offset += MEMBLOCK;
}

- brcmf_sdbrcm_sdiod_drive_strength_init(bus, brcmf_sdiod_drive_strength);
+err:
+ kfree(memblock);

- /* Get info on the ARM and SOCRAM cores... */
- brcmf_sdcard_reg_read(bus->sdiodev,
- CORE_SB(bus->ci->armcorebase, sbidhigh), 4);
- bus->orig_ramsize = bus->ci->ramsize;
- if (!(bus->orig_ramsize)) {
- brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n");
- goto fail;
- }
- bus->ramsize = bus->orig_ramsize;
- if (brcmf_dongle_memsize)
- brcmf_sdbrcm_setmemsize(bus, brcmf_dongle_memsize);
+ release_firmware(bus->firmware);
+ bus->fw_ptr = 0;

- brcmf_dbg(ERROR, "DHD: dongle ram size is set to %d(orig %d)\n",
- bus->ramsize, bus->orig_ramsize);
+ return ret;
+}

- /* Set core control so an SDIO reset does a backplane reset */
- reg_addr = bus->ci->buscorebase +
- offsetof(struct sdpcmd_regs, corecontrol);
- reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
- brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
- reg_val | CC_BPRESEN);
+/*
+ * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file
+ * and ending in a NUL.
+ * Removes carriage returns, empty lines, comment lines, and converts
+ * newlines to NULs.
+ * Shortens buffer as needed and pads with NULs. End of buffer is marked
+ * by two NULs.
+*/

- brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
+static uint brcmf_process_nvram_vars(char *varbuf, uint len)
+{
+ char *dp;
+ bool findNewline;
+ int column;
+ uint buf_len, n;

- /* Locate an appropriately-aligned portion of hdrbuf */
- bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
- BRCMF_SDALIGN);
+ dp = varbuf;

- /* Set the poll and/or interrupt flags */
- bus->intr = (bool) brcmf_intr;
- bus->poll = (bool) brcmf_poll;
- if (bus->poll)
- bus->pollrate = 1;
+ findNewline = false;
+ column = 0;

- return true;
+ for (n = 0; n < len; n++) {
+ if (varbuf[n] == 0)
+ break;
+ if (varbuf[n] == '\r')
+ continue;
+ if (findNewline && varbuf[n] != '\n')
+ continue;
+ findNewline = false;
+ if (varbuf[n] == '#') {
+ findNewline = true;
+ continue;
+ }
+ if (varbuf[n] == '\n') {
+ if (column == 0)
+ continue;
+ *dp++ = 0;
+ column = 0;
+ continue;
+ }
+ *dp++ = varbuf[n];
+ column++;
+ }
+ buf_len = dp - varbuf;

-fail:
- return false;
+ while (dp < varbuf + n)
+ *dp++ = 0;
+
+ return buf_len;
}

-static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus)
+static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus)
{
- brcmf_dbg(TRACE, "Enter\n");
+ uint len;
+ char *memblock = NULL;
+ char *bufp;
+ int ret;

- if (bus->drvr->maxctl) {
- bus->rxblen =
- roundup((bus->drvr->maxctl + SDPCM_HDRLEN),
- ALIGNMENT) + BRCMF_SDALIGN;
- bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
- if (!(bus->rxbuf)) {
- brcmf_dbg(ERROR, "kmalloc of %d-byte rxbuf failed\n",
- bus->rxblen);
- goto fail;
- }
+ bus->nv_name = BCM4329_NV_NAME;
+ ret = request_firmware(&bus->firmware, bus->nv_name,
+ &bus->sdiodev->func[2]->dev);
+ if (ret) {
+ brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
+ return ret;
}
+ bus->fw_ptr = 0;

- /* Allocate buffer to receive glomed packet */
- bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC);
- if (!(bus->databuf)) {
- brcmf_dbg(ERROR, "kmalloc of %d-byte databuf failed\n",
- MAX_DATA_BUF);
- /* release rxbuf which was already located as above */
- if (!bus->rxblen)
- kfree(bus->rxbuf);
- goto fail;
+ memblock = kmalloc(MEMBLOCK, GFP_ATOMIC);
+ if (memblock == NULL) {
+ brcmf_dbg(ERROR, "Failed to allocate memory %d bytes\n",
+ MEMBLOCK);
+ ret = -ENOMEM;
+ goto err;
}

- /* Align the buffer */
- if ((unsigned long)bus->databuf % BRCMF_SDALIGN)
- bus->dataptr = bus->databuf + (BRCMF_SDALIGN -
- ((unsigned long)bus->databuf % BRCMF_SDALIGN));
- else
- bus->dataptr = bus->databuf;
+ len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus);
+
+ if (len > 0 && len < MEMBLOCK) {
+ bufp = (char *)memblock;
+ bufp[len] = 0;
+ len = brcmf_process_nvram_vars(bufp, len);
+ bufp += len;
+ *bufp++ = 0;
+ if (len)
+ ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1);
+ if (ret)
+ brcmf_dbg(ERROR, "error downloading vars: %d\n", ret);
+ } else {
+ brcmf_dbg(ERROR, "error reading nvram file: %d\n", len);
+ ret = -EIO;
+ }
+
+err:
+ kfree(memblock);

- return true;
+ release_firmware(bus->firmware);
+ bus->fw_ptr = 0;

-fail:
- return false;
+ return ret;
}

-static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus)
+static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
{
- brcmf_dbg(TRACE, "Enter\n");
-
- /* Disable F2 to clear any intermediate frame state on the dongle */
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- SDIO_FUNC_ENABLE_1, NULL);
+ int bcmerror = -1;

- bus->drvr->busstate = BRCMF_BUS_DOWN;
- bus->sleeping = false;
- bus->rxflow = false;
+ /* Keep arm in reset */
+ if (brcmf_sdbrcm_download_state(bus, true)) {
+ brcmf_dbg(ERROR, "error placing ARM core in reset\n");
+ goto err;
+ }

- /* Done with backplane-dependent accesses, can drop clock... */
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+ /* External image takes precedence if specified */
+ if (brcmf_sdbrcm_download_code_file(bus)) {
+ brcmf_dbg(ERROR, "dongle image file download failed\n");
+ goto err;
+ }

- /* ...and initialize clock/power states */
- bus->clkstate = CLK_SDONLY;
- bus->idletime = (s32) brcmf_idletime;
- bus->idleclock = BRCMF_IDLE_ACTIVE;
+ /* External nvram takes precedence if specified */
+ if (brcmf_sdbrcm_download_nvram(bus))
+ brcmf_dbg(ERROR, "dongle nvram file download failed\n");

- /* Query the F2 block size, set roundup accordingly */
- bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
- bus->roundup = min(max_roundup, bus->blocksize);
+ /* Take arm out of reset */
+ if (brcmf_sdbrcm_download_state(bus, false)) {
+ brcmf_dbg(ERROR, "error getting out of ARM core reset\n");
+ goto err;
+ }

- /* bus module does not support packet chaining */
- bus->use_rxchain = false;
- bus->sd_rxchain = false;
+ bcmerror = 0;

- return true;
+err:
+ return bcmerror;
}

static bool
@@ -4219,359 +3991,478 @@ brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
return ret;
}

-/* Detach and free everything */
-static void brcmf_sdbrcm_release(struct brcmf_bus *bus)
+void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus, bool enforce_mutex)
{
+ u32 local_hostintmask;
+ u8 saveclk;
+ uint retries;
+ int err;
+
brcmf_dbg(TRACE, "Enter\n");

- if (bus) {
- /* De-register interrupt handler */
- brcmf_sdcard_intr_dereg(bus->sdiodev);
+ if (enforce_mutex)
+ brcmf_sdbrcm_sdlock(bus);

- if (bus->drvr) {
- brcmf_detach(bus->drvr);
- brcmf_sdbrcm_release_dongle(bus);
- bus->drvr = NULL;
- }
+ bus_wake(bus);

- brcmf_sdbrcm_release_malloc(bus);
+ /* Enable clock for device interrupts */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);

- kfree(bus);
+ if (bus->watchdog_tsk) {
+ send_sig(SIGTERM, bus->watchdog_tsk, 1);
+ kthread_stop(bus->watchdog_tsk);
+ bus->watchdog_tsk = NULL;
}

- brcmf_dbg(TRACE, "Disconnected\n");
-}
+ if (bus->dpc_tsk) {
+ send_sig(SIGTERM, bus->dpc_tsk, 1);
+ kthread_stop(bus->dpc_tsk);
+ bus->dpc_tsk = NULL;
+ } else
+ tasklet_kill(&bus->tasklet);

-static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus)
-{
- brcmf_dbg(TRACE, "Enter\n");
+ /* Disable and clear interrupts at the chip level also */
+ w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
+ local_hostintmask = bus->hostintmask;
+ bus->hostintmask = 0;

- if (bus->drvr && bus->drvr->dongle_reset)
- return;
+ /* Change our idea of bus state */
+ bus->drvr->busstate = BRCMF_BUS_DOWN;

- kfree(bus->rxbuf);
- bus->rxctl = bus->rxbuf = NULL;
+ /* Force clocks on backplane to be sure F2 interrupt propagates */
+ saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (!err) {
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
+ }
+ if (err)
+ brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
+
+ /* Turn off the bus (F2), free any pending packets */
+ brcmf_dbg(INTR, "disable SDIO interrupts\n");
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ SDIO_FUNC_ENABLE_1, NULL);
+
+ /* Clear any pending interrupts now that F2 is disabled */
+ w_sdreg32(bus, local_hostintmask,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
+
+ /* Turn off the backplane clock (only) */
+ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+
+ /* Clear the data packet queues */
+ brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
+
+ /* Clear any held glomming stuff */
+ if (bus->glomd)
+ brcmu_pkt_buf_free_skb(bus->glomd);
+
+ if (bus->glom)
+ brcmu_pkt_buf_free_skb(bus->glom);
+
+ bus->glom = bus->glomd = NULL;
+
+ /* Clear rx control and wake any waiters */
bus->rxlen = 0;
+ brcmf_sdbrcm_ioctl_resp_wake(bus);

- kfree(bus->databuf);
- bus->databuf = NULL;
+ /* Reset some F2 state stuff */
+ bus->rxskip = false;
+ bus->tx_seq = bus->rx_seq = 0;
+
+ if (enforce_mutex)
+ brcmf_sdbrcm_sdunlock(bus);
}

-static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
+int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr, bool enforce_mutex)
{
- brcmf_dbg(TRACE, "Enter\n");
+ struct brcmf_bus *bus = drvr->bus;
+ unsigned long timeout;
+ uint retries = 0;
+ u8 ready, enable;
+ int err, ret = 0;
+ u8 saveclk;

- if (bus->drvr && bus->drvr->dongle_reset)
- return;
+ brcmf_dbg(TRACE, "Enter\n");

- if (bus->ci) {
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
- brcmf_sdbrcm_chip_detach(bus);
- if (bus->vars && bus->varsz)
- kfree(bus->vars);
- bus->vars = NULL;
+ /* try to download image and nvram to the dongle */
+ if (drvr->busstate == BRCMF_BUS_DOWN) {
+ if (!(brcmf_sdbrcm_download_firmware(bus)))
+ return -1;
}

- brcmf_dbg(TRACE, "Disconnected\n");
-}
+ if (!bus->drvr)
+ return 0;

-void brcmf_sdbrcm_disconnect(void *ptr)
-{
- struct brcmf_bus *bus = (struct brcmf_bus *)ptr;
+ /* Start the watchdog timer */
+ bus->drvr->tickcnt = 0;
+ brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);

- brcmf_dbg(TRACE, "Enter\n");
+ if (enforce_mutex)
+ brcmf_sdbrcm_sdlock(bus);

- if (bus)
- brcmf_sdbrcm_release(bus);
+ /* Make sure backplane clock is on, needed to generate F2 interrupt */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ if (bus->clkstate != CLK_AVAIL)
+ goto exit;

- brcmf_dbg(TRACE, "Disconnected\n");
-}
+ /* Force clocks on backplane to be sure F2 interrupt propagates */
+ saveclk =
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (!err) {
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
+ }
+ if (err) {
+ brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
+ goto exit;
+ }

-int brcmf_bus_register(void)
-{
- brcmf_dbg(TRACE, "Enter\n");
+ /* Enable function 2 (frame transfers) */
+ w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
+ offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries);
+ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);

- /* Sanity check on the module parameters */
- do {
- /* Both watchdog and DPC as tasklets are ok */
- if ((brcmf_watchdog_prio < 0) && (brcmf_dpc_prio < 0))
- break;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ enable, NULL);

- /* If both watchdog and DPC are threads, TX must be deferred */
- if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)
- && brcmf_deferred_tx)
+ timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY);
+ ready = 0;
+ while (enable != ready) {
+ ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0,
+ SDIO_CCCR_IORx, NULL);
+ if (time_after(jiffies, timeout))
break;
+ else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
+ /* prevent busy waiting if it takes too long */
+ msleep_interruptible(20);
+ }

- brcmf_dbg(ERROR, "Invalid module parameters.\n");
- return -EINVAL;
- } while (0);
+ brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready);
+
+ /* If F2 successfully enabled, set core and enable interrupts */
+ if (ready == enable) {
+ /* Set up the interrupt mask and enable interrupts */
+ bus->hostintmask = HOSTINTMASK;
+ w_sdreg32(bus, bus->hostintmask,
+ offsetof(struct sdpcmd_regs, hostintmask), &retries);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_WATERMARK, 8, &err);
+
+ /* Set bus state according to enable result */
+ drvr->busstate = BRCMF_BUS_DATA;
+ }
+
+ else {
+ /* Disable F2 again */
+ enable = SDIO_FUNC_ENABLE_1;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
+ SDIO_CCCR_IOEx, enable, NULL);
+ }
+
+ /* Restore previous clock setting */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);

- return brcmf_sdio_register();
-}
+ /* If we didn't come up, turn off backplane clock */
+ if (drvr->busstate != BRCMF_BUS_DATA)
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);

-void brcmf_bus_unregister(void)
-{
- brcmf_dbg(TRACE, "Enter\n");
+exit:
+ if (enforce_mutex)
+ brcmf_sdbrcm_sdunlock(bus);

- brcmf_sdio_unregister();
+ return ret;
}

-struct device *brcmf_bus_get_device(struct brcmf_bus *bus)
+void brcmf_sdbrcm_isr(void *arg)
{
- return &bus->sdiodev->func[2]->dev;
-}
+ struct brcmf_bus *bus = (struct brcmf_bus *) arg;

-static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
-{
- int offset = 0;
- uint len;
- u8 *memblock = NULL, *memptr;
- int ret;
+ brcmf_dbg(TRACE, "Enter\n");

- brcmf_dbg(INFO, "Enter\n");
+ if (!bus) {
+ brcmf_dbg(ERROR, "bus is null pointer, exiting\n");
+ return;
+ }

- bus->fw_name = BCM4329_FW_NAME;
- ret = request_firmware(&bus->firmware, bus->fw_name,
- &bus->sdiodev->func[2]->dev);
- if (ret) {
- brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
- return ret;
+ if (bus->drvr->busstate == BRCMF_BUS_DOWN) {
+ brcmf_dbg(ERROR, "bus is down. we have nothing to do\n");
+ return;
}
- bus->fw_ptr = 0;
+ /* Count the interrupt call */
+ bus->intrcount++;
+ bus->ipend = true;

- memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC);
- if (memblock == NULL) {
- brcmf_dbg(ERROR, "Failed to allocate memory %d bytes\n",
- MEMBLOCK);
- ret = -ENOMEM;
- goto err;
+ /* Shouldn't get this interrupt if we're sleeping? */
+ if (bus->sleeping) {
+ brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n");
+ return;
}
- if ((u32)(unsigned long)memblock % BRCMF_SDALIGN)
- memptr += (BRCMF_SDALIGN -
- ((u32)(unsigned long)memblock % BRCMF_SDALIGN));

- /* Download image */
- while ((len =
- brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) {
- ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len);
- if (ret) {
- brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n",
- ret, MEMBLOCK, offset);
- goto err;
- }
+ /* Disable additional interrupts (is this needed now)? */
+ if (!bus->intr)
+ brcmf_dbg(ERROR, "isr w/o interrupt configured!\n");

- offset += MEMBLOCK;
- }
+ bus->dpc_sched = true;
+ brcmf_sdbrcm_sched_dpc(bus);
+}

-err:
- kfree(memblock);
+static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr)
+{
+ struct brcmf_bus *bus;

- release_firmware(bus->firmware);
- bus->fw_ptr = 0;
+ brcmf_dbg(TIMER, "Enter\n");

- return ret;
-}
+ bus = drvr->bus;

-/*
- * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file
- * and ending in a NUL.
- * Removes carriage returns, empty lines, comment lines, and converts
- * newlines to NULs.
- * Shortens buffer as needed and pads with NULs. End of buffer is marked
- * by two NULs.
-*/
+ if (bus->drvr->dongle_reset)
+ return false;

-static uint brcmf_process_nvram_vars(char *varbuf, uint len)
-{
- char *dp;
- bool findNewline;
- int column;
- uint buf_len, n;
+ /* Ignore the timer if simulating bus down */
+ if (bus->sleeping)
+ return false;

- dp = varbuf;
+ brcmf_sdbrcm_sdlock(bus);

- findNewline = false;
- column = 0;
+ /* Poll period: check device if appropriate. */
+ if (bus->poll && (++bus->polltick >= bus->pollrate)) {
+ u32 intstatus = 0;

- for (n = 0; n < len; n++) {
- if (varbuf[n] == 0)
- break;
- if (varbuf[n] == '\r')
- continue;
- if (findNewline && varbuf[n] != '\n')
- continue;
- findNewline = false;
- if (varbuf[n] == '#') {
- findNewline = true;
- continue;
- }
- if (varbuf[n] == '\n') {
- if (column == 0)
- continue;
- *dp++ = 0;
- column = 0;
- continue;
- }
- *dp++ = varbuf[n];
- column++;
- }
- buf_len = dp - varbuf;
+ /* Reset poll tick */
+ bus->polltick = 0;

- while (dp < varbuf + n)
- *dp++ = 0;
+ /* Check device if no interrupts */
+ if (!bus->intr || (bus->intrcount == bus->lastintrs)) {

- return buf_len;
-}
+ if (!bus->dpc_sched) {
+ u8 devpend;
+ devpend = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_0, SDIO_CCCR_INTx,
+ NULL);
+ intstatus =
+ devpend & (INTR_STATUS_FUNC1 |
+ INTR_STATUS_FUNC2);
+ }

-static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus)
-{
- uint len;
- char *memblock = NULL;
- char *bufp;
- int ret;
+ /* If there is something, make like the ISR and
+ schedule the DPC */
+ if (intstatus) {
+ bus->pollcnt++;
+ bus->ipend = true;

- bus->nv_name = BCM4329_NV_NAME;
- ret = request_firmware(&bus->firmware, bus->nv_name,
- &bus->sdiodev->func[2]->dev);
- if (ret) {
- brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
- return ret;
- }
- bus->fw_ptr = 0;
+ bus->dpc_sched = true;
+ brcmf_sdbrcm_sched_dpc(bus);

- memblock = kmalloc(MEMBLOCK, GFP_ATOMIC);
- if (memblock == NULL) {
- brcmf_dbg(ERROR, "Failed to allocate memory %d bytes\n",
- MEMBLOCK);
- ret = -ENOMEM;
- goto err;
- }
+ }
+ }

- len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus);
+ /* Update interrupt tracking */
+ bus->lastintrs = bus->intrcount;
+ }
+#ifdef BCMDBG
+ /* Poll for console output periodically */
+ if (drvr->busstate == BRCMF_BUS_DATA && brcmf_console_ms != 0) {
+ bus->console.count += brcmf_watchdog_ms;
+ if (bus->console.count >= brcmf_console_ms) {
+ bus->console.count -= brcmf_console_ms;
+ /* Make sure backplane clock is on */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ if (brcmf_sdbrcm_readconsole(bus) < 0)
+ brcmf_console_ms = 0; /* On error,
+ stop trying */
+ }
+ }
+#endif /* BCMDBG */

- if (len > 0 && len < MEMBLOCK) {
- bufp = (char *)memblock;
- bufp[len] = 0;
- len = brcmf_process_nvram_vars(bufp, len);
- bufp += len;
- *bufp++ = 0;
- if (len)
- ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1);
- if (ret)
- brcmf_dbg(ERROR, "error downloading vars: %d\n", ret);
- } else {
- brcmf_dbg(ERROR, "error reading nvram file: %d\n", len);
- ret = -EIO;
+ /* On idle timeout clear activity flag and/or turn off clock */
+ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
+ if (++bus->idlecount >= bus->idletime) {
+ bus->idlecount = 0;
+ if (bus->activity) {
+ bus->activity = false;
+ brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
+ } else {
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ }
+ }
}

-err:
- kfree(memblock);
+ brcmf_sdbrcm_sdunlock(bus);

- release_firmware(bus->firmware);
- bus->fw_ptr = 0;
+ return bus->ipend;
+}

- return ret;
+static bool brcmf_sdbrcm_chipmatch(u16 chipid)
+{
+ if (chipid == BCM4329_CHIP_ID)
+ return true;
+ return false;
}

-static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
+static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus)
{
- int bcmerror = -1;
+ brcmf_dbg(TRACE, "Enter\n");

- /* Keep arm in reset */
- if (brcmf_sdbrcm_download_state(bus, true)) {
- brcmf_dbg(ERROR, "error placing ARM core in reset\n");
- goto err;
- }
+ if (bus->drvr && bus->drvr->dongle_reset)
+ return;

- /* External image takes precedence if specified */
- if (brcmf_sdbrcm_download_code_file(bus)) {
- brcmf_dbg(ERROR, "dongle image file download failed\n");
- goto err;
- }
+ kfree(bus->rxbuf);
+ bus->rxctl = bus->rxbuf = NULL;
+ bus->rxlen = 0;

- /* External nvram takes precedence if specified */
- if (brcmf_sdbrcm_download_nvram(bus))
- brcmf_dbg(ERROR, "dongle nvram file download failed\n");
+ kfree(bus->databuf);
+ bus->databuf = NULL;
+}

- /* Take arm out of reset */
- if (brcmf_sdbrcm_download_state(bus, false)) {
- brcmf_dbg(ERROR, "error getting out of ARM core reset\n");
- goto err;
+static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus->drvr->maxctl) {
+ bus->rxblen =
+ roundup((bus->drvr->maxctl + SDPCM_HDRLEN),
+ ALIGNMENT) + BRCMF_SDALIGN;
+ bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
+ if (!(bus->rxbuf)) {
+ brcmf_dbg(ERROR, "kmalloc of %d-byte rxbuf failed\n",
+ bus->rxblen);
+ goto fail;
+ }
}

- bcmerror = 0;
+ /* Allocate buffer to receive glomed packet */
+ bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC);
+ if (!(bus->databuf)) {
+ brcmf_dbg(ERROR, "kmalloc of %d-byte databuf failed\n",
+ MAX_DATA_BUF);
+ /* release rxbuf which was already located as above */
+ if (!bus->rxblen)
+ kfree(bus->rxbuf);
+ goto fail;
+ }

-err:
- return bcmerror;
-}
+ /* Align the buffer */
+ if ((unsigned long)bus->databuf % BRCMF_SDALIGN)
+ bus->dataptr = bus->databuf + (BRCMF_SDALIGN -
+ ((unsigned long)bus->databuf % BRCMF_SDALIGN));
+ else
+ bus->dataptr = bus->databuf;

+ return true;

-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);
+fail:
+ return false;
}

-int brcmf_bus_devreset(struct brcmf_pub *drvr, u8 flag)
-{
- int bcmerror = 0;
- struct brcmf_bus *bus;
-
- bus = drvr->bus;
+/* SDIO Pad drive strength to select value mappings */
+struct sdiod_drive_str {
+ u8 strength; /* Pad Drive Strength in mA */
+ u8 sel; /* Chip-specific select value */
+};

- if (flag == true) {
- brcmf_sdbrcm_wd_timer(bus, 0);
- if (!bus->drvr->dongle_reset) {
- /* Expect app to have torn down any
- connection before calling */
- /* Stop the bus, disable F2 */
- brcmf_sdbrcm_bus_stop(bus, false);
+/* SDIO Drive Strength to sel value table for PMU Rev 1 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
+ {
+ 4, 0x2}, {
+ 2, 0x3}, {
+ 1, 0x0}, {
+ 0, 0x0}
+ };

- /* Clean tx/rx buffer pointers,
- detach from the dongle */
- brcmf_sdbrcm_release_dongle(bus);
+/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
+ {
+ 12, 0x7}, {
+ 10, 0x6}, {
+ 8, 0x5}, {
+ 6, 0x4}, {
+ 4, 0x2}, {
+ 2, 0x1}, {
+ 0, 0x0}
+ };

- bus->drvr->dongle_reset = true;
- bus->drvr->up = false;
+/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
+static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
+ {
+ 32, 0x7}, {
+ 26, 0x6}, {
+ 22, 0x5}, {
+ 16, 0x4}, {
+ 12, 0x3}, {
+ 8, 0x2}, {
+ 4, 0x1}, {
+ 0, 0x0}
+ };

- brcmf_dbg(TRACE, "WLAN OFF DONE\n");
- /* App can now remove power from device */
- } else
- bcmerror = -EIO;
- } else {
- /* App must have restored power to device before calling */
+#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))

- brcmf_dbg(TRACE, " == WLAN ON ==\n");
+static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
+ u32 drivestrength) {
+ struct sdiod_drive_str *str_tab = NULL;
+ u32 str_mask = 0;
+ u32 str_shift = 0;
+ char chn[8];

- if (bus->drvr->dongle_reset) {
- /* Turn on WLAN */
+ if (!(bus->ci->cccaps & CC_CAP_PMU))
+ return;

- /* Attempt to re-attach & download */
- if (brcmf_sdbrcm_probe_attach(bus, SI_ENUM_BASE)) {
- /* Attempt to download binary to the dongle */
- if (brcmf_sdbrcm_probe_init(bus)) {
- /* Re-init bus, enable F2 transfer */
- brcmf_sdbrcm_bus_init(bus->drvr, false);
+ switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) {
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
+ str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
+ str_mask = 0x30000000;
+ str_shift = 28;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
+ str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
+ str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ default:
+ brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
+ brcmu_chipname(bus->ci->chip, chn, 8),
+ bus->ci->chiprev, bus->ci->pmurev);
+ break;
+ }

- bus->drvr->dongle_reset = false;
- bus->drvr->up = true;
+ if (str_tab != NULL) {
+ u32 drivestrength_sel = 0;
+ u32 cc_data_temp;
+ int i;

- brcmf_dbg(TRACE, "WLAN ON DONE\n");
- } else
- bcmerror = -EIO;
- } else
- bcmerror = -EIO;
- } else {
- bcmerror = -EISCONN;
- brcmf_dbg(ERROR, "Set DEVRESET=false invoked when device is on\n");
- bcmerror = -EIO;
+ for (i = 0; str_tab[i].strength != 0; i++) {
+ if (drivestrength >= str_tab[i].strength) {
+ drivestrength_sel = str_tab[i].sel;
+ break;
+ }
}
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
+
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
+ 4, 1);
+ cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev,
+ CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4);
+ cc_data_temp &= ~str_mask;
+ drivestrength_sel <<= str_shift;
+ cc_data_temp |= drivestrength_sel;
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
+ 4, cc_data_temp);
+
+ brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
+ drivestrength, cc_data_temp);
}
- return bcmerror;
}

static int
@@ -4615,98 +4506,19 @@ brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_dev *sdiodev,
CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
ci->pmurev = regdata & PCAP_REV_MASK;

- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->buscorebase, sbidhigh), 4);
- ci->buscorerev = SBCOREREV(regdata);
- ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
-
- brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
- ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype);
-
- /* get chipcommon capabilites */
- ci->cccaps = brcmf_sdcard_reg_read(sdiodev,
- CORE_CC_REG(ci->cccorebase, capabilities), 4);
-
- return 0;
-}
-
-static void
-brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
-{
- u32 regdata;
-
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbtmstatelow), 4);
- if (regdata & SBTML_RESET)
- return;
-
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbtmstatelow), 4);
- if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
- /*
- * set target reject and spin until busy is clear
- * (preserve core-specific bits)
- */
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbtmstatelow), 4);
- brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow),
- 4, regdata | SBTML_REJ);
-
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbtmstatelow), 4);
- udelay(1);
- SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbtmstatehigh), 4) &
- SBTMH_BUSY), 100000);
-
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbtmstatehigh), 4);
- if (regdata & SBTMH_BUSY)
- brcmf_dbg(ERROR, "ARM core still busy\n");
-
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbidlow), 4);
- if (regdata & SBIDL_INIT) {
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbimstate), 4) |
- SBIM_RJ;
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(corebase, sbimstate), 4,
- regdata);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbimstate), 4);
- udelay(1);
- SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbimstate), 4) &
- SBIM_BY), 100000);
- }
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(ci->buscorebase, sbidhigh), 4);
+ ci->buscorerev = SBCOREREV(regdata);
+ ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;

- /* set reset and reject while enabling the clocks */
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(corebase, sbtmstatelow), 4,
- (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
- SBTML_REJ | SBTML_RESET));
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbtmstatelow), 4);
- udelay(10);
+ brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
+ ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype);

- /* clear the initiator reject bit */
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbidlow), 4);
- if (regdata & SBIDL_INIT) {
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbimstate), 4) &
- ~SBIM_RJ;
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(corebase, sbimstate), 4,
- regdata);
- }
- }
+ /* get chipcommon capabilites */
+ ci->cccaps = brcmf_sdcard_reg_read(sdiodev,
+ CORE_CC_REG(ci->cccorebase, capabilities), 4);

- /* leave reset and reject asserted */
- brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
- (SBTML_REJ | SBTML_RESET));
- udelay(1);
+ return 0;
}

static int
@@ -4804,234 +4616,483 @@ fail:
return err;
}

-static void
-brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
+static bool
+brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
+{
+ u8 clkctl = 0;
+ int err = 0;
+ int reg_addr;
+ u32 reg_val;
+
+ bus->alp_only = true;
+
+ /* Return the window to backplane enumeration space for core access */
+ if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE))
+ brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n");
+
+#ifdef BCMDBG
+ printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n",
+ brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4));
+
+#endif /* BCMDBG */
+
+ /*
+ * Force PLL off until brcmf_sdbrcm_chip_attach()
+ * programs PLL control regs
+ */
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ BRCMF_INIT_CLKCTL1, &err);
+ if (!err)
+ clkctl =
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+
+ if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
+ brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
+ err, BRCMF_INIT_CLKCTL1, clkctl);
+ goto fail;
+ }
+
+ if (brcmf_sdbrcm_chip_attach(bus, regsva)) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n");
+ goto fail;
+ }
+
+ if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) {
+ brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip);
+ goto fail;
+ }
+
+ brcmf_sdbrcm_sdiod_drive_strength_init(bus, brcmf_sdiod_drive_strength);
+
+ /* Get info on the ARM and SOCRAM cores... */
+ brcmf_sdcard_reg_read(bus->sdiodev,
+ CORE_SB(bus->ci->armcorebase, sbidhigh), 4);
+ bus->orig_ramsize = bus->ci->ramsize;
+ if (!(bus->orig_ramsize)) {
+ brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n");
+ goto fail;
+ }
+ bus->ramsize = bus->orig_ramsize;
+ if (brcmf_dongle_memsize)
+ brcmf_sdbrcm_setmemsize(bus, brcmf_dongle_memsize);
+
+ brcmf_dbg(ERROR, "DHD: dongle ram size is set to %d(orig %d)\n",
+ bus->ramsize, bus->orig_ramsize);
+
+ /* Set core control so an SDIO reset does a backplane reset */
+ reg_addr = bus->ci->buscorebase +
+ offsetof(struct sdpcmd_regs, corecontrol);
+ reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
+ brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
+ reg_val | CC_BPRESEN);
+
+ brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
+
+ /* Locate an appropriately-aligned portion of hdrbuf */
+ bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
+ BRCMF_SDALIGN);
+
+ /* Set the poll and/or interrupt flags */
+ bus->intr = (bool) brcmf_intr;
+ bus->poll = (bool) brcmf_poll;
+ if (bus->poll)
+ bus->pollrate = 1;
+
+ return true;
+
+fail:
+ return false;
+}
+
+static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Disable F2 to clear any intermediate frame state on the dongle */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ SDIO_FUNC_ENABLE_1, NULL);
+
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ bus->sleeping = false;
+ bus->rxflow = false;
+
+ /* Done with backplane-dependent accesses, can drop clock... */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+
+ /* ...and initialize clock/power states */
+ bus->clkstate = CLK_SDONLY;
+ bus->idletime = (s32) brcmf_idletime;
+ bus->idleclock = BRCMF_IDLE_ACTIVE;
+
+ /* Query the F2 block size, set roundup accordingly */
+ bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
+ bus->roundup = min(max_roundup, bus->blocksize);
+
+ /* bus module does not support packet chaining */
+ bus->use_rxchain = false;
+ bus->sd_rxchain = false;
+
+ return true;
+}
+
+static int
+brcmf_sdbrcm_watchdog_thread(void *data)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *)data;
+
+ /* This thread doesn't need any user-level access,
+ * so get rid of all our resources
+ */
+ if (brcmf_watchdog_prio > 0) {
+ struct sched_param param;
+ param.sched_priority = (brcmf_watchdog_prio < MAX_RT_PRIO) ?
+ brcmf_watchdog_prio : (MAX_RT_PRIO - 1);
+ sched_setscheduler(current, SCHED_FIFO, &param);
+ }
+
+ allow_signal(SIGTERM);
+ /* Run until signal received */
+ while (1) {
+ if (kthread_should_stop())
+ break;
+ if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
+ if (bus->drvr->dongle_reset == false)
+ brcmf_sdbrcm_bus_watchdog(bus->drvr);
+ /* Count the tick for reference */
+ bus->drvr->tickcnt++;
+ } else
+ break;
+ }
+ return 0;
+}
+
+static void
+brcmf_sdbrcm_watchdog(unsigned long data)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *)data;
+
+ if (brcmf_watchdog_prio >= 0) {
+ if (bus->watchdog_tsk)
+ complete(&bus->watchdog_wait);
+ else
+ return;
+ } else {
+ brcmf_sdbrcm_bus_watchdog(bus->drvr);
+
+ /* Count the tick for reference */
+ bus->drvr->tickcnt++;
+ }
+
+ /* Reschedule the watchdog */
+ if (bus->wd_timer_valid)
+ mod_timer(&bus->timer, jiffies + brcmf_watchdog_ms * HZ / 1000);
+}
+
+static void
+brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ kfree(bus->ci);
+ bus->ci = NULL;
+}
+
+static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus->drvr && bus->drvr->dongle_reset)
+ return;
+
+ if (bus->ci) {
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ brcmf_sdbrcm_chip_detach(bus);
+ if (bus->vars && bus->varsz)
+ kfree(bus->vars);
+ bus->vars = NULL;
+ }
+
+ brcmf_dbg(TRACE, "Disconnected\n");
+}
+
+/* Detach and free everything */
+static void brcmf_sdbrcm_release(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus) {
+ /* De-register interrupt handler */
+ brcmf_sdcard_intr_dereg(bus->sdiodev);
+
+ if (bus->drvr) {
+ brcmf_detach(bus->drvr);
+ brcmf_sdbrcm_release_dongle(bus);
+ bus->drvr = NULL;
+ }
+
+ brcmf_sdbrcm_release_malloc(bus);
+
+ kfree(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)
{
- u32 regdata;
+ int ret;
+ struct brcmf_bus *bus;

- /*
- * Must do the disable sequence first to work for
- * arbitrary current core state.
+ /* 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_sdbrcm_chip_disablecore(sdiodev, corebase);
+ brcmf_txbound = BRCMF_TXBOUND;
+ brcmf_rxbound = BRCMF_RXBOUND;
+ brcmf_alignctl = true;
+ brcmf_readahead = true;
+ retrydata = false;
+ brcmf_dongle_memsize = 0;
+ brcmf_txminmax = BRCMF_TXMINMAX;

- /*
- * Now do the initialization sequence.
- * set reset while enabling the clock and
- * forcing them on throughout the core
- */
- brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
- ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
- SBTML_RESET);
- udelay(1);
+ forcealign = true;

- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbtmstatehigh), 4);
- if (regdata & SBTMH_SERR)
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(corebase, sbtmstatehigh), 4, 0);
+ brcmf_c_init();

- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(corebase, sbimstate), 4);
- if (regdata & (SBIM_IBE | SBIM_TO))
- brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4,
- regdata & ~(SBIM_IBE | SBIM_TO));
+ brcmf_dbg(TRACE, "Enter\n");

- /* clear reset and allow it to propagate throughout the core */
- brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
- (SICF_FGC << SBTML_SICF_SHIFT) |
- (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
- udelay(1);
+ /* We make an assumption about address window mappings:
+ * regsva == SI_ENUM_BASE*/

- /* leave clock enabled */
- brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
- (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
- udelay(1);
-}
+ /* Allocate private bus interface state */
+ bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
+ if (!bus) {
+ brcmf_dbg(ERROR, "kmalloc of struct dhd_bus failed\n");
+ goto fail;
+ }
+ bus->sdiodev = sdiodev;
+ sdiodev->bus = bus;
+ bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
+ bus->usebufpool = false; /* Use bufpool if allocated,
+ else use locally malloced rxbuf */

-/* SDIO Pad drive strength to select value mappings */
-struct sdiod_drive_str {
- u8 strength; /* Pad Drive Strength in mA */
- u8 sel; /* Chip-specific select value */
-};
+ /* attempt to attach to the dongle */
+ if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n");
+ goto fail;
+ }

-/* SDIO Drive Strength to sel value table for PMU Rev 1 */
-static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
- {
- 4, 0x2}, {
- 2, 0x3}, {
- 1, 0x0}, {
- 0, 0x0}
- };
+ spin_lock_init(&bus->txqlock);
+ init_waitqueue_head(&bus->ctrl_wait);
+ init_waitqueue_head(&bus->ioctl_resp_wait);

-/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
-static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
- {
- 12, 0x7}, {
- 10, 0x6}, {
- 8, 0x5}, {
- 6, 0x4}, {
- 4, 0x2}, {
- 2, 0x1}, {
- 0, 0x0}
- };
+ /* Set up the watchdog timer */
+ init_timer(&bus->timer);
+ bus->timer.data = (unsigned long)bus;
+ bus->timer.function = brcmf_sdbrcm_watchdog;

-/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
-static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
- {
- 32, 0x7}, {
- 26, 0x6}, {
- 22, 0x5}, {
- 16, 0x4}, {
- 12, 0x3}, {
- 8, 0x2}, {
- 4, 0x1}, {
- 0, 0x0}
- };
+ /* Initialize thread based operation and lock */
+ if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)) {
+ bus->threads_only = true;
+ sema_init(&bus->sdsem, 1);
+ } else {
+ bus->threads_only = false;
+ spin_lock_init(&bus->sdlock);
+ }

-#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
+ if (brcmf_dpc_prio >= 0) {
+ /* Initialize watchdog thread */
+ init_completion(&bus->watchdog_wait);
+ bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
+ bus, "brcmf_watchdog");
+ if (IS_ERR(bus->watchdog_tsk)) {
+ printk(KERN_WARNING
+ "brcmf_watchdog thread failed to start\n");
+ bus->watchdog_tsk = NULL;
+ }
+ } else
+ bus->watchdog_tsk = NULL;

-static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
- u32 drivestrength) {
- struct sdiod_drive_str *str_tab = NULL;
- u32 str_mask = 0;
- u32 str_shift = 0;
- char chn[8];
+ /* Set up the bottom half handler */
+ if (brcmf_dpc_prio >= 0) {
+ /* Initialize DPC thread */
+ init_completion(&bus->dpc_wait);
+ bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread,
+ bus, "brcmf_dpc");
+ if (IS_ERR(bus->dpc_tsk)) {
+ printk(KERN_WARNING
+ "brcmf_dpc thread failed to start\n");
+ bus->dpc_tsk = NULL;
+ }
+ } else {
+ tasklet_init(&bus->tasklet, brcmf_sdbrcm_dpc_tasklet,
+ (unsigned long)bus);
+ bus->dpc_tsk = NULL;
+ }

- if (!(bus->ci->cccaps & CC_CAP_PMU))
- return;
+ /* Attach to the brcmf/OS/network interface */
+ bus->drvr = brcmf_attach(bus, SDPCM_RESERVE);
+ if (!bus->drvr) {
+ brcmf_dbg(ERROR, "brcmf_attach failed\n");
+ goto fail;
+ }

- switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) {
- case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
- str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
- str_mask = 0x30000000;
- str_shift = 28;
- break;
- case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
- case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
- str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
- str_mask = 0x00003800;
- str_shift = 11;
- break;
- case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
- str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
- str_mask = 0x00003800;
- str_shift = 11;
- break;
- default:
- brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
- brcmu_chipname(bus->ci->chip, chn, 8),
- bus->ci->chiprev, bus->ci->pmurev);
- break;
+ /* Allocate buffers */
+ if (!(brcmf_sdbrcm_probe_malloc(bus))) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n");
+ goto fail;
}

- if (str_tab != NULL) {
- u32 drivestrength_sel = 0;
- u32 cc_data_temp;
- int i;
+ if (!(brcmf_sdbrcm_probe_init(bus))) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n");
+ goto fail;
+ }

- for (i = 0; str_tab[i].strength != 0; i++) {
- if (drivestrength >= str_tab[i].strength) {
- drivestrength_sel = str_tab[i].sel;
- break;
- }
+ /* Register interrupt callback, but mask it (not operational yet). */
+ brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n");
+ ret = brcmf_sdcard_intr_reg(bus->sdiodev);
+ if (ret != 0) {
+ brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret);
+ goto fail;
+ }
+ brcmf_dbg(INTR, "registered SDIO interrupt function ok\n");
+
+ brcmf_dbg(INFO, "completed!!\n");
+
+ /* if firmware path present try to download and bring up bus */
+ ret = brcmf_bus_start(bus->drvr);
+ if (ret != 0) {
+ if (ret == -ENOLINK) {
+ brcmf_dbg(ERROR, "dongle is not responding\n");
+ goto fail;
}
+ }
+ /* Ok, have the per-port tell the stack we're open for business */
+ if (brcmf_net_attach(bus->drvr, 0) != 0) {
+ brcmf_dbg(ERROR, "Net attach failed!!\n");
+ goto fail;
+ }

- brcmf_sdcard_reg_write(bus->sdiodev,
- CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
- 4, 1);
- cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev,
- CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4);
- cc_data_temp &= ~str_mask;
- drivestrength_sel <<= str_shift;
- cc_data_temp |= drivestrength_sel;
- brcmf_sdcard_reg_write(bus->sdiodev,
- CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
- 4, cc_data_temp);
+ return bus;
+
+fail:
+ brcmf_sdbrcm_release(bus);
+ return NULL;
+}
+
+void brcmf_sdbrcm_disconnect(void *ptr)
+{
+ struct brcmf_bus *bus = (struct brcmf_bus *)ptr;

- brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
- drivestrength, cc_data_temp);
- }
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus)
+ brcmf_sdbrcm_release(bus);
+
+ brcmf_dbg(TRACE, "Disconnected\n");
}

-static void
-brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus)
+int brcmf_bus_register(void)
{
brcmf_dbg(TRACE, "Enter\n");

- kfree(bus->ci);
- bus->ci = NULL;
+ /* Sanity check on the module parameters */
+ do {
+ /* Both watchdog and DPC as tasklets are ok */
+ if ((brcmf_watchdog_prio < 0) && (brcmf_dpc_prio < 0))
+ break;
+
+ /* If both watchdog and DPC are threads, TX must be deferred */
+ if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)
+ && brcmf_deferred_tx)
+ break;
+
+ brcmf_dbg(ERROR, "Invalid module parameters.\n");
+ return -EINVAL;
+ } while (0);
+
+ return brcmf_sdio_register();
}

-static void
-brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar)
+void brcmf_bus_unregister(void)
{
- brcmf_sdbrcm_sdunlock(bus);
- wait_event_interruptible_timeout(bus->ctrl_wait,
- (*lockvar == false), HZ * 2);
- brcmf_sdbrcm_sdlock(bus);
- return;
+ brcmf_dbg(TRACE, "Enter\n");
+
+ brcmf_sdio_unregister();
}

-static void
-brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus)
+struct device *brcmf_bus_get_device(struct brcmf_bus *bus)
{
- if (waitqueue_active(&bus->ctrl_wait))
- wake_up_interruptible(&bus->ctrl_wait);
- return;
+ return &bus->sdiodev->func[2]->dev;
}

-static int
-brcmf_sdbrcm_watchdog_thread(void *data)
+int brcmf_bus_devreset(struct brcmf_pub *drvr, u8 flag)
{
- struct brcmf_bus *bus = (struct brcmf_bus *)data;
+ int bcmerror = 0;
+ struct brcmf_bus *bus;

- /* This thread doesn't need any user-level access,
- * so get rid of all our resources
- */
- if (brcmf_watchdog_prio > 0) {
- struct sched_param param;
- param.sched_priority = (brcmf_watchdog_prio < MAX_RT_PRIO) ?
- brcmf_watchdog_prio : (MAX_RT_PRIO - 1);
- sched_setscheduler(current, SCHED_FIFO, &param);
- }
+ bus = drvr->bus;

- allow_signal(SIGTERM);
- /* Run until signal received */
- while (1) {
- if (kthread_should_stop())
- break;
- if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
- if (bus->drvr->dongle_reset == false)
- brcmf_sdbrcm_bus_watchdog(bus->drvr);
- /* Count the tick for reference */
- bus->drvr->tickcnt++;
- } else
- break;
- }
- return 0;
-}
+ if (flag == true) {
+ brcmf_sdbrcm_wd_timer(bus, 0);
+ if (!bus->drvr->dongle_reset) {
+ /* Expect app to have torn down any
+ connection before calling */
+ /* Stop the bus, disable F2 */
+ brcmf_sdbrcm_bus_stop(bus, false);

-static void
-brcmf_sdbrcm_watchdog(unsigned long data)
-{
- struct brcmf_bus *bus = (struct brcmf_bus *)data;
+ /* Clean tx/rx buffer pointers,
+ detach from the dongle */
+ brcmf_sdbrcm_release_dongle(bus);

- if (brcmf_watchdog_prio >= 0) {
- if (bus->watchdog_tsk)
- complete(&bus->watchdog_wait);
- else
- return;
+ bus->drvr->dongle_reset = true;
+ bus->drvr->up = false;
+
+ brcmf_dbg(TRACE, "WLAN OFF DONE\n");
+ /* App can now remove power from device */
+ } else
+ bcmerror = -EIO;
} else {
- brcmf_sdbrcm_bus_watchdog(bus->drvr);
+ /* App must have restored power to device before calling */

- /* Count the tick for reference */
- bus->drvr->tickcnt++;
- }
+ brcmf_dbg(TRACE, " == WLAN ON ==\n");

- /* Reschedule the watchdog */
- if (bus->wd_timer_valid)
- mod_timer(&bus->timer, jiffies + brcmf_watchdog_ms * HZ / 1000);
+ if (bus->drvr->dongle_reset) {
+ /* Turn on WLAN */
+
+ /* Attempt to re-attach & download */
+ if (brcmf_sdbrcm_probe_attach(bus, SI_ENUM_BASE)) {
+ /* Attempt to download binary to the dongle */
+ if (brcmf_sdbrcm_probe_init(bus)) {
+ /* Re-init bus, enable F2 transfer */
+ brcmf_sdbrcm_bus_init(bus->drvr, false);
+
+ bus->drvr->dongle_reset = false;
+ bus->drvr->up = true;
+
+ brcmf_dbg(TRACE, "WLAN ON DONE\n");
+ } else
+ bcmerror = -EIO;
+ } else
+ bcmerror = -EIO;
+ } else {
+ bcmerror = -EISCONN;
+ brcmf_dbg(ERROR, "Set DEVRESET=false invoked when device is on\n");
+ bcmerror = -EIO;
+ }
+ brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
+ }
+ return bcmerror;
}

void
@@ -5074,118 +5135,3 @@ brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
bus->save_ms = wdtick;
}
}
-
-static int brcmf_sdbrcm_dpc_thread(void *data)
-{
- struct brcmf_bus *bus = (struct brcmf_bus *) data;
-
- /* This thread doesn't need any user-level access,
- * so get rid of all our resources
- */
- if (brcmf_dpc_prio > 0) {
- struct sched_param param;
- param.sched_priority = (brcmf_dpc_prio < MAX_RT_PRIO) ?
- brcmf_dpc_prio : (MAX_RT_PRIO - 1);
- sched_setscheduler(current, SCHED_FIFO, &param);
- }
-
- allow_signal(SIGTERM);
- /* Run until signal received */
- while (1) {
- if (kthread_should_stop())
- break;
- 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 (brcmf_sdbrcm_dpc(bus))
- complete(&bus->dpc_wait);
- } else {
- brcmf_sdbrcm_bus_stop(bus, true);
- }
- } else
- break;
- }
- return 0;
-}
-
-static void brcmf_sdbrcm_dpc_tasklet(unsigned long data)
-{
- struct brcmf_bus *bus = (struct brcmf_bus *) data;
-
- /* Call bus dpc unless it indicated down (then clean stop) */
- if (bus->drvr->busstate != BRCMF_BUS_DOWN) {
- if (brcmf_sdbrcm_dpc(bus))
- tasklet_schedule(&bus->tasklet);
- } else
- brcmf_sdbrcm_bus_stop(bus, true);
-}
-
-static void brcmf_sdbrcm_sched_dpc(struct brcmf_bus *bus)
-{
- if (bus->dpc_tsk) {
- complete(&bus->dpc_wait);
- return;
- }
-
- tasklet_schedule(&bus->tasklet);
-}
-
-static void brcmf_sdbrcm_sdlock(struct brcmf_bus *bus)
-{
- if (bus->threads_only)
- down(&bus->sdsem);
- else
- spin_lock_bh(&bus->sdlock);
-}
-
-static void brcmf_sdbrcm_sdunlock(struct brcmf_bus *bus)
-{
- if (bus->threads_only)
- up(&bus->sdsem);
- else
- spin_unlock_bh(&bus->sdlock);
-}
-
-static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus)
-{
- if (bus->firmware->size < bus->fw_ptr + len)
- len = bus->firmware->size - bus->fw_ptr;
-
- memcpy(buf, &bus->firmware->data[bus->fw_ptr], len);
- bus->fw_ptr += len;
- return len;
-}
-
-MODULE_FIRMWARE(BCM4329_FW_NAME);
-MODULE_FIRMWARE(BCM4329_NV_NAME);
-
-static int brcmf_sdbrcm_ioctl_resp_wait(struct brcmf_bus *bus, uint *condition,
- bool *pending)
-{
- DECLARE_WAITQUEUE(wait, current);
- int timeout = msecs_to_jiffies(brcmf_ioctl_timeout_msec);
-
- /* Wait until control frame is available */
- add_wait_queue(&bus->ioctl_resp_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- while (!(*condition) && (!signal_pending(current) && timeout))
- timeout = schedule_timeout(timeout);
-
- if (signal_pending(current))
- *pending = true;
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&bus->ioctl_resp_wait, &wait);
-
- return timeout;
-}
-
-static int brcmf_sdbrcm_ioctl_resp_wake(struct brcmf_bus *bus)
-{
- if (waitqueue_active(&bus->ioctl_resp_wait))
- wake_up_interruptible(&bus->ioctl_resp_wait);
-
- return 0;
-}
--
1.7.4.1



2011-09-13 07:50:18

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 07/17] staging: brcm80211: removed function brcms_c_wme_initparams_sta()

since its variable assignment can be done in a more straightforward
manner.

Reported-by: Johannes Berg <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/main.c | 57 +++++++++--------------------
drivers/staging/brcm80211/brcmsmac/main.h | 19 ----------
2 files changed, 17 insertions(+), 59 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/main.c b/drivers/staging/brcm80211/brcmsmac/main.c
index 9921af2..7067a02 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.c
+++ b/drivers/staging/brcm80211/brcmsmac/main.c
@@ -431,6 +431,12 @@ struct brcms_b_state {
u32 preamble_ovr; /* preamble override */
};

+struct edcf_acparam {
+ u8 ACI;
+ u8 ECW;
+ u16 TXOP;
+} __packed;
+
const u8 prio2fifo[NUMPRIO] = {
TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */
TX_AC_BK_FIFO, /* 1 BK AC_BK Background */
@@ -4124,34 +4130,6 @@ static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val)
}
}

-/*
- * Initialize a WME Parameter Info Element with default
- * STA parameters from WMM Spec, Table 12
- */
-void
-brcms_c_wme_initparams_sta(struct brcms_c_info *wlc, struct wme_param_ie *pe)
-{
- static const struct wme_param_ie stadef = {
- WME_OUI,
- WME_TYPE,
- WME_SUBTYPE_PARAM_IE,
- WME_VER,
- 0,
- 0,
- {
- {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA,
- cpu_to_le16(EDCF_AC_BE_TXOP_STA)},
- {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA,
- cpu_to_le16(EDCF_AC_BK_TXOP_STA)},
- {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA,
- cpu_to_le16(EDCF_AC_VI_TXOP_STA)},
- {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA,
- cpu_to_le16(EDCF_AC_VO_TXOP_STA)}
- }
- };
- memcpy(pe, &stadef, sizeof(*pe));
-}
-
void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
const struct ieee80211_tx_queue_params *params,
bool suspend)
@@ -4222,18 +4200,19 @@ void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
{
u16 aci;
int i_ac;
- struct edcf_acparam *edcf_acp;
-
struct ieee80211_tx_queue_params txq_pars;
struct ieee80211_tx_queue_params *params = &txq_pars;
-
- /*
- * AP uses AC params from wme_param_ie_ap.
- * AP advertises AC params from wme_param_ie.
- * STA uses AC params from wme_param_ie.
- */
-
- edcf_acp = (struct edcf_acparam *) &wlc->wme_param_ie.acparam[0];
+ static struct edcf_acparam default_edcf_acparams[] = {
+ {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA,
+ cpu_to_le16(EDCF_AC_BE_TXOP_STA)},
+ {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA,
+ cpu_to_le16(EDCF_AC_BK_TXOP_STA)},
+ {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA,
+ cpu_to_le16(EDCF_AC_VI_TXOP_STA)},
+ {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA,
+ cpu_to_le16(EDCF_AC_VO_TXOP_STA)}
+ }; /* ucode needs these parameters during its initialization */
+ struct edcf_acparam *edcf_acp = &default_edcf_acparams[0];

for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) {
/* find out which ac this set of params applies to */
@@ -5294,8 +5273,6 @@ brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
wlc->cfg->_idx = 0;
wlc->cfg->wlc = wlc;

- brcms_c_wme_initparams_sta(wlc, &wlc->wme_param_ie);
-
wlc->mimoft = FT_HT;
wlc->ht_cap.cap_info = HT_CAP;

diff --git a/drivers/staging/brcm80211/brcmsmac/main.h b/drivers/staging/brcm80211/brcmsmac/main.h
index 0462250..aa0bf03 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.h
+++ b/drivers/staging/brcm80211/brcmsmac/main.h
@@ -298,22 +298,6 @@ struct modulecb {

};

-struct edcf_acparam {
- u8 ACI;
- u8 ECW;
- u16 TXOP;
-} __packed;
-
-struct wme_param_ie {
- u8 oui[3];
- u8 type;
- u8 subtype;
- u8 version;
- u8 qosinfo;
- u8 rsvd;
- struct edcf_acparam acparam[AC_COUNT];
-} __packed;
-
struct brcms_hw_band {
int bandtype; /* BRCM_BAND_2G, BRCM_BAND_5G */
uint bandunit; /* bandstate[] index */
@@ -463,8 +447,6 @@ struct brcms_txq_info {
* WDarmed: watchdog timer is armed.
* WDlast: last time wlc_watchdog() was called.
* edcf_txop[AC_COUNT]: current txop for each ac.
- * wme_param_ie: on STA contains parameters in use locally, and on AP
- * contains parameters advertised
* wme_retries: per-AC retry limits.
* tx_prec_map: Precedence map based on HW FIFO space.
* fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME.
@@ -578,7 +560,6 @@ struct brcms_c_info {
/* WME */
u16 edcf_txop[AC_COUNT];

- struct wme_param_ie wme_param_ie;
u16 wme_retries[AC_COUNT];
u16 tx_prec_map;
u16 fifo2prec_map[NFIFO];
--
1.7.4.1



2011-09-13 07:50:18

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 12/17] staging: brcm80211: macro cleanup in softmac rate.h

Substituted/moved/deleted macro's.

Reported-by: Johannes Berg <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/ampdu.c | 25 ++--
drivers/staging/brcm80211/brcmsmac/main.c | 173 +++++++++++++-------------
drivers/staging/brcm80211/brcmsmac/rate.c | 16 ++-
drivers/staging/brcm80211/brcmsmac/rate.h | 188 +++++++++++++++++-----------
drivers/staging/brcm80211/brcmsmac/stf.c | 2 +-
5 files changed, 220 insertions(+), 184 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/ampdu.c b/drivers/staging/brcm80211/brcmsmac/ampdu.c
index 76f4871..47dc27a 100644
--- a/drivers/staging/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/staging/brcm80211/brcmsmac/ampdu.c
@@ -158,16 +158,16 @@ static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
/* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
/* 20MHz, No SGI */
- rate = MCS_RATE(mcs, false, false);
+ rate = mcs_2_rate(mcs, false, false);
ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
/* 40 MHz, No SGI */
- rate = MCS_RATE(mcs, true, false);
+ rate = mcs_2_rate(mcs, true, false);
ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
/* 20MHz, SGI */
- rate = MCS_RATE(mcs, false, true);
+ rate = mcs_2_rate(mcs, false, true);
ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
/* 40 MHz, SGI */
- rate = MCS_RATE(mcs, true, true);
+ rate = mcs_2_rate(mcs, true, true);
ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
}
}
@@ -330,7 +330,7 @@ static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
/* note : we divide/multiply by 100 to avoid integer overflows */
max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS],
AMPDU_NUM_MPDU_LEGACY);
- phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
+ phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
dma_rate =
(((phy_rate / 100) *
(max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
@@ -341,7 +341,7 @@ static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
dma_rate = dma_rate >> 7;
for (i = 0; i < FFPLD_MAX_MCS; i++) {
/* shifting to keep it within integer range */
- phy_rate = MCS_RATE(i, true, false) >> 7;
+ phy_rate = mcs_2_rate(i, true, false) >> 7;
if (phy_rate > dma_rate) {
tmp = ((fifo->ampdu_pld_size * phy_rate) /
((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
@@ -360,7 +360,7 @@ static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
{
struct ampdu_info *ampdu = wlc->ampdu;
- u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
+ u32 phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
u32 txunfl_ratio;
u8 max_mpdu;
u32 current_ampdu_cnt = 0;
@@ -678,7 +678,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,

}
is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
- sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
+ sgi = plcp3_issgi(plcp3) ? 1 : 0;
mcs = plcp0 & ~MIMO_PLCP_40MHZ;
max_ampdu_bytes =
min(scb_ampdu->max_rx_ampdu_bytes,
@@ -697,9 +697,8 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);

if (fbr_iscck) /* CCK */
- rspec_fallback =
- CCK_RSPEC(CCK_PHY2MAC_RATE
- (txh->FragPLCPFallback[0]));
+ rspec_fallback = cck_rspec(cck_phy2mac_rate
+ (txh->FragPLCPFallback[0]));
else { /* MIMO */
rspec_fallback = RSPEC_MIMORATE;
rspec_fallback |=
@@ -722,7 +721,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,

/* if (first mpdu for host agg) */
/* test whether to add more */
- if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
+ if ((mcs_2_rate(mcs, true, false) >= f->dmaxferrate) &&
(count == f->mcs2ampdu_table[mcs])) {
BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping"
" ampdu at %d for mcs %d\n",
@@ -816,7 +815,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
}

/* set the preload length */
- if (MCS_RATE(mcs, true, false) >= f->dmaxferrate) {
+ if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
dma_len = min(dma_len, f->ampdu_pld_size);
txh->PreloadSize = cpu_to_le16(dma_len);
} else
diff --git a/drivers/staging/brcm80211/brcmsmac/main.c b/drivers/staging/brcm80211/brcmsmac/main.c
index ec7de38..2c9ac6d 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.c
+++ b/drivers/staging/brcm80211/brcmsmac/main.c
@@ -170,7 +170,7 @@
/* Find basic rate for a given rate */
static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
{
- if (IS_MCS(rspec))
+ if (is_mcs_rate(rspec))
return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
.leg_ofdm];
return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
@@ -178,9 +178,9 @@ static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)

static u16 frametype(u32 rspec, u8 mimoframe)
{
- if (IS_MCS(rspec))
+ if (is_mcs_rate(rspec))
return mimoframe;
- return IS_CCK(rspec) ? FT_CCK : FT_OFDM;
+ return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
}

/* rfdisable delay timer 500 ms, runs of ALP clock */
@@ -4001,7 +4001,7 @@ u32 brcms_c_lowest_basic_rspec(struct brcms_c_info *wlc,
* pick siso/cdd as default for OFDM (note no basic
* rate MCSs are supported yet)
*/
- if (IS_OFDM(lowest_basic_rspec))
+ if (is_ofdm_rate(lowest_basic_rspec))
lowest_basic_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);

return lowest_basic_rspec;
@@ -6560,7 +6560,7 @@ u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
u8 phy_rate, index;

/* get the phy specific rate encoding for the PLCP SIGNAL field */
- if (IS_OFDM(rate))
+ if (is_ofdm_rate(rate))
table_ptr = M_RT_DIRMAP_A;
else
table_ptr = M_RT_DIRMAP_B;
@@ -6772,27 +6772,26 @@ brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,
u8 preamble_type, uint dur)
{
uint nsyms, mac_len, Ndps, kNdps;
- uint rate = RSPEC2RATE(ratespec);
+ uint rate = rspec2rate(ratespec);

BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n",
wlc->pub->unit, ratespec, preamble_type, dur);

- if (IS_MCS(ratespec)) {
+ if (is_mcs_rate(ratespec)) {
uint mcs = ratespec & RSPEC_RATE_MASK;
- int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec);
+ int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
/* payload calculation matches that of regular ofdm */
if (wlc->band->bandtype == BRCM_BAND_2G)
dur -= DOT11_OFDM_SIGNAL_EXTENSION;
/* kNdbps = kbps * 4 */
- kNdps =
- MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
- RSPEC_ISSGI(ratespec)) * 4;
+ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+ rspec_issgi(ratespec)) * 4;
nsyms = dur / APHY_SYMBOL_TIME;
mac_len =
((nsyms * kNdps) -
((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;
- } else if (IS_OFDM(ratespec)) {
+ } else if (is_ofdm_rate(ratespec)) {
dur -= APHY_PREAMBLE_TIME;
dur -= APHY_SIGNAL_TIME;
/* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
@@ -6872,14 +6871,14 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
goto done;
}
}
- } else if (IS_OFDM(rate)) {
+ } else if (is_ofdm_rate(rate)) {
if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n",
wlc->pub->unit, __func__);
bcmerror = -EINVAL;
goto done;
}
- } else if (IS_CCK(rate)) {
+ } else if (is_cck_rate(rate)) {
if ((cur_band->bandtype != BRCM_BAND_2G)
|| (stf != PHY_TXC1_MODE_SISO)) {
wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n",
@@ -7074,7 +7073,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
* determine and validate primary rate
* and fallback rates
*/
- if (!RSPEC_ACTIVE(rspec[k])) {
+ if (!rspec_active(rspec[k])) {
rspec[k] = BRCM_RATE_1M;
} else {
if (!is_multicast_ether_addr(h->addr1)) {
@@ -7093,15 +7092,15 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
* apply siso/cdd to single stream mcs's or ofdm
* if rspec is auto selected
*/
- if (((IS_MCS(rspec[k]) &&
- IS_SINGLE_STREAM(rspec[k] & RSPEC_RATE_MASK)) ||
- IS_OFDM(rspec[k]))
+ if (((is_mcs_rate(rspec[k]) &&
+ is_single_stream(rspec[k] & RSPEC_RATE_MASK)) ||
+ is_ofdm_rate(rspec[k]))
&& ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)
|| !(rspec[k] & RSPEC_OVERRIDE))) {
rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);

/* For SISO MCS use STBC if possible */
- if (IS_MCS(rspec[k])
+ if (is_mcs_rate(rspec[k])
&& BRCMS_STF_SS_STBC_TX(wlc, scb)) {
u8 stc;

@@ -7126,7 +7125,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
wlc->band->pi))
? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;

- if (IS_MCS(rspec[k])) {
+ if (is_mcs_rate(rspec[k])) {
/* mcs 32 must be 40b/w DUP */
if ((rspec[k] & RSPEC_RATE_MASK)
== 32) {
@@ -7138,7 +7137,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
/* else check if dst is using 40 Mhz */
else if (scb->flags & SCB_IS40)
mimo_txbw = PHY_TXC1_BW_40MHZ;
- } else if (IS_OFDM(rspec[k])) {
+ } else if (is_ofdm_rate(rspec[k])) {
if (wlc->ofdm_40txbw != AUTO)
mimo_txbw = wlc->ofdm_40txbw;
} else if (wlc->cck_40txbw != AUTO) {
@@ -7159,7 +7158,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,

/* Set channel width */
rspec[k] &= ~RSPEC_BW_MASK;
- if ((k == 0) || ((k > 0) && IS_MCS(rspec[k])))
+ if ((k == 0) || ((k > 0) && is_mcs_rate(rspec[k])))
rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);
else
rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
@@ -7172,13 +7171,13 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
mimo_preamble_type = BRCMS_GF_PREAMBLE;

if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
- && (!IS_MCS(rspec[k]))) {
+ && (!is_mcs_rate(rspec[k]))) {
wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_"
- "RC_MCS != IS_MCS(rspec)\n",
+ "RC_MCS != is_mcs_rate(rspec)\n",
wlc->pub->unit, __func__);
}

- if (IS_MCS(rspec[k])) {
+ if (is_mcs_rate(rspec[k])) {
preamble_type[k] = mimo_preamble_type;

/*
@@ -7186,13 +7185,13 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
* for single stream
*/
if ((rspec[k] & RSPEC_SHORT_GI)
- && IS_SINGLE_STREAM(rspec[k] &
+ && is_single_stream(rspec[k] &
RSPEC_RATE_MASK))
preamble_type[k] = BRCMS_MM_PREAMBLE;
}

/* should be better conditionalized */
- if (!IS_MCS(rspec[0])
+ if (!is_mcs_rate(rspec[0])
&& (tx_info->control.rates[0].
flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
preamble_type[k] = BRCMS_SHORT_PREAMBLE;
@@ -7204,7 +7203,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);

/* for nphy, stf of ofdm frames must follow policies */
- if (BRCMS_ISNPHY(wlc->band) && IS_OFDM(rspec[k])) {
+ if (BRCMS_ISNPHY(wlc->band) && is_ofdm_rate(rspec[k])) {
rspec[k] &= ~RSPEC_STF_MASK;
rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;
}
@@ -7229,13 +7228,13 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
plcp_fallback, sizeof(txh->FragPLCPFallback));

/* Length field now put in CCK FBR CRC field */
- if (IS_CCK(rspec[1])) {
+ if (is_cck_rate(rspec[1])) {
txh->FragPLCPFallback[4] = phylen & 0xff;
txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;
}

/* MIMO-RATE: need validation ?? */
- mainrates = IS_OFDM(rspec[0]) ?
+ mainrates = is_ofdm_rate(rspec[0]) ?
D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) :
plcp[0];

@@ -7292,7 +7291,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
/* Set fallback rate preamble type */
if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) ||
(preamble_type[1] == BRCMS_GF_PREAMBLE)) {
- if (RSPEC2RATE(rspec[1]) != BRCM_RATE_1M)
+ if (rspec2rate(rspec[1]) != BRCM_RATE_1M)
mch |= TXC_PREAMBLE_DATA_FB_SHORT;
}

@@ -7336,15 +7335,15 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
mimo_ctlchbw);
}

- if (!IS_OFDM(rts_rspec[0]) &&
- !((RSPEC2RATE(rts_rspec[0]) == BRCM_RATE_1M) ||
+ if (!is_ofdm_rate(rts_rspec[0]) &&
+ !((rspec2rate(rts_rspec[0]) == BRCM_RATE_1M) ||
(wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE;
mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;
}

- if (!IS_OFDM(rts_rspec[1]) &&
- !((RSPEC2RATE(rts_rspec[1]) == BRCM_RATE_1M) ||
+ if (!is_ofdm_rate(rts_rspec[1]) &&
+ !((rspec2rate(rts_rspec[1]) == BRCM_RATE_1M) ||
(wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE;
mch |= TXC_PREAMBLE_RTS_FB_SHORT;
@@ -7403,7 +7402,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
* low 8 bits: main frag rate/mcs,
* high 8 bits: rts/cts rate/mcs
*/
- mainrates |= (IS_OFDM(rts_rspec[0]) ?
+ mainrates |= (is_ofdm_rate(rts_rspec[0]) ?
D11A_PHY_HDR_GRATE(
(struct ofdm_phy_hdr *) rts_plcp) :
rts_plcp[0]) << 8;
@@ -7418,7 +7417,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,

#ifdef SUPPORT_40MHZ
/* add null delimiter count */
- if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && IS_MCS(rspec))
+ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && is_mcs_rate(rspec))
txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =
brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);

@@ -7448,7 +7447,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
phyctl = frametype(rspec[0], wlc->mimoft);
if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) ||
(preamble_type[0] == BRCMS_GF_PREAMBLE)) {
- if (RSPEC2RATE(rspec[0]) != BRCM_RATE_1M)
+ if (rspec2rate(rspec[0]) != BRCM_RATE_1M)
phyctl |= PHY_TXC_SHORT_HDR;
}

@@ -7477,14 +7476,14 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
* is going to be set, fill in non-zero MModeLen and/or
* MModeFbrLen it will be unnecessary if they are separated
*/
- if (IS_MCS(rspec[0]) &&
+ if (is_mcs_rate(rspec[0]) &&
(preamble_type[0] == BRCMS_MM_PREAMBLE)) {
u16 mmodelen =
brcms_c_calc_lsig_len(wlc, rspec[0], phylen);
txh->MModeLen = cpu_to_le16(mmodelen);
}

- if (IS_MCS(rspec[1]) &&
+ if (is_mcs_rate(rspec[1]) &&
(preamble_type[1] == BRCMS_MM_PREAMBLE)) {
u16 mmodefbrlen =
brcms_c_calc_lsig_len(wlc, rspec[1], phylen);
@@ -7570,7 +7569,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
wiphy_err(wlc->wiphy, "wl%d: %s txop invalid "
"for rate %d\n",
wlc->pub->unit, fifo_names[queue],
- RSPEC2RATE(rspec[0]));
+ rspec2rate(rspec[0]));
}

if (dur > wlc->edcf_txop[ac])
@@ -7772,10 +7771,10 @@ static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp)
{
u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);
plcp[0] = mcs;
- if (RSPEC_IS40MHZ(rspec) || (mcs == 32))
+ if (rspec_is40mhz(rspec) || (mcs == 32))
plcp[0] |= MIMO_PLCP_40MHZ;
BRCMS_SET_MIMO_PLCP_LEN(plcp, length);
- plcp[3] = RSPEC_MIMOPLCP3(rspec); /* rspec already holds this byte */
+ plcp[3] = rspec_mimoplcp3(rspec); /* rspec already holds this byte */
plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */
plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */
plcp[5] = 0;
@@ -7787,7 +7786,7 @@ brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp)
{
u8 rate_signal;
u32 tmp = 0;
- int rate = RSPEC2RATE(rspec);
+ int rate = rspec2rate(rspec);

/*
* encode rate per 802.11a-1999 sec 17.3.4.1, with lsb
@@ -7809,7 +7808,7 @@ brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp)
static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec,
uint length, u8 *plcp)
{
- int rate = RSPEC2RATE(rspec);
+ int rate = rspec2rate(rspec);

brcms_c_cck_plcp_set(wlc, rate, length, plcp);
}
@@ -7818,9 +7817,9 @@ void
brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,
uint length, u8 *plcp)
{
- if (IS_MCS(rspec))
+ if (is_mcs_rate(rspec))
brcms_c_compute_mimo_plcp(rspec, length, plcp);
- else if (IS_OFDM(rspec))
+ else if (is_ofdm_rate(rspec))
brcms_c_compute_ofdm_plcp(rspec, length, plcp);
else
brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
@@ -7881,7 +7880,7 @@ u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
if (BRCMS_ISLCNPHY(wlc->band)) {
bw = PHY_TXC1_BW_20MHZ;
} else {
- bw = RSPEC_GET_BW(rspec);
+ bw = rspec_get_bw(rspec);
/* 10Mhz is not supported yet */
if (bw < PHY_TXC1_BW_20MHZ) {
wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is "
@@ -7890,14 +7889,14 @@ u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
}
}

- if (IS_MCS(rspec)) {
+ if (is_mcs_rate(rspec)) {
uint mcs = rspec & RSPEC_RATE_MASK;

- /* bw, stf, coding-type is part of RSPEC_PHYTXBYTE2 returns */
- phyctl1 = RSPEC_PHYTXBYTE2(rspec);
+ /* bw, stf, coding-type is part of rspec_phytxbyte2 returns */
+ phyctl1 = rspec_phytxbyte2(rspec);
/* set the upper byte of phyctl1 */
phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8);
- } else if (IS_CCK(rspec) && !BRCMS_ISLCNPHY(wlc->band)
+ } else if (is_cck_rate(rspec) && !BRCMS_ISLCNPHY(wlc->band)
&& !BRCMS_ISSSLPNPHY(wlc->band)) {
/*
* In CCK mode LPPHY overloads OFDM Modulation bits with CCK
@@ -7905,11 +7904,11 @@ u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
* this format
*/
/* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
- phyctl1 = (bw | (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
+ phyctl1 = (bw | (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
} else { /* legacy OFDM/CCK */
s16 phycfg;
/* get the phyctl byte from rate phycfg table */
- phycfg = brcms_c_rate_legacy_phyctl(RSPEC2RATE(rspec));
+ phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec));
if (phycfg == -1) {
wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong "
"legacy OFDM/CCK rate\n");
@@ -7918,7 +7917,7 @@ u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
/* set the upper byte of phyctl1 */
phyctl1 =
(bw | (phycfg << 8) |
- (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
+ (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
}
return phyctl1;
}
@@ -7932,7 +7931,7 @@ brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
if (use_rspec)
/* use frame rate as rts rate */
rts_rspec = rspec;
- else if (wlc->band->gmode && wlc->protection->_g && !IS_CCK(rspec))
+ else if (wlc->band->gmode && wlc->protection->_g && !is_cck_rate(rspec))
/* Use 11Mbps as the g protection RTS target rate and fallback.
* Use the brcms_basic_rate() lookup to find the best basic rate
* under the target in case 11 Mbps is not Basic.
@@ -7956,13 +7955,13 @@ brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
* if rspec/rspec_fallback is 40MHz, then send RTS on both
* 20MHz channel (DUP), otherwise send RTS on control channel
*/
- if (RSPEC_IS40MHZ(rspec) && !IS_CCK(rts_rspec))
+ if (rspec_is40mhz(rspec) && !is_cck_rate(rts_rspec))
rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);
else
rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);

/* pick siso/cdd as default for ofdm */
- if (IS_OFDM(rts_rspec)) {
+ if (is_ofdm_rate(rts_rspec)) {
rts_rspec &= ~RSPEC_STF_MASK;
rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
}
@@ -8269,13 +8268,13 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
plcp = p->data;

rspec = brcms_c_compute_rspec(rxh, plcp);
- if (IS_MCS(rspec)) {
+ if (is_mcs_rate(rspec)) {
rx_status->rate_idx = rspec & RSPEC_RATE_MASK;
rx_status->flag |= RX_FLAG_HT;
- if (RSPEC_IS40MHZ(rspec))
+ if (rspec_is40mhz(rspec))
rx_status->flag |= RX_FLAG_40MHZ;
} else {
- switch (RSPEC2RATE(rspec)) {
+ switch (rspec2rate(rspec)) {
case BRCM_RATE_1M:
rx_status->rate_idx = 0;
break;
@@ -8326,10 +8325,10 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,

/* Determine short preamble and rate_idx */
preamble = 0;
- if (IS_CCK(rspec)) {
+ if (is_cck_rate(rspec)) {
if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)
rx_status->flag |= RX_FLAG_SHORTPRE;
- } else if (IS_OFDM(rspec)) {
+ } else if (is_ofdm_rate(rspec)) {
rx_status->flag |= RX_FLAG_SHORTPRE;
} else {
wiphy_err(wlc->wiphy, "%s: Unknown modulation\n",
@@ -8337,7 +8336,7 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
}
}

- if (PLCP3_ISSGI(plcp[3]))
+ if (plcp3_issgi(plcp[3]))
rx_status->flag |= RX_FLAG_SHORT_GI;

if (rxh->RxStatus1 & RXS_DECERR) {
@@ -8479,23 +8478,22 @@ brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
uint nsyms, len = 0, kNdps;

BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n",
- wlc->pub->unit, RSPEC2RATE(ratespec), mac_len);
+ wlc->pub->unit, rspec2rate(ratespec), mac_len);

- if (IS_MCS(ratespec)) {
+ if (is_mcs_rate(ratespec)) {
uint mcs = ratespec & RSPEC_RATE_MASK;
- /* MCS_TXS(mcs) returns num tx streams - 1 */
- int tot_streams = (MCS_TXS(mcs) + 1) + RSPEC_STC(ratespec);
+ int tot_streams = (mcs_2_txstreams(mcs) + 1) +
+ rspec_stc(ratespec);

/*
* the payload duration calculation matches that
* of regular ofdm
*/
/* 1000Ndbps = kbps * 4 */
- kNdps =
- MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
- RSPEC_ISSGI(ratespec)) * 4;
+ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+ rspec_issgi(ratespec)) * 4;

- if (RSPEC_STC(ratespec) == 0)
+ if (rspec_stc(ratespec) == 0)
nsyms =
CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
APHY_TAIL_NBITS) * 1000, kNdps);
@@ -8527,7 +8525,7 @@ brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
u8 preamble_type, uint mac_len)
{
uint nsyms, dur = 0, Ndps, kNdps;
- uint rate = RSPEC2RATE(ratespec);
+ uint rate = rspec2rate(ratespec);

if (rate == 0) {
wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n",
@@ -8538,19 +8536,18 @@ brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n",
wlc->pub->unit, ratespec, preamble_type, mac_len);

- if (IS_MCS(ratespec)) {
+ if (is_mcs_rate(ratespec)) {
uint mcs = ratespec & RSPEC_RATE_MASK;
- int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec);
+ int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);

dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
if (preamble_type == BRCMS_MM_PREAMBLE)
dur += PREN_MM_EXT;
/* 1000Ndbps = kbps * 4 */
- kNdps =
- MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
- RSPEC_ISSGI(ratespec)) * 4;
+ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+ rspec_issgi(ratespec)) * 4;

- if (RSPEC_STC(ratespec) == 0)
+ if (rspec_stc(ratespec) == 0)
nsyms =
CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
APHY_TAIL_NBITS) * 1000, kNdps);
@@ -8564,7 +8561,7 @@ brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
dur += APHY_SYMBOL_TIME * nsyms;
if (wlc->band->bandtype == BRCM_BAND_2G)
dur += DOT11_OFDM_SIGNAL_EXTENSION;
- } else if (IS_OFDM(rate)) {
+ } else if (is_ofdm_rate(rate)) {
dur = APHY_PREAMBLE_TIME;
dur += APHY_SIGNAL_TIME;
/* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
@@ -8649,7 +8646,7 @@ void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
* Keep track of the best basic rate so far by
* modulation type.
*/
- if (IS_OFDM(rate))
+ if (is_ofdm_rate(rate))
ofdm_basic = rate;
else
cck_basic = rate;
@@ -8662,12 +8659,12 @@ void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
* the hole in the table
*/

- br[rate] = IS_OFDM(rate) ? ofdm_basic : cck_basic;
+ br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic;

if (br[rate] != 0)
continue;

- if (IS_OFDM(rate)) {
+ if (is_ofdm_rate(rate)) {
/*
* In 11g and 11a, the OFDM mandatory rates
* are 6, 12, and 24 Mbps
@@ -8696,10 +8693,10 @@ static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
u16 basic_ptr;

/* Shared memory address for the table we are reading */
- dir_table = IS_OFDM(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;
+ dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;

/* Shared memory address for the table we are writing */
- basic_table = IS_OFDM(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;
+ basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;

/*
* for a given rate, the LS-nibble of the PLCP SIGNAL field is
@@ -8788,15 +8785,15 @@ bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,
return false;

/* check if this is a mimo rate */
- if (IS_MCS(rspec)) {
- if (!VALID_MCS((rspec & RSPEC_RATE_MASK)))
+ if (is_mcs_rate(rspec)) {
+ if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE)
goto error;

return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));
}

for (i = 0; i < hw_rateset->count; i++)
- if (hw_rateset->rates[i] == RSPEC2RATE(rspec))
+ if (hw_rateset->rates[i] == rspec2rate(rspec))
return true;
error:
if (verbose)
diff --git a/drivers/staging/brcm80211/brcmsmac/rate.c b/drivers/staging/brcm80211/brcmsmac/rate.c
index 1241dc9..0a0c0ad 100644
--- a/drivers/staging/brcm80211/brcmsmac/rate.c
+++ b/drivers/staging/brcm80211/brcmsmac/rate.c
@@ -353,12 +353,12 @@ u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp)
switch (rxh->PhyRxStatus_0 & PRXS0_FT_MASK) {
case PRXS0_CCK:
rspec =
- CCK_PHY2MAC_RATE(
+ cck_phy2mac_rate(
((struct cck_phy_hdr *) plcp)->signal);
break;
case PRXS0_OFDM:
rspec =
- OFDM_PHY2MAC_RATE(
+ ofdm_phy2mac_rate(
((struct ofdm_phy_hdr *) plcp)->rlpt[0]);
break;
case PRXS0_PREN:
@@ -375,14 +375,14 @@ u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp)
/* not supported, error condition */
break;
}
- if (PLCP3_ISSGI(plcp[3]))
+ if (plcp3_issgi(plcp[3]))
rspec |= RSPEC_SHORT_GI;
} else
if ((phy_type == PHY_TYPE_A) || (rxh->PhyRxStatus_0 & PRXS0_OFDM))
- rspec = OFDM_PHY2MAC_RATE(
+ rspec = ofdm_phy2mac_rate(
((struct ofdm_phy_hdr *) plcp)->rlpt[0]);
else
- rspec = CCK_PHY2MAC_RATE(
+ rspec = cck_phy2mac_rate(
((struct cck_phy_hdr *) plcp)->signal);

return rspec;
@@ -417,9 +417,11 @@ brcms_c_rateset_filter(struct brcms_c_rateset *src, struct brcms_c_rateset *dst,
r = src->rates[i];
if (basic_only && !(r & BRCMS_RATE_FLAG))
continue;
- if (rates == BRCMS_RATES_CCK && IS_OFDM((r & BRCMS_RATE_MASK)))
+ if (rates == BRCMS_RATES_CCK &&
+ is_ofdm_rate((r & BRCMS_RATE_MASK)))
continue;
- if (rates == BRCMS_RATES_OFDM && IS_CCK((r & BRCMS_RATE_MASK)))
+ if (rates == BRCMS_RATES_OFDM &&
+ is_cck_rate((r & BRCMS_RATE_MASK)))
continue;
dst->rates[count++] = r & xmask;
}
diff --git a/drivers/staging/brcm80211/brcmsmac/rate.h b/drivers/staging/brcm80211/brcmsmac/rate.h
index ae5479b..2cc66e0 100644
--- a/drivers/staging/brcm80211/brcmsmac/rate.h
+++ b/drivers/staging/brcm80211/brcmsmac/rate.h
@@ -18,6 +18,7 @@
#define _BRCM_RATE_H_

#include "types.h"
+#include "d11.h"

extern const u8 rate_info[];
extern const struct brcms_c_rateset cck_ofdm_mimo_rates;
@@ -48,33 +49,31 @@ struct brcms_mcs_info {
#define MCS_TABLE_SIZE 33 /* Number of mcs entries in the table */
extern const struct brcms_mcs_info mcs_table[];

-#define MCS_INVALID 0xFF
-#define MCS_CR_MASK 0x07 /* Code Rate bit mask */
-#define MCS_MOD_MASK 0x38 /* Modulation bit shift */
-#define MCS_MOD_SHIFT 3 /* MOdulation bit shift */
#define MCS_TXS_MASK 0xc0 /* num tx streams - 1 bit mask */
#define MCS_TXS_SHIFT 6 /* num tx streams - 1 bit shift */
-#define MCS_CR(_mcs) (mcs_table[_mcs].tx_phy_ctl3 & MCS_CR_MASK)

-#define MCS_MOD(_mcs) \
- ((mcs_table[_mcs].tx_phy_ctl3 & MCS_MOD_MASK) >> MCS_MOD_SHIFT)
-
-#define MCS_TXS(_mcs) \
- ((mcs_table[_mcs].tx_phy_ctl3 & MCS_TXS_MASK) >> MCS_TXS_SHIFT)
-
-#define MCS_RATE(_mcs, _is40, _sgi) (_sgi ? \
- (_is40 ? mcs_table[_mcs].phy_rate_40_sgi : \
- mcs_table[_mcs].phy_rate_20_sgi) : \
- (_is40 ? mcs_table[_mcs].phy_rate_40 : mcs_table[_mcs].phy_rate_20))
-
-#define VALID_MCS(_mcs) ((_mcs < MCS_TABLE_SIZE))
+/* returns num tx streams - 1 */
+static inline u8 mcs_2_txstreams(u8 mcs)
+{
+ return (mcs_table[mcs].tx_phy_ctl3 & MCS_TXS_MASK) >> MCS_TXS_SHIFT;
+}
+
+static inline uint mcs_2_rate(u8 mcs, bool is40, bool sgi)
+{
+ if (sgi) {
+ if (is40)
+ return mcs_table[mcs].phy_rate_40_sgi;
+ return mcs_table[mcs].phy_rate_20_sgi;
+ }
+ if (is40)
+ return mcs_table[mcs].phy_rate_40;
+
+ return mcs_table[mcs].phy_rate_20;
+}

/* Macro to use the rate_info table */
#define BRCMS_RATE_MASK_FULL 0xff /* Rate value mask with basic rate flag */

-/* convert 500kbps to bps */
-#define BRCMS_RATE_500K_TO_BPS(rate) ((rate) * 500000)
-
/*
* rate spec : holds rate and mode specific information required to generate a
* tx frame. Legacy CCK and OFDM information is held in the same manner as was
@@ -113,65 +112,104 @@ extern const struct brcms_mcs_info mcs_table[];
/* bit indicates override rate only */
#define RSPEC_OVERRIDE_MCS_ONLY 0x40000000

-#define BRCMS_HTPHY 127 /* HT PHY Membership */
-
-#define RSPEC_ACTIVE(rspec) (rspec & (RSPEC_RATE_MASK | RSPEC_MIMORATE))
-
-#define RSPEC2RATE(rspec) \
- ((rspec & RSPEC_MIMORATE) ? \
- MCS_RATE((rspec & RSPEC_RATE_MASK), RSPEC_IS40MHZ(rspec), \
- RSPEC_ISSGI(rspec)) : \
- (rspec & RSPEC_RATE_MASK))
-
-#define RSPEC_PHYTXBYTE2(rspec) ((rspec & 0xff00) >> 8)
-
-#define RSPEC_GET_BW(rspec) ((rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT)
-
-#define RSPEC_IS40MHZ(rspec) \
- ((((rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT) == PHY_TXC1_BW_40MHZ) || \
- (((rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT) == PHY_TXC1_BW_40MHZ_DUP))
-
-#define RSPEC_ISSGI(rspec) ((rspec & RSPEC_SHORT_GI) == RSPEC_SHORT_GI)
-#define RSPEC_MIMOPLCP3(rspec) ((rspec & 0xf00000) >> 16)
-#define PLCP3_ISSGI(plcp) (plcp & (RSPEC_SHORT_GI >> 16))
-#define RSPEC_STC(rspec) ((rspec & RSPEC_STC_MASK) >> RSPEC_STC_SHIFT)
-#define RSPEC_STF(rspec) ((rspec & RSPEC_STF_MASK) >> RSPEC_STF_SHIFT)
-#define PLCP3_ISSTBC(plcp) ((plcp & (RSPEC_STC_MASK) >> 16) == 0x10)
-#define PLCP3_STC_MASK 0x30
-#define PLCP3_STC_SHIFT 4
-
-/* Rate info table; takes a legacy rate or u32 */
-#define IS_MCS(r) (r & RSPEC_MIMORATE)
-
-#define IS_OFDM(r) (!IS_MCS(r) && (rate_info[(r) & RSPEC_RATE_MASK] & \
- BRCMS_RATE_FLAG))
-
-#define IS_CCK(r) (!IS_MCS(r) && ( \
- ((r) & BRCMS_RATE_MASK) == BRCM_RATE_1M || \
- ((r) & BRCMS_RATE_MASK) == BRCM_RATE_2M || \
- ((r) & BRCMS_RATE_MASK) == BRCM_RATE_5M5 || \
- ((r) & BRCMS_RATE_MASK) == BRCM_RATE_11M))
-
-#define IS_SINGLE_STREAM(mcs) \
- (((mcs) <= HIGHEST_SINGLE_STREAM_MCS) || ((mcs) == 32))
-
-#define CCK_RSPEC(cck) ((cck) & RSPEC_RATE_MASK)
-
-#define OFDM_RSPEC(ofdm) (((ofdm) & RSPEC_RATE_MASK) |\
- (PHY_TXC1_MODE_CDD << RSPEC_STF_SHIFT))
-
-#define LEGACY_RSPEC(rate) \
- (IS_CCK(rate) ? CCK_RSPEC(rate) : OFDM_RSPEC(rate))
-
-#define MCS_RSPEC(mcs) (((mcs) & RSPEC_RATE_MASK) | RSPEC_MIMORATE | \
- (IS_SINGLE_STREAM(mcs) ? (PHY_TXC1_MODE_CDD << RSPEC_STF_SHIFT) : \
- (PHY_TXC1_MODE_SDM << RSPEC_STF_SHIFT)))
+static inline bool rspec_active(u32 rspec)
+{
+ return rspec & (RSPEC_RATE_MASK | RSPEC_MIMORATE);
+}
+
+static inline u8 rspec_phytxbyte2(u32 rspec)
+{
+ return (rspec & 0xff00) >> 8;
+}
+
+static inline u32 rspec_get_bw(u32 rspec)
+{
+ return (rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT;
+}
+
+static inline bool rspec_issgi(u32 rspec)
+{
+ return (rspec & RSPEC_SHORT_GI) == RSPEC_SHORT_GI;
+}
+
+static inline bool rspec_is40mhz(u32 rspec)
+{
+ u32 bw = rspec_get_bw(rspec);
+
+ return bw == PHY_TXC1_BW_40MHZ || bw == PHY_TXC1_BW_40MHZ_DUP;
+}
+
+static inline uint rspec2rate(u32 rspec)
+{
+ if (rspec & RSPEC_MIMORATE)
+ return mcs_2_rate(rspec & RSPEC_RATE_MASK, rspec_is40mhz(rspec),
+ rspec_issgi(rspec));
+ return rspec & RSPEC_RATE_MASK;
+}
+
+static inline u8 rspec_mimoplcp3(u32 rspec)
+{
+ return (rspec & 0xf00000) >> 16;
+}
+
+static inline bool plcp3_issgi(u8 plcp)
+{
+ return (plcp & (RSPEC_SHORT_GI >> 16)) != 0;
+}
+
+static inline uint rspec_stc(u32 rspec)
+{
+ return (rspec & RSPEC_STC_MASK) >> RSPEC_STC_SHIFT;
+}
+
+static inline uint rspec_stf(u32 rspec)
+{
+ return (rspec & RSPEC_STF_MASK) >> RSPEC_STF_SHIFT;
+}
+
+static inline bool is_mcs_rate(u32 ratespec)
+{
+ return (ratespec & RSPEC_MIMORATE) != 0;
+}
+
+static inline bool is_ofdm_rate(u32 ratespec)
+{
+ return !is_mcs_rate(ratespec) &&
+ (rate_info[ratespec & RSPEC_RATE_MASK] & BRCMS_RATE_FLAG);
+}
+
+static inline bool is_cck_rate(u32 ratespec)
+{
+ u32 rate = (ratespec & BRCMS_RATE_MASK);
+
+ return !is_mcs_rate(ratespec) && (
+ rate == BRCM_RATE_1M || rate == BRCM_RATE_2M ||
+ rate == BRCM_RATE_5M5 || rate == BRCM_RATE_11M);
+}
+
+static inline bool is_single_stream(u8 mcs)
+{
+ return mcs <= HIGHEST_SINGLE_STREAM_MCS || mcs == 32;
+}
+
+static inline u8 cck_rspec(u8 cck)
+{
+ return cck & RSPEC_RATE_MASK;
+}

/* Convert encoded rate value in plcp header to numerical rates in 500 KHz
* increments */
extern const u8 ofdm_rate_lookup[];
-#define OFDM_PHY2MAC_RATE(rlpt) (ofdm_rate_lookup[rlpt & 0x7])
-#define CCK_PHY2MAC_RATE(signal) (signal/5)
+
+static inline u8 ofdm_phy2mac_rate(u8 rlpt)
+{
+ return ofdm_rate_lookup[rlpt & 0x7];
+}
+
+static inline u8 cck_phy2mac_rate(u8 signal)
+{
+ return signal/5;
+}

/* Rates specified in brcms_c_rateset_filter() */
#define BRCMS_RATES_CCK_OFDM 0
diff --git a/drivers/staging/brcm80211/brcmsmac/stf.c b/drivers/staging/brcm80211/brcmsmac/stf.c
index 82805e0..91b53a5 100644
--- a/drivers/staging/brcm80211/brcmsmac/stf.c
+++ b/drivers/staging/brcm80211/brcmsmac/stf.c
@@ -421,7 +421,7 @@ static u16 _brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc,
{
u16 phytxant = wlc->stf->phytxant;

- if (RSPEC_STF(rspec) != PHY_TXC1_MODE_SISO)
+ if (rspec_stf(rspec) != PHY_TXC1_MODE_SISO)
phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
else if (wlc->stf->txant == ANT_TX_DEF)
phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
--
1.7.4.1



2011-09-13 07:50:07

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 04/17] staging: brcm80211: fix for fullmac build problem

Fullmac had a build error for CONFIG_PM_SLEEP=n

Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index 0aff62d..7cb8f3f 100644
--- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -49,12 +49,10 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);

-#ifdef CONFIG_PM_SLEEP
static DECLARE_WAIT_QUEUE_HEAD(sdioh_request_byte_wait);
static DECLARE_WAIT_QUEUE_HEAD(sdioh_request_word_wait);
static DECLARE_WAIT_QUEUE_HEAD(sdioh_request_packet_wait);
static DECLARE_WAIT_QUEUE_HEAD(sdioh_request_buffer_wait);
-#endif /* CONFIG_PM_SLEEP */

static bool
brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
--
1.7.4.1



2011-09-13 07:50:22

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 10/17] staging: brcm80211: remove devpath related nvram variable lookup

From: Arend van Spriel <[email protected]>

The lookup function used for the devpath related functions did
not provide a variable table so the lookup would always fail. As
this makes the functions pretty useless these have been removed.

Reviewed-by: Roland Vossen <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/aiutils.c | 62 +-------------------------
drivers/staging/brcm80211/brcmsmac/aiutils.h | 5 --
2 files changed, 2 insertions(+), 65 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/aiutils.c b/drivers/staging/brcm80211/brcmsmac/aiutils.c
index 9510d83..b7b0bdf 100644
--- a/drivers/staging/brcm80211/brcmsmac/aiutils.c
+++ b/drivers/staging/brcm80211/brcmsmac/aiutils.c
@@ -1018,17 +1018,9 @@ static __used void ai_nvram_process(struct si_info *sii, char *pvars)

/* do a pci config read to get subsystem id and subvendor id */
pci_read_config_dword(sii->pbus, PCI_SUBSYSTEM_VENDOR_ID, &w);
- /* Let nvram variables override subsystem Vend/ID */
- sii->pub.boardvendor = (u16)ai_getdevpathintvar(&sii->pub,
- "boardvendor");
- if (sii->pub.boardvendor == 0)
- sii->pub.boardvendor = w & 0xffff;
-
- sii->pub.boardtype = (u16)ai_getdevpathintvar(&sii->pub,
- "boardtype");
- if (sii->pub.boardtype == 0)
- sii->pub.boardtype = (w >> 16) & 0xffff;

+ sii->pub.boardvendor = w & 0xffff;
+ sii->pub.boardtype = (w >> 16) & 0xffff;
sii->pub.boardflags = getintvar(pvars, "boardflags");
}

@@ -1864,56 +1856,6 @@ int ai_devpath(struct si_pub *sih, char *path, int size)
return 0;
}

-/* Concatenate the dev path with a varname into the given 'var' buffer
- * and return the 'var' pointer. Nothing is done to the arguments if
- * len == 0 or var is NULL, var is still returned. On overflow, the
- * first char will be set to '\0'.
- */
-static char *ai_devpathvar(struct si_pub *sih, char *var, int len,
- const char *name)
-{
- uint path_len;
-
- if (!var || len <= 0)
- return var;
-
- if (ai_devpath(sih, var, len) == 0) {
- path_len = strlen(var);
-
- if (strlen(name) + 1 > (uint) (len - path_len))
- var[0] = '\0';
- else
- strncpy(var + path_len, name, len - path_len - 1);
- }
-
- return var;
-}
-
-/* Get a variable, but only if it has a devpath prefix */
-char *ai_getdevpathvar(struct si_pub *sih, const char *name)
-{
- char varname[SI_DEVPATH_BUFSZ + 32];
-
- ai_devpathvar(sih, varname, sizeof(varname), name);
-
- return getvar(NULL, varname);
-}
-
-/* Get a variable, but only if it has a devpath prefix */
-int ai_getdevpathintvar(struct si_pub *sih, const char *name)
-{
- char varname[SI_DEVPATH_BUFSZ + 32];
-
- ai_devpathvar(sih, varname, sizeof(varname), name);
-
- return getintvar(NULL, varname);
-}
-
-char *ai_getnvramflvar(struct si_pub *sih, const char *name)
-{
- return getvar(NULL, name);
-}
-
bool ai_pci_war16165(struct si_pub *sih)
{
struct si_info *sii;
diff --git a/drivers/staging/brcm80211/brcmsmac/aiutils.h b/drivers/staging/brcm80211/brcmsmac/aiutils.h
index 0d4fa85..a776945 100644
--- a/drivers/staging/brcm80211/brcmsmac/aiutils.h
+++ b/drivers/staging/brcm80211/brcmsmac/aiutils.h
@@ -369,9 +369,6 @@ extern bool ai_is_sprom_available(struct si_pub *sih);
* Return 0 on success, nonzero otherwise.
*/
extern int ai_devpath(struct si_pub *sih, char *path, int size);
-/* Read variable with prepending the devpath to the name */
-extern char *ai_getdevpathvar(struct si_pub *sih, const char *name);
-extern int ai_getdevpathintvar(struct si_pub *sih, const char *name);

extern void ai_pci_sleep(struct si_pub *sih);
extern void ai_pci_down(struct si_pub *sih);
@@ -382,6 +379,4 @@ extern void ai_chipcontrl_epa4331(struct si_pub *sih, bool on);
/* Enable Ex-PA for 4313 */
extern void ai_epa_4313war(struct si_pub *sih);

-char *ai_getnvramflvar(struct si_pub *sih, const char *name);
-
#endif /* _BRCM_AIUTILS_H_ */
--
1.7.4.1



2011-09-13 07:50:18

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 11/17] staging: brcm80211: remove brcms_c_get_par and set_par functions

From: Arend van Spriel <[email protected]>

The source main.c provided an interface function that handled several
things demultiplexing on given identifier. This interface has been
replaced by separate functions to make it more straightforward.

Reported-by: Johannes Berg <[email protected]>
Reviewed-by: Roland Vossen <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/mac80211_if.c | 26 ++----
drivers/staging/brcm80211/brcmsmac/main.c | 87 ++++++---------------
drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c | 2 +-
drivers/staging/brcm80211/brcmsmac/pub.h | 8 +-
4 files changed, 39 insertions(+), 84 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
index 5696b39..4cc0db6 100644
--- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
@@ -373,14 +373,8 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)

LOCK(wl);
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
- if (brcms_c_set_par(wl->wlc, IOV_BCN_LI_BCN,
- conf->listen_interval) < 0) {
- wiphy_err(wiphy, "%s: Error setting listen_interval\n",
- __func__);
- err = -EIO;
- goto config_out;
- }
- brcms_c_get_par(wl->wlc, IOV_BCN_LI_BCN, &new_int);
+ brcms_c_set_beacon_listen_interval(wl->wlc,
+ conf->listen_interval);
}
if (changed & IEEE80211_CONF_CHANGE_MONITOR)
wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n",
@@ -392,17 +386,16 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
"true" : "false");

if (changed & IEEE80211_CONF_CHANGE_POWER) {
- if (brcms_c_set_par(wl->wlc, IOV_QTXPOWER,
- conf->power_level * 4) < 0) {
+ err = brcms_c_set_tx_power(wl->wlc, conf->power_level);
+ if (err < 0) {
wiphy_err(wiphy, "%s: Error setting power_level\n",
__func__);
- err = -EIO;
goto config_out;
}
- brcms_c_get_par(wl->wlc, IOV_QTXPOWER, &new_int);
- if (new_int != (conf->power_level * 4))
+ new_int = brcms_c_get_tx_power(wl->wlc);
+ if (new_int != conf->power_level)
wiphy_err(wiphy, "%s: Power level req != actual, %d %d"
- "\n", __func__, conf->power_level * 4,
+ "\n", __func__, conf->power_level,
new_int);
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
@@ -1177,9 +1170,8 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,

wl->pub->ieee_hw = hw;

- if (brcms_c_set_par(wl->wlc, IOV_MPC, 0) < 0)
- wiphy_err(wl->wiphy, "wl%d: Error setting MPC variable to 0\n",
- unit);
+ /* disable mpc */
+ brcms_c_set_radio_mpc(wl->wlc, false);

/* register our interrupt handler */
if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
diff --git a/drivers/staging/brcm80211/brcmsmac/main.c b/drivers/staging/brcm80211/brcmsmac/main.c
index a40fcba..ec7de38 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.c
+++ b/drivers/staging/brcm80211/brcmsmac/main.c
@@ -9375,74 +9375,37 @@ void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
brcms_msleep(wlc->wl, 1);
}

-int brcms_c_set_par(struct brcms_c_info *wlc, enum wlc_par_id par_id,
- int int_val)
+void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
{
- int err = 0;
+ wlc->bcn_li_bcn = interval;
+ if (wlc->pub->up)
+ brcms_c_bcn_li_upd(wlc);
+}

- switch (par_id) {
- case IOV_BCN_LI_BCN:
- wlc->bcn_li_bcn = (u8) int_val;
- if (wlc->pub->up)
- brcms_c_bcn_li_upd(wlc);
- break;
- /* As long as override is false, this only sets the *user*
- targets. User can twiddle this all he wants with no harm.
- wlc_phy_txpower_set() explicitly sets override to false if
- not internal or test.
- */
- case IOV_QTXPOWER:{
- u8 qdbm;
- bool override;
-
- /* Remove override bit and clip to max qdbm value */
- qdbm = (u8)min_t(u32, (int_val & ~WL_TXPWR_OVERRIDE), 0xff);
- /* Extract override setting */
- override = (int_val & WL_TXPWR_OVERRIDE) ? true : false;
- err =
- wlc_phy_txpower_set(wlc->band->pi, qdbm, override);
- break;
- }
- case IOV_MPC:
- wlc->mpc = (bool)int_val;
- brcms_c_radio_mpc_upd(wlc);
- break;
- default:
- err = -ENOTSUPP;
- }
- return err;
+int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
+{
+ uint qdbm;
+
+ /* Remove override bit and clip to max qdbm value */
+ qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff);
+ return wlc_phy_txpower_set(wlc->band->pi, qdbm, false);
}

-int brcms_c_get_par(struct brcms_c_info *wlc, enum wlc_par_id par_id,
- int *ret_int_ptr)
+int brcms_c_get_tx_power(struct brcms_c_info *wlc)
{
- int err = 0;
+ uint qdbm;
+ bool override;

- switch (par_id) {
- case IOV_BCN_LI_BCN:
- *ret_int_ptr = wlc->bcn_li_bcn;
- break;
- case IOV_QTXPOWER: {
- uint qdbm;
- bool override;
-
- err = wlc_phy_txpower_get(wlc->band->pi, &qdbm,
- &override);
- if (err != 0)
- return err;
-
- /* Return qdbm units */
- *ret_int_ptr =
- qdbm | (override ? WL_TXPWR_OVERRIDE : 0);
- break;
- }
- case IOV_MPC:
- *ret_int_ptr = (s32) wlc->mpc;
- break;
- default:
- err = -ENOTSUPP;
- }
- return err;
+ wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override);
+
+ /* Return qdbm units */
+ return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
+}
+
+void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc)
+{
+ wlc->mpc = mpc;
+ brcms_c_radio_mpc_upd(wlc);
}

/*
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c
index eb171f0..196a595 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c
@@ -1463,7 +1463,7 @@ int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
int i;

if (qdbm > 127)
- return 5;
+ return -EINVAL;

for (i = 0; i < TXP_NUM_RATES; i++)
pi->tx_user_target[i] = (u8) qdbm;
diff --git a/drivers/staging/brcm80211/brcmsmac/pub.h b/drivers/staging/brcm80211/brcmsmac/pub.h
index 6230350..c72f7b5 100644
--- a/drivers/staging/brcm80211/brcmsmac/pub.h
+++ b/drivers/staging/brcm80211/brcmsmac/pub.h
@@ -350,10 +350,6 @@ extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
struct ieee80211_sta *sta, u16 tid);
extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
u8 ba_wsize, uint max_rx_ampdu_bytes);
-extern int brcms_c_set_par(struct brcms_c_info *wlc, enum wlc_par_id par_id,
- int val);
-extern int brcms_c_get_par(struct brcms_c_info *wlc, enum wlc_par_id par_id,
- int *ret_int_ptr);
extern char *getvar(char *vars, const char *name);
extern int getintvar(char *vars, const char *name);

@@ -384,6 +380,10 @@ int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period);
u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx);
void brcms_c_set_shortslot_override(struct brcms_c_info *wlc,
s8 sslot_override);
+void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval);
+int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
+int brcms_c_get_tx_power(struct brcms_c_info *wlc);
+void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc);

/* helper functions */
extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
--
1.7.4.1



2011-09-13 07:50:22

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 14/17] staging: brcm80211: simplification of brcmf_netdev_ioctl_priv()

This function is only called from within the driver. Because of that
certain simplifications (not required to lock down user mem pages,
not required to check user permissions) could be performed.

Reviewed-by: Arend van Spriel <[email protected]>
Reviewed-by: Franky Lin <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmfmac/dhd.h | 14 +----
drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 69 +++------------------
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 5 +-
3 files changed, 13 insertions(+), 75 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h
index 93a1bfc..a92a28e 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd.h
@@ -715,7 +715,8 @@ extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus,
extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx);
extern int brcmf_netdev_wait_pend8021x(struct net_device *dev);

-extern int brcmf_netdev_ioctl_priv(struct net_device *net, struct ifreq *ifr);
+extern int brcmf_netdev_ioctl_priv(struct net_device *net,
+ struct brcmf_ioctl *ioc);

/* Indication from bus module regarding removal/absence of dongle */
extern void brcmf_detach(struct brcmf_pub *drvr);
@@ -771,17 +772,6 @@ extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg);
extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg,
int enable, int master_mode);

-/* Linux network driver ioctl encoding */
-struct brcmf_c_ioctl {
- uint cmd; /* common ioctl definition */
- void __user *buf; /* pointer to user buffer */
- uint len; /* length of user buffer */
- bool set; /* get or set request (optional) */
- uint used; /* bytes read or written (optional) */
- uint needed; /* bytes needed (optional) */
- uint driver; /* to identify target driver */
-};
-
/* per-driver magic numbers */
#define BRCMF_IOCTL_MAGIC 0x00444944

diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
index 4bc231e..3898765 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
@@ -964,61 +964,19 @@ static int brcmf_netdev_ioctl_entry(struct net_device *net, struct ifreq *ifr,
return -EOPNOTSUPP;
}

-/* called only from within this driver, handles cmd == SIOCDEVPRIVATE */
-int brcmf_netdev_ioctl_priv(struct net_device *net, struct ifreq *ifr)
+/* called only from within this driver */
+int brcmf_netdev_ioctl_priv(struct net_device *net, struct brcmf_ioctl *ioc)
{
- struct brcmf_c_ioctl ioc;
int bcmerror = 0;
int buflen = 0;
- void *buf = NULL;
- uint driver = 0;
bool is_set_key_cmd;
struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
int ifidx;

ifidx = brcmf_net2idx(drvr_priv, net);

- memset(&ioc, 0, sizeof(ioc));
-
- /* Copy the ioc control structure part of ioctl request */
- if (copy_from_user(&ioc, ifr->ifr_data, sizeof(struct brcmf_ioctl))) {
- bcmerror = -EINVAL;
- goto done;
- }
-
- /* Copy out any buffer passed */
- if (ioc.buf) {
- buflen = min_t(int, ioc.len, BRCMF_IOCTL_MAXLEN);
- /* optimization for direct ioctl calls from kernel */
- /*
- if (segment_eq(get_fs(), KERNEL_DS)) {
- buf = ioc.buf;
- } else {
- */
- {
- buf = kmalloc(buflen, GFP_ATOMIC);
- if (!buf) {
- bcmerror = -ENOMEM;
- goto done;
- }
- if (copy_from_user(buf, ioc.buf, buflen)) {
- bcmerror = -EINVAL;
- goto done;
- }
- }
- }
-
- /* To differentiate read 4 more byes */
- if ((copy_from_user(&driver, (char __user *)ifr->ifr_data +
- sizeof(struct brcmf_ioctl), sizeof(uint)) != 0)) {
- bcmerror = -EINVAL;
- goto done;
- }
-
- if (!capable(CAP_NET_ADMIN)) {
- bcmerror = -EPERM;
- goto done;
- }
+ if (ioc->buf != NULL)
+ buflen = min_t(int, ioc->len, BRCMF_IOCTL_MAXLEN);

/* send to dongle (must be up, and wl) */
if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) {
@@ -1036,25 +994,18 @@ int brcmf_netdev_ioctl_priv(struct net_device *net, struct ifreq *ifr)
* Intercept BRCMF_C_SET_KEY IOCTL - serialize M4 send and
* set key IOCTL to prevent M4 encryption.
*/
- is_set_key_cmd = ((ioc.cmd == BRCMF_C_SET_KEY) ||
- ((ioc.cmd == BRCMF_C_SET_VAR) &&
- !(strncmp("wsec_key", ioc.buf, 9))) ||
- ((ioc.cmd == BRCMF_C_SET_VAR) &&
- !(strncmp("bsscfg:wsec_key", ioc.buf, 15))));
+ is_set_key_cmd = ((ioc->cmd == BRCMF_C_SET_KEY) ||
+ ((ioc->cmd == BRCMF_C_SET_VAR) &&
+ !(strncmp("wsec_key", ioc->buf, 9))) ||
+ ((ioc->cmd == BRCMF_C_SET_VAR) &&
+ !(strncmp("bsscfg:wsec_key", ioc->buf, 15))));
if (is_set_key_cmd)
brcmf_netdev_wait_pend8021x(net);

bcmerror = brcmf_proto_ioctl(&drvr_priv->pub, ifidx,
- (struct brcmf_ioctl *)&ioc, buf, buflen);
+ ioc, ioc->buf, buflen);

done:
- if (!bcmerror && buf && ioc.buf) {
- if (copy_to_user(ioc.buf, buf, buflen))
- bcmerror = -EFAULT;
- }
-
- kfree(buf);
-
if (bcmerror > 0)
bcmerror = 0;

diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
index 3fa0c1b..b001e40 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
@@ -272,7 +272,6 @@ static void convert_key_to_CPU(struct brcmf_wsec_key *key)
static s32
brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
{
- struct ifreq ifr;
struct brcmf_ioctl ioc;
mm_segment_t fs;
s32 err = 0;
@@ -281,12 +280,10 @@ brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
ioc.cmd = cmd;
ioc.buf = arg;
ioc.len = len;
- strcpy(ifr.ifr_name, dev->name);
- ifr.ifr_data = (char __user *)&ioc;

fs = get_fs();
set_fs(get_ds());
- err = brcmf_netdev_ioctl_priv(dev, &ifr);
+ err = brcmf_netdev_ioctl_priv(dev, &ioc);
set_fs(fs);

return err;
--
1.7.4.1



2011-09-13 07:50:22

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 09/17] staging: brcm80211: added clarification on softmac dma alignment

Descriptor ring can only start at 8KB alignment, this requirement
is dictated by DMA hardware.

Reported-by: Johannes Berg <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/dma.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/dma.c b/drivers/staging/brcm80211/brcmsmac/dma.c
index 6c9b1fe..06990b3 100644
--- a/drivers/staging/brcm80211/brcmsmac/dma.c
+++ b/drivers/staging/brcm80211/brcmsmac/dma.c
@@ -24,8 +24,8 @@
#include "dma.h"

/*
- * Each descriptor ring must be 8kB aligned, and fit within a
- * contiguous 8kB physical address.
+ * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within
+ * a contiguous 8kB physical address.
*/
#define D64RINGALIGN_BITS 13
#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS)
@@ -440,6 +440,10 @@ static bool _dma_descriptor_align(struct dma_info *di)
return true;
}

+/*
+ * Descriptor table must start at the DMA hardware dictated alignment, so
+ * allocated memory must be large enough to support this requirement.
+ */
static void *dma_alloc_consistent(struct pci_dev *pdev, uint size,
u16 align_bits, uint *alloced,
dma_addr_t *pap)
--
1.7.4.1



2011-09-13 07:50:22

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 17/17] staging: brcm80211: introduced fullmac function get/set u32 to/from dongle

Code cleanup. Avoids repetition of same code fragment.

Reviewed-by: Arend van Spriel <[email protected]>
Reviewed-by: Franky Lin <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 62 ++++++++++-----------
1 files changed, 30 insertions(+), 32 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
index ce393ac..1f736ea 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
@@ -267,6 +267,19 @@ brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
return err;
}

+/* function for reading/writing a single u32 from/to the dongle */
+static int
+brcmf_dev_ioctl_u32(struct net_device *dev, u32 cmd, u32 *par)
+{
+ int err;
+ __le32 par_le = cpu_to_le32(*par);
+
+ err = brcmf_dev_ioctl(dev, cmd, &par_le, sizeof(__le32));
+ *par = le32_to_cpu(par_le);
+
+ return err;
+}
+
static void convert_key_from_CPU(struct brcmf_wsec_key *key,
struct brcmf_wsec_key_le *key_le)
{
@@ -327,8 +340,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}

- infra = cpu_to_le32(infra);
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_INFRA, &infra, sizeof(infra));
+ err = brcmf_dev_ioctl_u32(ndev, BRCMF_C_SET_INFRA, &infra);
if (unlikely(err)) {
WL_ERR("WLC_SET_INFRA error (%d)\n", err);
err = -EAGAIN;
@@ -656,8 +668,7 @@ static s32 brcmf_set_retry(struct net_device *dev, u32 retry, bool l)
s32 err = 0;
u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);

- retry = cpu_to_le32(retry);
- err = brcmf_dev_ioctl(dev, cmd, &retry, sizeof(retry));
+ err = brcmf_dev_ioctl_u32(dev, cmd, &retry);
if (unlikely(err)) {
WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
return err;
@@ -941,9 +952,9 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
}

/* set channel for starter */
- target_channel = cpu_to_le32(cfg_priv->channel);
- err = brcmf_dev_ioctl(dev, BRCM_SET_CHANNEL,
- &target_channel, sizeof(target_channel));
+ target_channel = cfg_priv->channel;
+ err = brcmf_dev_ioctl_u32(dev, BRCM_SET_CHANNEL,
+ &target_channel);
if (unlikely(err)) {
WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
goto done;
@@ -1388,9 +1399,7 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
}
/* Make sure radio is off or on as far as software is concerned */
disable = WL_RADIO_SW_DISABLE << 16;
- disable = cpu_to_le32(disable);
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_RADIO, &disable,
- sizeof(disable));
+ err = brcmf_dev_ioctl_u32(ndev, BRCMF_C_SET_RADIO, &disable);
if (unlikely(err))
WL_ERR("WLC_SET_RADIO error (%d)\n", err);

@@ -1440,7 +1449,7 @@ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, bool unicast, bool multicast)
{
u32 index;
- s32 wsec;
+ u32 wsec;
s32 err = 0;

WL_TRACE("Enter\n");
@@ -1448,19 +1457,16 @@ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
if (!check_sys_up(wiphy))
return -EIO;

- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_WSEC, &wsec, sizeof(wsec));
+ err = brcmf_dev_ioctl_u32(dev, BRCMF_C_GET_WSEC, &wsec);
if (unlikely(err)) {
WL_ERR("WLC_GET_WSEC error (%d)\n", err);
goto done;
}

- wsec = le32_to_cpu(wsec);
if (wsec & WEP_ENABLED) {
/* Just select a new current key */
- index = (u32) key_idx;
- index = cpu_to_le32(index);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY_PRIMARY, &index,
- sizeof(index));
+ index = key_idx;
+ err = brcmf_dev_ioctl_u32(dev, BRCMF_C_SET_KEY_PRIMARY, &index);
if (unlikely(err))
WL_ERR("error (%d)\n", err);
}
@@ -1637,8 +1643,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
}

val = 1; /* assume shared key. otherwise 0 */
- val = cpu_to_le32(val);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_AUTH, &val, sizeof(val));
+ err = brcmf_dev_ioctl_u32(dev, BRCMF_C_SET_AUTH, &val);
if (unlikely(err))
WL_ERR("WLC_SET_AUTH error (%d)\n", err);
done:
@@ -1699,8 +1704,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
}

val = 0; /* assume open key. otherwise 1 */
- val = cpu_to_le32(val);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_AUTH, &val, sizeof(val));
+ err = brcmf_dev_ioctl_u32(dev, BRCMF_C_SET_AUTH, &val);
if (unlikely(err)) {
WL_ERR("WLC_SET_AUTH error (%d)\n", err);
/* Ignore this error, may happen during DISASSOC */
@@ -1729,14 +1733,13 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,

memset(&params, 0, sizeof(params));

- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_WSEC, &wsec, sizeof(wsec));
+ err = brcmf_dev_ioctl_u32(dev, BRCMF_C_GET_WSEC, &wsec);
if (unlikely(err)) {
WL_ERR("WLC_GET_WSEC error (%d)\n", err);
/* Ignore this error, may happen during DISASSOC */
err = -EAGAIN;
goto done;
}
- wsec = le32_to_cpu(wsec);
switch (wsec) {
case WEP_ENABLED:
sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
@@ -1804,11 +1807,10 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
}

/* Report the current tx rate */
- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_RATE, &rate, sizeof(rate));
+ err = brcmf_dev_ioctl_u32(dev, BRCMF_C_GET_RATE, &rate);
if (err) {
WL_ERR("Could not get rate (%d)\n", err);
} else {
- rate = le32_to_cpu(rate);
sinfo->filled |= STATION_INFO_TX_BITRATE;
sinfo->txrate.legacy = rate * 5;
WL_CONN("Rate %d Mbps\n", rate / 2);
@@ -1858,10 +1860,9 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
}

pm = enabled ? PM_FAST : PM_OFF;
- pm = cpu_to_le32(pm);
WL_INFO("power save %s\n", (pm ? "enabled" : "disabled"));

- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_PM, &pm, sizeof(pm));
+ err = brcmf_dev_ioctl_u32(dev, BRCMF_C_SET_PM, &pm);
if (unlikely(err)) {
if (err == -ENODEV)
WL_ERR("net_device is not ready yet\n");
@@ -3491,8 +3492,7 @@ static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype)
WL_ERR("invalid type (%d)\n", iftype);
return err;
}
- infra = cpu_to_le32(infra);
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_INFRA, &infra, sizeof(infra));
+ err = brcmf_dev_ioctl_u32(ndev, BRCMF_C_SET_INFRA, &infra);
if (unlikely(err)) {
WL_ERR("WLC_SET_INFRA error (%d)\n", err);
return err;
@@ -3703,9 +3703,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv,
goto default_conf_out;

power_mode = cfg_priv->pwr_save ? PM_FAST : PM_OFF;
- power_mode = cpu_to_le32(power_mode);
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_PM,
- &power_mode, sizeof(power_mode));
+ err = brcmf_dev_ioctl_u32(ndev, BRCMF_C_SET_PM, &power_mode);
if (err)
goto default_conf_out;
WL_INFO("power save set to %s\n",
--
1.7.4.1



2011-09-14 02:04:01

by Dan Carpenter

[permalink] [raw]
Subject: Re: [PATCH 14/17] staging: brcm80211: simplification of brcmf_netdev_ioctl_priv()

On Tue, Sep 13, 2011 at 09:49:54AM +0200, Roland Vossen wrote:
> + if (ioc->buf != NULL)
> + buflen = min_t(int, ioc->len, BRCMF_IOCTL_MAXLEN);
^^^^
Should be uint here.

In Linus's tree we cast buflen to int in brcmf_proto_ioctl() so the
cap there doesn't work either.

if (len > BRCMF_C_IOCTL_MAXLEN)
goto done;

(len is negative).

regards,
dan carpenter


2011-09-13 19:17:57

by Dan Carpenter

[permalink] [raw]
Subject: Re: [PATCH 02/17] staging: brcm80211: remove ioctl layer from brcmsmac

On Tue, Sep 13, 2011 at 09:49:42AM +0200, Roland Vossen wrote:
> @@ -530,20 +515,22 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
>
> /* update the rate set */
> LOCK(wl);
> - brcms_c_ioctl(wl->wlc, BRCM_SET_RATESET, &rs, sizeof(rs));
> + error = brcms_c_set_rateset(wl->wlc, &rs);
> UNLOCK(wl);
> + if (!error)
^^^^^^

This test is reversed so this will fill your log with spam.

> + wiphy_err(wiphy, "changing basic rates failed: %d\n",
> + error);
> }

regards,
dan carpenter

2011-09-13 07:50:18

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 16/17] staging: brcm80211: fullmac sparse endianness encryption keys check

Added support by making a distinction between a struct and its little
endian relative.

Reviewed-by: Arend van Spriel <[email protected]>
Reviewed-by: Franky Lin <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmfmac/dhd.h | 36 +++++++++--
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 78 ++++++++++++----------
2 files changed, 73 insertions(+), 41 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h
index a92a28e..8898370 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd.h
@@ -405,6 +405,11 @@ struct brcmf_ssid {
unsigned char SSID[32];
};

+struct brcmf_ssid_le {
+ __le32 SSID_len;
+ unsigned char SSID[32];
+};
+
struct brcmf_scan_params {
struct brcmf_ssid ssid; /* default: {0, ""} */
u8 bssid[ETH_ALEN]; /* default: bcast */
@@ -500,16 +505,37 @@ struct brcmf_wsec_key {
u32 pad_1[18];
u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
u32 flags; /* misc flags */
- u32 pad_2[2];
- int pad_3;
- int iv_initialized; /* has IV been initialized already? */
- int pad_4;
+ u32 pad_2[3];
+ u32 iv_initialized; /* has IV been initialized already? */
+ u32 pad_3;
/* Rx IV */
struct {
u32 hi; /* upper 32 bits of IV */
u16 lo; /* lower 16 bits of IV */
} rxiv;
- u32 pad_5[2];
+ u32 pad_4[2];
+ u8 ea[ETH_ALEN]; /* per station */
+};
+
+/*
+ * dongle requires same struct as above but with fields in little endian order
+ */
+struct brcmf_wsec_key_le {
+ __le32 index; /* key index */
+ __le32 len; /* key length */
+ u8 data[WLAN_MAX_KEY_LEN]; /* key data */
+ __le32 pad_1[18];
+ __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
+ __le32 flags; /* misc flags */
+ __le32 pad_2[3];
+ __le32 iv_initialized; /* has IV been initialized already? */
+ __le32 pad_3;
+ /* Rx IV */
+ struct {
+ __le32 hi; /* upper 32 bits of IV */
+ __le16 lo; /* lower 16 bits of IV */
+ } rxiv;
+ __le32 pad_4[2];
u8 ea[ETH_ALEN]; /* per station */
};

diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
index 926b019..ce393ac 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
@@ -247,17 +247,6 @@ static const u32 __wl_cipher_suites[] = {
WLAN_CIPHER_SUITE_AES_CMAC,
};

-static void convert_key_from_CPU(struct brcmf_wsec_key *key)
-{
- key->index = cpu_to_le32(key->index);
- key->len = cpu_to_le32(key->len);
- key->algo = cpu_to_le32(key->algo);
- key->flags = cpu_to_le32(key->flags);
- key->rxiv.hi = cpu_to_le32(key->rxiv.hi);
- key->rxiv.lo = cpu_to_le16(key->rxiv.lo);
- key->iv_initialized = cpu_to_le32(key->iv_initialized);
-}
-
static s32
brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
{
@@ -278,6 +267,33 @@ brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
return err;
}

+static void convert_key_from_CPU(struct brcmf_wsec_key *key,
+ struct brcmf_wsec_key_le *key_le)
+{
+ key_le->index = cpu_to_le32(key->index);
+ key_le->len = cpu_to_le32(key->len);
+ key_le->algo = cpu_to_le32(key->algo);
+ key_le->flags = cpu_to_le32(key->flags);
+ key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
+ key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
+ key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
+ memcpy(key_le->data, key->data, sizeof(key->data));
+ memcpy(key_le->ea, key->ea, sizeof(key->ea));
+}
+
+static int send_key_to_dongle(struct net_device *dev,
+ struct brcmf_wsec_key *key)
+{
+ int err;
+ struct brcmf_wsec_key_le key_le;
+
+ convert_key_from_CPU(key, &key_le);
+ err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key_le, sizeof(key_le));
+ if (err)
+ WL_ERR("WLC_SET_KEY error (%d)\n", err);
+ return err;
+}
+
static s32
brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
enum nl80211_iftype type, u32 *flags,
@@ -1200,13 +1216,10 @@ brcmf_set_set_sharedkey(struct net_device *dev,
WL_CONN("key length (%d) key index (%d) algo (%d)\n",
key.len, key.index, key.algo);
WL_CONN("key \"%s\"\n", key.data);
- convert_key_from_CPU(&key);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key,
- sizeof(key));
- if (unlikely(err)) {
- WL_ERR("WLC_SET_KEY error (%d)\n", err);
+ err = send_key_to_dongle(dev, &key);
+ if (err)
return err;
- }
+
if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
WL_CONN("set auth_type to shared key\n");
val = 1; /* shared key */
@@ -1461,6 +1474,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, const u8 *mac_addr, struct key_params *params)
{
struct brcmf_wsec_key key;
+ struct brcmf_wsec_key_le key_le;
s32 err = 0;

memset(&key, 0, sizeof(key));
@@ -1473,12 +1487,9 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev,
/* check for key index change */
if (key.len == 0) {
/* key delete */
- convert_key_from_CPU(&key);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key));
- if (unlikely(err)) {
- WL_ERR("key delete error (%d)\n", err);
+ err = send_key_to_dongle(dev, &key);
+ if (err)
return err;
- }
} else {
if (key.len > sizeof(key.data)) {
WL_ERR("Invalid key length (%d)\n", key.len);
@@ -1531,10 +1542,11 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev,
WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
return -EINVAL;
}
- convert_key_from_CPU(&key);
+ convert_key_from_CPU(&key, &key_le);

brcmf_netdev_wait_pend8021x(dev);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key));
+ err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key_le,
+ sizeof(key_le));
if (unlikely(err)) {
WL_ERR("WLC_SET_KEY error (%d)\n", err);
return err;
@@ -1606,13 +1618,9 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
goto done;
}

- /* Set the new key/index */
- convert_key_from_CPU(&key);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key));
- if (unlikely(err)) {
- WL_ERR("WLC_SET_KEY error (%d)\n", err);
+ err = send_key_to_dongle(dev, &key); /* Set the new key/index */
+ if (err)
goto done;
- }

val = WEP_ENABLED;
err = brcmf_dev_intvar_get(dev, "wsec", &wsec);
@@ -1658,17 +1666,15 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
key.algo = CRYPTO_ALGO_OFF;

WL_CONN("key index (%d)\n", key_idx);
+
/* Set the new key/index */
- convert_key_from_CPU(&key);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key));
- if (unlikely(err)) {
+ err = send_key_to_dongle(dev, &key);
+ if (err) {
if (err == -EINVAL) {
if (key.index >= DOT11_MAX_DEFAULT_KEYS)
/* we ignore this key index in this case */
WL_ERR("invalid key index (%d)\n", key_idx);
- } else
- WL_ERR("WLC_SET_KEY error (%d)\n", err);
-
+ }
/* Ignore this error, may happen during DISASSOC */
err = -EAGAIN;
goto done;
--
1.7.4.1



2011-09-13 07:50:07

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 03/17] staging: brcm80211: remove function ieee_set_channel()

From: Arend van Spriel <[email protected]>

The function ieee_set_channel() provides very little functionality
so it has been removed.

Reported-by: Johannes Berg <[email protected]>
Reviewed-by: Roland Vossen <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/mac80211_if.c | 39 ++++-----------------
drivers/staging/brcm80211/brcmsmac/main.c | 11 +-----
drivers/staging/brcm80211/brcmsmac/pub.h | 3 +-
3 files changed, 12 insertions(+), 41 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
index 7d012be..5696b39 100644
--- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
@@ -363,34 +363,6 @@ brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
UNLOCK(wl);
}

-/*
- * precondition: perimeter lock has been acquired
- */
-static int
-ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
- enum nl80211_channel_type type)
-{
- struct brcms_info *wl = hw->priv;
- int err;
-
- switch (type) {
- case NL80211_CHAN_HT20:
- case NL80211_CHAN_NO_HT:
- err = brcms_c_set_channel(wl->wlc, chan->hw_value);
- break;
- case NL80211_CHAN_HT40MINUS:
- case NL80211_CHAN_HT40PLUS:
- wiphy_err(hw->wiphy,
- "%s: Need to implement 40 Mhz Channels!\n", __func__);
- err = -ENOTSUPP;
- break;
- default:
- err = -EINVAL;
- }
-
- return err;
-}
-
static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
{
struct ieee80211_conf *conf = &hw->conf;
@@ -433,9 +405,14 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
"\n", __func__, conf->power_level * 4,
new_int);
}
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
- err = ieee_set_channel(hw, conf->channel, conf->channel_type);
-
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ if (conf->channel_type == NL80211_CHAN_HT20 ||
+ conf->channel_type == NL80211_CHAN_NO_HT)
+ err = brcms_c_set_channel(wl->wlc,
+ conf->channel->hw_value);
+ else
+ err = -ENOTSUPP;
+ }
if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
err = brcms_c_set_rate_limit(wl->wlc,
conf->short_frame_max_tx_count,
diff --git a/drivers/staging/brcm80211/brcmsmac/main.c b/drivers/staging/brcm80211/brcmsmac/main.c
index 705f0eb..bf3634e 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.c
+++ b/drivers/staging/brcm80211/brcmsmac/main.c
@@ -6288,14 +6288,8 @@ u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx)
return wlc->band->phytype;
}

-int brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)
+void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)
{
- if (sslot_override != BRCMS_SHORTSLOT_AUTO &&
- sslot_override != BRCMS_SHORTSLOT_OFF &&
- sslot_override != BRCMS_SHORTSLOT_ON) {
- return -EINVAL;
- }
-
wlc->shortslot_override = sslot_override;

/*
@@ -6303,7 +6297,7 @@ int brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)
* currently on the 5G band
*/
if (wlc->band->bandtype == BRCM_BAND_5G)
- return 0;
+ return;

if (wlc->pub->up && wlc->pub->associated) {
/* let watchdog or beacon processing update shortslot */
@@ -6320,7 +6314,6 @@ int brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)
(wlc->shortslot_override ==
BRCMS_SHORTSLOT_ON);
}
- return 0;
}

/*
diff --git a/drivers/staging/brcm80211/brcmsmac/pub.h b/drivers/staging/brcm80211/brcmsmac/pub.h
index 3655ac6..2069d16 100644
--- a/drivers/staging/brcm80211/brcmsmac/pub.h
+++ b/drivers/staging/brcm80211/brcmsmac/pub.h
@@ -386,7 +386,8 @@ void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs);
int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period);
u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx);
-int brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override);
+void brcms_c_set_shortslot_override(struct brcms_c_info *wlc,
+ s8 sslot_override);

/* helper functions */
extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
--
1.7.4.1



2011-09-13 07:50:22

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 08/17] staging: brcm80211: macro cleanup in softmac main.c

Reported-by: Johannes Berg <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/main.c | 249 +++++++++++++----------------
1 files changed, 115 insertions(+), 134 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/main.c b/drivers/staging/brcm80211/brcmsmac/main.c
index 7067a02..a40fcba 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.c
+++ b/drivers/staging/brcm80211/brcmsmac/main.c
@@ -167,23 +167,21 @@

#define BRCMS_HWRXOFF 38 /* chip rx buffer offset */

-/*
- * driver maintains internal 'tick'(wlc->pub->now) which increments in 1s
- * OS timer(soft watchdog) it is not a wall clock and won't increment when
- * driver is in "down" state this low resolution driver tick can be used
- * for maintenance tasks such as phy calibration and scb update
- */
-
-#define BRCMS_WAR16165(wlc) (wlc->war16165)
-
/* Find basic rate for a given rate */
-#define BRCMS_BASIC_RATE(wlc, rspec) \
- (IS_MCS(rspec) \
- ? (wlc)->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK].leg_ofdm] \
- : (wlc)->band->basic_rate[rspec & RSPEC_RATE_MASK])
+static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
+{
+ if (IS_MCS(rspec))
+ return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
+ .leg_ofdm];
+ return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
+}

-#define FRAMETYPE(r, mimoframe) \
- (IS_MCS(r) ? mimoframe : (IS_CCK(r) ? FT_CCK : FT_OFDM))
+static u16 frametype(u32 rspec, u8 mimoframe)
+{
+ if (IS_MCS(rspec))
+ return mimoframe;
+ return IS_CCK(rspec) ? FT_CCK : FT_OFDM;
+}

/* rfdisable delay timer 500 ms, runs of ALP clock */
#define RFDISABLE_DEFAULT 10000000
@@ -240,11 +238,6 @@

#define FRAGNUM_MASK 0xF

-#define DMAREG(wlc_hw, direction, fifonum) \
- ((direction == DMA_TX) ? \
- &(wlc_hw->regs->fifo64regs[fifonum].dmaxmt) : \
- &(wlc_hw->regs->fifo64regs[fifonum].dmarcv))
-
#define APHY_SLOT_TIME 9
#define BPHY_SLOT_TIME 20

@@ -359,21 +352,11 @@
#define END_FOREACH_BSS() }

/* currently the best mechanism for determining SIFS is the band in use */
-#define SIFS(band) ((band)->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME : \
- BPHY_SIFS_TIME);
-
-/* A fifo is full. Clear precedences related to that FIFO */
-#define BRCMS_TX_FIFO_CLEAR(wlc, fifo) \
- ((wlc)->tx_prec_map &= ~(wlc)->fifo2prec_map[fifo])
-
-/* Fifo is NOT full. Enable precedences for that FIFO */
-#define BRCMS_TX_FIFO_ENAB(wlc, fifo) \
- ((wlc)->tx_prec_map |= (wlc)->fifo2prec_map[fifo])
-
-#define BRCMS_PORTOPEN(cfg) true
-
-#define brcms_b_copyfrom_shm(wlc_hw, offset, buf, len) \
- brcms_b_copyfrom_objmem(wlc_hw, offset, buf, len, OBJADDR_SHM_SEL)
+static u16 get_sifs(struct brcms_band *band)
+{
+ return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME :
+ BPHY_SIFS_TIME;
+}

/*
* Detect Card removed.
@@ -384,45 +367,35 @@
* If clocks are present, call the sb routine which will figure out if the
* device is removed.
*/
-#define DEVICEREMOVED(wlc) \
- ((wlc->hw->clk) ? \
- ((R_REG(&wlc->hw->regs->maccontrol) & \
- (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN) : \
- (ai_deviceremoved(wlc->hw->sih)))
-
-#define BRCMS_WME_RETRY_SHORT_GET(wlc, ac) \
- GFIELD(wlc->wme_retries[ac], EDCF_SHORT)
-#define BRCMS_WME_RETRY_SFB_GET(wlc, ac) \
- GFIELD(wlc->wme_retries[ac], EDCF_SFB)
-#define BRCMS_WME_RETRY_LONG_GET(wlc, ac) \
- GFIELD(wlc->wme_retries[ac], EDCF_LONG)
-#define BRCMS_WME_RETRY_LFB_GET(wlc, ac) \
- GFIELD(wlc->wme_retries[ac], EDCF_LFB)
-
-#define BRCMS_WME_RETRY_SHORT_SET(wlc, ac, val) \
- (wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], EDCF_SHORT, val))
-#define BRCMS_WME_RETRY_SFB_SET(wlc, ac, val) \
- (wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], EDCF_SFB, val))
-#define BRCMS_WME_RETRY_LONG_SET(wlc, ac, val) \
- (wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], EDCF_LONG, val))
-#define BRCMS_WME_RETRY_LFB_SET(wlc, ac, val) \
- (wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], EDCF_LFB, val))
+static bool brcms_deviceremoved(struct brcms_c_info *wlc)
+{
+ if (!wlc->hw->clk)
+ return ai_deviceremoved(wlc->hw->sih);
+ return (R_REG(&wlc->hw->regs->maccontrol) &
+ (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN;
+}

/* sum the individual fifo tx pending packet counts */
-#define TXPKTPENDTOT(wlc) \
- ((wlc)->core->txpktpend[0] + (wlc)->core->txpktpend[1] + \
- (wlc)->core->txpktpend[2] + (wlc)->core->txpktpend[3])
-#define TXPKTPENDGET(wlc, fifo) ((wlc)->core->txpktpend[(fifo)])
-#define TXPKTPENDINC(wlc, fifo, val) ((wlc)->core->txpktpend[(fifo)] += (val))
-#define TXPKTPENDDEC(wlc, fifo, val) ((wlc)->core->txpktpend[(fifo)] -= (val))
-#define TXPKTPENDCLR(wlc, fifo) ((wlc)->core->txpktpend[(fifo)] = 0)
+static s16 brcms_txpktpendtot(struct brcms_c_info *wlc)
+{
+ return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] +
+ wlc->core->txpktpend[2] + wlc->core->txpktpend[3];
+}

-#define IS_MBAND_UNLOCKED(wlc) \
- ((wlc->pub->_nbands > 1) && !(wlc)->bandlocked)
+static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc)
+{
+ return wlc->pub->_nbands > 1 && !wlc->bandlocked;
+}

-#define CHSPEC_WLC_BW(chanspec) (CHSPEC_IS40(chanspec) ? BRCMS_40_MHZ : \
- CHSPEC_IS20(chanspec) ? BRCMS_20_MHZ : \
- BRCMS_10_MHZ)
+static int brcms_chspec_bw(u16 chanspec)
+{
+ if (CHSPEC_IS40(chanspec))
+ return BRCMS_40_MHZ;
+ if (CHSPEC_IS20(chanspec))
+ return BRCMS_20_MHZ;
+
+ return BRCMS_10_MHZ;
+}

/* dup state between BMAC(struct brcms_hardware) and HIGH(struct brcms_c_info)
driver */
@@ -973,7 +946,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
bool fatal = false;
struct wiphy *wiphy = wlc->wiphy;

- if (DEVICEREMOVED(wlc)) {
+ if (brcms_deviceremoved(wlc)) {
wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
__func__);
brcms_down(wlc->wl);
@@ -1086,6 +1059,14 @@ brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init)
}
}

+static struct dma64regs *
+dmareg(struct brcms_hardware *hw, uint direction, uint fifonum)
+{
+ if (direction == DMA_TX)
+ return &(hw->regs->fifo64regs[fifonum].dmaxmt);
+ return &(hw->regs->fifo64regs[fifonum].dmarcv);
+}
+
static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
{
uint i;
@@ -1110,8 +1091,8 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
* RX: RX_FIFO (RX data packets)
*/
wlc_hw->di[0] = dma_attach(name, wlc_hw->sih,
- (wme ? DMAREG(wlc_hw, DMA_TX, 0) :
- NULL), DMAREG(wlc_hw, DMA_RX, 0),
+ (wme ? dmareg(wlc_hw, DMA_TX, 0) :
+ NULL), dmareg(wlc_hw, DMA_RX, 0),
(wme ? NTXD : 0), NRXD,
RXBUFSZ, -1, NRXBUFPOST,
BRCMS_HWRXOFF, &brcm_msg_level);
@@ -1124,7 +1105,7 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
* RX: UNUSED
*/
wlc_hw->di[1] = dma_attach(name, wlc_hw->sih,
- DMAREG(wlc_hw, DMA_TX, 1), NULL,
+ dmareg(wlc_hw, DMA_TX, 1), NULL,
NTXD, 0, 0, -1, 0, 0,
&brcm_msg_level);
dma_attach_err |= (NULL == wlc_hw->di[1]);
@@ -1135,7 +1116,7 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
* RX: UNUSED
*/
wlc_hw->di[2] = dma_attach(name, wlc_hw->sih,
- DMAREG(wlc_hw, DMA_TX, 2), NULL,
+ dmareg(wlc_hw, DMA_TX, 2), NULL,
NTXD, 0, 0, -1, 0, 0,
&brcm_msg_level);
dma_attach_err |= (NULL == wlc_hw->di[2]);
@@ -1145,7 +1126,7 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
* (legacy) TX_CTL_FIFO (TX control & mgmt packets)
*/
wlc_hw->di[3] = dma_attach(name, wlc_hw->sih,
- DMAREG(wlc_hw, DMA_TX, 3),
+ dmareg(wlc_hw, DMA_TX, 3),
NULL, NTXD, 0, 0, -1,
0, 0, &brcm_msg_level);
dma_attach_err |= (NULL == wlc_hw->di[3]);
@@ -2567,7 +2548,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
* Read and clear macintmask and macintstatus and intstatus registers.
* This routine should be called with interrupts off
* Return:
- * -1 if DEVICEREMOVED(wlc) evaluates to true;
+ * -1 if brcms_deviceremoved(wlc) evaluates to true;
* 0 if the interrupt is not for us, or we are in some special cases;
* device interrupt status bits otherwise.
*/
@@ -2584,10 +2565,10 @@ static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr)
macintstatus);

/* detect cardbus removed, in power down(suspend) and in reset */
- if (DEVICEREMOVED(wlc))
+ if (brcms_deviceremoved(wlc))
return -1;

- /* DEVICEREMOVED succeeds even when the core is still resetting,
+ /* brcms_deviceremoved() succeeds even when the core is still resetting,
* handle that case here.
*/
if (macintstatus == 0xffffffff)
@@ -2916,7 +2897,7 @@ void brcms_c_coredisable(struct brcms_hardware *wlc_hw)

BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);

- dev_gone = DEVICEREMOVED(wlc_hw->wlc);
+ dev_gone = brcms_deviceremoved(wlc_hw->wlc);

if (dev_gone)
return;
@@ -2949,7 +2930,7 @@ static void brcms_c_flushqueues(struct brcms_c_info *wlc)
for (i = 0; i < NFIFO; i++)
if (wlc_hw->di[i]) {
dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL);
- TXPKTPENDCLR(wlc, i);
+ wlc->core->txpktpend[i] = 0;
BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i);
}

@@ -3131,7 +3112,7 @@ bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
* disallow PS when one of the following
* bsscfg specific conditions meets
*/
- if (!cfg->BSS || !BRCMS_PORTOPEN(cfg))
+ if (!cfg->BSS)
return false;

if (!cfg->dtim_programmed)
@@ -3147,7 +3128,7 @@ static void brcms_b_reset(struct brcms_hardware *wlc_hw)
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);

/* reset the core */
- if (!DEVICEREMOVED(wlc_hw->wlc))
+ if (!brcms_deviceremoved(wlc_hw->wlc))
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);

/* purge the dma rings */
@@ -3724,7 +3705,7 @@ void brcms_c_init(struct brcms_c_info *wlc)
* Initialize WME parameters; if they haven't been set by some other
* mechanism (IOVar, etc) then read them from the hardware.
*/
- if (BRCMS_WME_RETRY_SHORT_GET(wlc, 0) == 0) {
+ if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) {
/* Uninitialized; read from HW */
int ac;

@@ -3987,16 +3968,14 @@ void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
brcms_c_set_phy_chanspec(wlc, chanspec);

/* init antenna selection */
- if (CHSPEC_WLC_BW(old_chanspec) != CHSPEC_WLC_BW(chanspec)) {
+ if (brcms_chspec_bw(old_chanspec) != brcms_chspec_bw(chanspec)) {
brcms_c_antsel_init(wlc->asi);

/* Fix the hardware rateset based on bw.
* Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz
*/
brcms_c_rateset_bw_mcs_filter(&wlc->band->hw_rateset,
- wlc->band->
- mimo_cap_40 ? CHSPEC_WLC_BW(chanspec)
- : 0);
+ wlc->band->mimo_cap_40 ? brcms_chspec_bw(chanspec) : 0);
}

/* update some mac configuration since chanspec changed */
@@ -4278,7 +4257,7 @@ static void brcms_c_radio_enable(struct brcms_c_info *wlc)
if (wlc->pub->up)
return;

- if (DEVICEREMOVED(wlc))
+ if (brcms_deviceremoved(wlc))
return;

brcms_up(wlc->wl);
@@ -4332,7 +4311,7 @@ static void brcms_c_radio_timer(void *arg)
{
struct brcms_c_info *wlc = (struct brcms_c_info *) arg;

- if (DEVICEREMOVED(wlc)) {
+ if (brcms_deviceremoved(wlc)) {
wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
__func__);
brcms_down(wlc->wl);
@@ -4380,7 +4359,7 @@ static void brcms_c_watchdog(void *arg)
if (!wlc->pub->up)
return;

- if (DEVICEREMOVED(wlc)) {
+ if (brcms_deviceremoved(wlc)) {
wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
__func__);
brcms_down(wlc->wl);
@@ -4564,8 +4543,6 @@ struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc)
return wlc->pub;
}

-#define CHIP_SUPPORTS_11N(wlc) 1
-
/* low level attach
* run backplane attach, init nvram
* run phy attach
@@ -5011,7 +4988,7 @@ static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
brcms_c_rateset_default(&bi->rateset, NULL, band->phytype,
band->bandtype, false, BRCMS_RATE_MASK_FULL,
(bool) (wlc->pub->_n_enab & SUPPORT_11N),
- CHSPEC_WLC_BW(chanspec), wlc->stf->txstreams);
+ brcms_chspec_bw(chanspec), wlc->stf->txstreams);

if (wlc->pub->_n_enab & SUPPORT_11N)
bi->flags |= BRCMS_BSS_HT;
@@ -5202,7 +5179,7 @@ brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
}

/* init _n_enab supported mode */
- if (BRCMS_PHY_11N_CAP(wlc->band) && CHIP_SUPPORTS_11N(wlc)) {
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
if (n_disabled & WLFEATURE_DISABLE_11N) {
pub->_n_enab = OFF;
brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,
@@ -5649,7 +5626,7 @@ int brcms_c_up(struct brcms_c_info *wlc)
BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);

/* HW is turned off so don't try to access it */
- if (wlc->pub->hw_off || DEVICEREMOVED(wlc))
+ if (wlc->pub->hw_off || brcms_deviceremoved(wlc))
return -ENOMEDIUM;

if (!wlc->pub->hw_up) {
@@ -5712,7 +5689,7 @@ int brcms_c_up(struct brcms_c_info *wlc)
/* Set EDCF hostflags */
brcms_c_mhf(wlc, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL);

- if (BRCMS_WAR16165(wlc))
+ if (wlc->war16165)
brcms_c_mhf(wlc, MHF2, MHF2_PCISLOWCLKWAR, MHF2_PCISLOWCLKWAR,
BRCM_BAND_ALL);

@@ -5760,7 +5737,7 @@ static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
if (!wlc_hw->up)
return callbacks;

- dev_gone = DEVICEREMOVED(wlc_hw->wlc);
+ dev_gone = brcms_deviceremoved(wlc_hw->wlc);

/* disable interrupts */
if (dev_gone)
@@ -5791,7 +5768,7 @@ static int brcms_b_down_finish(struct brcms_hardware *wlc_hw)
wlc_hw->up = false;
wlc_phy_hw_state_upd(wlc_hw->band->pi, false);

- dev_gone = DEVICEREMOVED(wlc_hw->wlc);
+ dev_gone = brcms_deviceremoved(wlc_hw->wlc);

if (dev_gone) {
wlc_hw->sbclk = false;
@@ -5850,7 +5827,7 @@ uint brcms_c_down(struct brcms_c_info *wlc)

callbacks += brcms_b_bmac_down_prep(wlc->hw);

- dev_gone = DEVICEREMOVED(wlc);
+ dev_gone = brcms_deviceremoved(wlc);

/* Call any registered down handlers */
for (i = 0; i < BRCMS_MAXMODULES; i++) {
@@ -6099,7 +6076,7 @@ brcms_c_set_internal_rateset(struct brcms_c_info *wlc,
goto good;

/* try the other band */
- if (IS_MBAND_UNLOCKED(wlc)) {
+ if (brcms_is_mband_unlocked(wlc)) {
bandunit = OTHERBANDUNIT(wlc);
memcpy(&new, &rs, sizeof(struct brcms_c_rateset));
if (brcms_c_rate_hwrs_filter_sort_validate(&new,
@@ -6147,7 +6124,7 @@ int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
return -EINVAL;


- if (!wlc->pub->up && IS_MBAND_UNLOCKED(wlc)) {
+ if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) {
if (wlc->band->bandunit != chspec_bandunit(chspec))
wlc->bandinit_pending = true;
else
@@ -6180,8 +6157,10 @@ int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)
brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);

for (ac = 0; ac < AC_COUNT; ac++) {
- BRCMS_WME_RETRY_SHORT_SET(wlc, ac, srl);
- BRCMS_WME_RETRY_LONG_SET(wlc, ac, lrl);
+ wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],
+ EDCF_SHORT, wlc->SRL);
+ wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],
+ EDCF_LONG, wlc->LRL);
}
brcms_c_wme_retries_write(wlc);

@@ -6400,8 +6379,8 @@ void brcms_c_statsupd(struct brcms_c_info *wlc)
#endif /* BCMDBG */

/* Read mac stats from contiguous shared memory */
- brcms_b_copyfrom_shm(wlc->hw, M_UCODE_MACSTAT,
- &macstats, sizeof(struct macstat));
+ brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats,
+ sizeof(struct macstat), OBJADDR_SHM_SEL);

#ifdef BCMDBG
/* check for rx fifo 0 overflow */
@@ -6719,7 +6698,7 @@ brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec,
* is less than or equal to the rate of the immediately previous
* frame in the FES
*/
- rspec = BRCMS_BASIC_RATE(wlc, rspec);
+ rspec = brcms_basic_rate(wlc, rspec);
/* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */
dur =
brcms_c_calc_frame_time(wlc, rspec, preamble_type,
@@ -6747,7 +6726,7 @@ brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec,
* is less than or equal to the rate of the immediately previous
* frame in the FES
*/
- rspec = BRCMS_BASIC_RATE(wlc, rspec);
+ rspec = brcms_basic_rate(wlc, rspec);
/* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */
return brcms_c_calc_frame_time(wlc, rspec, preamble_type,
(DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +
@@ -6770,7 +6749,7 @@ brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate,
{
u16 dur, sifs;

- sifs = SIFS(wlc->band);
+ sifs = get_sifs(wlc->band);

dur = sifs;
dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type);
@@ -7140,7 +7119,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
* Is the phy configured to use 40MHZ frames? If
* so then pick the desired txbw
*/
- if (CHSPEC_WLC_BW(wlc->chanspec) == BRCMS_40_MHZ) {
+ if (brcms_chspec_bw(wlc->chanspec) == BRCMS_40_MHZ) {
/* default txbw is 20in40 SB */
mimo_ctlchbw = mimo_txbw =
CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
@@ -7458,15 +7437,15 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
txh->MainRates = cpu_to_le16(mainrates);

/* XtraFrameTypes */
- xfts = FRAMETYPE(rspec[1], wlc->mimoft);
- xfts |= (FRAMETYPE(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
- xfts |= (FRAMETYPE(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
+ xfts = frametype(rspec[1], wlc->mimoft);
+ xfts |= (frametype(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
+ xfts |= (frametype(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
xfts |= CHSPEC_CHANNEL(wlc_phy_chanspec_get(wlc->band->pi)) <<
XFTS_CHANNEL_SHIFT;
txh->XtraFrameTypes = cpu_to_le16(xfts);

/* PhyTxControlWord */
- phyctl = FRAMETYPE(rspec[0], wlc->mimoft);
+ phyctl = frametype(rspec[0], wlc->mimoft);
if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) ||
(preamble_type[0] == BRCMS_GF_PREAMBLE)) {
if (RSPEC2RATE(rspec[0]) != BRCM_RATE_1M)
@@ -7707,7 +7686,7 @@ brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
if (fifo == TX_BCMC_FIFO)
frameid = le16_to_cpu(txh->TxFrameID);

- if (BRCMS_WAR16165(wlc))
+ if (wlc->war16165)
brcms_c_war16165(wlc, true);


@@ -7716,9 +7695,9 @@ brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
* used, this will be handled in brcms_b_txfifo()
*/
if (commit) {
- TXPKTPENDINC(wlc, fifo, txpktpend);
+ wlc->core->txpktpend[fifo] += txpktpend;
BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n",
- txpktpend, TXPKTPENDGET(wlc, fifo));
+ txpktpend, wlc->core->txpktpend[fifo]);
}

/* Commit BCMC sequence number in the SHM frame ID location */
@@ -7867,7 +7846,7 @@ brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
{
u16 dur, sifs;

- sifs = SIFS(wlc->band);
+ sifs = get_sifs(wlc->band);

if (!cts_only) {
/* RTS/CTS */
@@ -7955,19 +7934,19 @@ brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
rts_rspec = rspec;
else if (wlc->band->gmode && wlc->protection->_g && !IS_CCK(rspec))
/* Use 11Mbps as the g protection RTS target rate and fallback.
- * Use the BRCMS_BASIC_RATE() lookup to find the best basic rate
+ * Use the brcms_basic_rate() lookup to find the best basic rate
* under the target in case 11 Mbps is not Basic.
* 6 and 9 Mbps are not usually selected by rate selection, but
* even if the OFDM rate we are protecting is 6 or 9 Mbps, 11
* is more robust.
*/
- rts_rspec = BRCMS_BASIC_RATE(wlc, BRCM_RATE_11M);
+ rts_rspec = brcms_basic_rate(wlc, BRCM_RATE_11M);
else
/* calculate RTS rate and fallback rate based on the frame rate
* RTS must be sent at a basic rate since it is a
* control frame, sec 9.6 of 802.11 spec
*/
- rts_rspec = BRCMS_BASIC_RATE(wlc, rspec);
+ rts_rspec = brcms_basic_rate(wlc, rspec);

if (BRCMS_PHY_11N_CAP(wlc->band)) {
/* set rts txbw to correct side band */
@@ -8043,7 +8022,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs, u32 frm_tx2)
}

p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
- if (BRCMS_WAR16165(wlc))
+ if (wlc->war16165)
brcms_c_war16165(wlc, false);
if (p == NULL)
goto fatal;
@@ -8103,8 +8082,10 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs, u32 frm_tx2)
fbl;

if (queue < AC_COUNT) {
- sfbl = BRCMS_WME_RETRY_SFB_GET(wlc, wme_fifo2ac[queue]);
- lfbl = BRCMS_WME_RETRY_LFB_GET(wlc, wme_fifo2ac[queue]);
+ sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
+ EDCF_SFB);
+ lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
+ EDCF_LFB);
} else {
sfbl = wlc->SFBL;
lfbl = wlc->LFBL;
@@ -8179,12 +8160,12 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs, u32 frm_tx2)
void
brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend)
{
- TXPKTPENDDEC(wlc, fifo, txpktpend);
+ wlc->core->txpktpend[fifo] -= txpktpend;
BCMMSG(wlc->wiphy, "pktpend dec %d to %d\n", txpktpend,
- TXPKTPENDGET(wlc, fifo));
+ wlc->core->txpktpend[fifo]);

/* There is more room; mark precedences related to this FIFO sendable */
- BRCMS_TX_FIFO_ENAB(wlc, fifo);
+ wlc->tx_prec_map |= wlc->fifo2prec_map[fifo];

/* figure out which bsscfg is being worked on... */
}
@@ -8774,10 +8755,10 @@ void brcms_c_set_ratetable(struct brcms_c_info *wlc)
for (i = 0; i < rs.count; i++) {
rate = rs.rates[i] & BRCMS_RATE_MASK;

- /* for a given rate BRCMS_BASIC_RATE returns the rate at
+ /* for a given rate brcms_basic_rate returns the rate at
* which a response ACK/CTS should be sent.
*/
- basic_rate = BRCMS_BASIC_RATE(wlc, rate);
+ basic_rate = brcms_basic_rate(wlc, rate);
if (basic_rate == 0)
/* This should only happen if we are using a
* restricted rateset.
@@ -8835,7 +8816,7 @@ void brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
u16 dur, sifs;
uint i;

- sifs = SIFS(wlc->band);
+ sifs = get_sifs(wlc->band);

rs_dflt = brcms_c_rateset_get_hwrs(wlc);

@@ -9124,7 +9105,8 @@ int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop)
/* return if insufficient dma resources */
if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) {
/* Mark precedences related to this FIFO, unsendable */
- BRCMS_TX_FIFO_CLEAR(wlc, fifo);
+ /* A fifo is full. Clear precedences related to that FIFO */
+ wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]);
return -EBUSY;
}
return 0;
@@ -9153,7 +9135,7 @@ void brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs)
brcms_c_rateset_default(rs, NULL, wlc->band->phytype,
wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL,
(bool) (wlc->pub->_n_enab & SUPPORT_11N),
- CHSPEC_WLC_BW(wlc->default_bss->chanspec),
+ brcms_chspec_bw(wlc->default_bss->chanspec),
wlc->stf->txstreams);
}

@@ -9389,8 +9371,7 @@ void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL);

/* wait for queue and DMA fifos to run dry */
- while (!pktq_empty(&wlc->pkt_queue->q) ||
- TXPKTPENDTOT(wlc) > 0)
+ while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0)
brcms_msleep(wlc->wl, 1);
}

--
1.7.4.1



2011-09-13 07:50:22

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 15/17] staging: brcm80211: cleaned up function brcmf_cfg80211_get_key()

Unnecessary endianess conversion and struct member setting was deleted.

Reviewed-by: Arend van Spriel <[email protected]>
Reviewed-by: Franky Lin <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 17 -----------------
1 files changed, 0 insertions(+), 17 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
index b001e40..926b019 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
@@ -258,17 +258,6 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key)
key->iv_initialized = cpu_to_le32(key->iv_initialized);
}

-static void convert_key_to_CPU(struct brcmf_wsec_key *key)
-{
- key->index = le32_to_cpu(key->index);
- key->len = le32_to_cpu(key->len);
- key->algo = le32_to_cpu(key->algo);
- key->flags = le32_to_cpu(key->flags);
- key->rxiv.hi = le32_to_cpu(key->rxiv.hi);
- key->rxiv.lo = le16_to_cpu(key->rxiv.lo);
- key->iv_initialized = le32_to_cpu(key->iv_initialized);
-}
-
static s32
brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
{
@@ -1722,7 +1711,6 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
void (*callback) (void *cookie, struct key_params * params))
{
struct key_params params;
- struct brcmf_wsec_key key;
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
struct brcmf_cfg80211_security *sec;
s32 wsec;
@@ -1733,12 +1721,7 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
if (!check_sys_up(wiphy))
return -EIO;

- memset(&key, 0, sizeof(key));
- key.index = key_idx;
- convert_key_to_CPU(&key);
memset(&params, 0, sizeof(params));
- params.key_len = (u8) min_t(u8, WLAN_MAX_KEY_LEN, key.len);
- memcpy(params.key, key.data, params.key_len);

err = brcmf_dev_ioctl(dev, BRCMF_C_GET_WSEC, &wsec, sizeof(wsec));
if (unlikely(err)) {
--
1.7.4.1



2011-09-15 15:17:00

by Roland Vossen

[permalink] [raw]
Subject: Re: [PATCH 02/17] staging: brcm80211: remove ioctl layer from brcmsmac

Greg, please drop this particular [02/17] patch. I will send a new one.

Hello Dan,

>> + if (!error)
> ^^^^^^
> This test is reversed so this will fill your log with spam.

You are right. Will sent out a new patch today.

Thanks for the sharp eye,

Roland.


2011-09-13 07:50:18

by Roland Vossen

[permalink] [raw]
Subject: [PATCH 05/17] staging: brcm80211: macro cleanup in softmac dma

Substituted macro's by functions. Renamed several struct members in dma.c
to get rid of a set of macro's.

Reported-by: Johannes Berg <[email protected]>
Reviewed-by: Arend van Spriel <[email protected]>
Signed-off-by: Roland Vossen <[email protected]>
---
drivers/staging/brcm80211/brcmsmac/dma.c | 139 +++++++++++++++++-------------
1 files changed, 80 insertions(+), 59 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/dma.c b/drivers/staging/brcm80211/brcmsmac/dma.c
index 63e5e0e..6c9b1fe 100644
--- a/drivers/staging/brcm80211/brcmsmac/dma.c
+++ b/drivers/staging/brcm80211/brcmsmac/dma.c
@@ -155,9 +155,6 @@
#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 /* no. of descriptors used - 1 */
#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */

-#define DMA64_DD_PARITY(dd) \
- parity32((dd)->addrlow ^ (dd)->addrhigh ^ (dd)->ctrl1 ^ (dd)->ctrl2)
-
/*
* packet headroom necessary to accommodate the largest header
* in the system, (i.e TXOFF). By doing, we avoid the need to
@@ -192,27 +189,8 @@

#define DMA_NONE(args)

-#define d64txregs dregs.d64_u.txregs_64
-#define d64rxregs dregs.d64_u.rxregs_64
-#define txd64 dregs.d64_u.txd_64
-#define rxd64 dregs.d64_u.rxd_64
-
#define MAXNAMEL 8 /* 8 char names */

-/* descriptor bumping macros */
-/* faster than %, but n must be power of 2 */
-#define XXD(x, n) ((x) & ((n) - 1))
-
-#define TXD(x) XXD((x), di->ntxd)
-#define RXD(x) XXD((x), di->nrxd)
-#define NEXTTXD(i) TXD((i) + 1)
-#define PREVTXD(i) TXD((i) - 1)
-#define NEXTRXD(i) RXD((i) + 1)
-#define PREVRXD(i) RXD((i) - 1)
-
-#define NTXDACTIVE(h, t) TXD((t) - (h))
-#define NRXDACTIVE(h, t) RXD((t) - (h))
-
/* macros to convert between byte offsets and indexes */
#define B2I(bytes, type) ((bytes) / sizeof(type))
#define I2B(index, type) ((index) * sizeof(type))
@@ -245,18 +223,14 @@ struct dma_info {
bool dma64; /* this dma engine is operating in 64-bit mode */
bool addrext; /* this dma engine supports DmaExtendedAddrChanges */

- union {
- struct {
- /* 64-bit dma tx engine registers */
- struct dma64regs *txregs_64;
- /* 64-bit dma rx engine registers */
- struct dma64regs *rxregs_64;
- /* pointer to dma64 tx descriptor ring */
- struct dma64desc *txd_64;
- /* pointer to dma64 rx descriptor ring */
- struct dma64desc *rxd_64;
- } d64_u;
- } dregs;
+ /* 64-bit dma tx engine registers */
+ struct dma64regs *d64txregs;
+ /* 64-bit dma rx engine registers */
+ struct dma64regs *d64rxregs;
+ /* pointer to dma64 tx descriptor ring */
+ struct dma64desc *txd64;
+ /* pointer to dma64 rx descriptor ring */
+ struct dma64desc *rxd64;

u16 dmadesc_align; /* alignment requirement for dma descriptors */

@@ -320,6 +294,65 @@ struct dma_info {
*/
static uint dma_msg_level;

+/* Check for odd number of 1's */
+static u32 parity32(u32 data)
+{
+ data ^= data >> 16;
+ data ^= data >> 8;
+ data ^= data >> 4;
+ data ^= data >> 2;
+ data ^= data >> 1;
+
+ return data & 1;
+}
+
+static bool dma64_dd_parity(struct dma64desc *dd)
+{
+ return parity32(dd->addrlow ^ dd->addrhigh ^ dd->ctrl1 ^ dd->ctrl2);
+}
+
+/* descriptor bumping functions */
+
+static uint xxd(uint x, uint n)
+{
+ return x & (n - 1); /* faster than %, but n must be power of 2 */
+}
+
+static uint txd(struct dma_info *di, uint x)
+{
+ return xxd(x, di->ntxd);
+}
+
+static uint rxd(struct dma_info *di, uint x)
+{
+ return xxd(x, di->nrxd);
+}
+
+static uint nexttxd(struct dma_info *di, uint i)
+{
+ return txd(di, i + 1);
+}
+
+static uint prevtxd(struct dma_info *di, uint i)
+{
+ return txd(di, i - 1);
+}
+
+static uint nextrxd(struct dma_info *di, uint i)
+{
+ return txd(di, i + 1);
+}
+
+static uint ntxdactive(struct dma_info *di, uint h, uint t)
+{
+ return txd(di, t-h);
+}
+
+static uint nrxdactive(struct dma_info *di, uint h, uint t)
+{
+ return rxd(di, t-h);
+}
+
static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags)
{
uint dmactrlflags = di->dma.dmactrlflags;
@@ -675,18 +708,6 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
return NULL;
}

-/* Check for odd number of 1's */
-static inline u32 parity32(u32 data)
-{
- data ^= data >> 16;
- data ^= data >> 8;
- data ^= data >> 4;
- data ^= data >> 2;
- data ^= data >> 1;
-
- return data & 1;
-}
-
static inline void
dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring,
dma_addr_t pa, uint outidx, u32 *flags, u32 bufcount)
@@ -713,7 +734,7 @@ dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring,
ddring[outidx].ctrl2 = cpu_to_le32(ctrl2);
}
if (di->dma.dmactrlflags & DMA_CTRL_PEN) {
- if (DMA64_DD_PARITY(&ddring[outidx]))
+ if (dma64_dd_parity(&ddring[outidx]))
ddring[outidx].ctrl2 =
cpu_to_le32(ctrl2 | D64_CTRL2_PARITY);
}
@@ -866,7 +887,7 @@ static struct sk_buff *dma64_getnextrxp(struct dma_info *di, bool forceall)
di->rxd64[i].addrlow = 0xdeadbeef;
di->rxd64[i].addrhigh = 0xdeadbeef;

- di->rxin = NEXTRXD(i);
+ di->rxin = nextrxd(di, i);

return rxp;
}
@@ -988,7 +1009,7 @@ bool dma_rxfill(struct dma_pub *pub)
rxin = di->rxin;
rxout = di->rxout;

- n = di->nrxpost - NRXDACTIVE(rxin, rxout);
+ n = di->nrxpost - nrxdactive(di, rxin, rxout);

DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));

@@ -1035,7 +1056,7 @@ bool dma_rxfill(struct dma_pub *pub)

dma64_dd_upd(di, di->rxd64, pa, rxout, &flags,
di->rxbufsize);
- rxout = NEXTRXD(rxout);
+ rxout = nextrxd(di, rxout);
}

di->rxout = rxout;
@@ -1237,7 +1258,7 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)
next = p->next;

/* return nonzero if out of tx descriptors */
- if (NEXTTXD(txout) == di->txin)
+ if (nexttxd(di, txout) == di->txin)
goto outoftxd;

if (len == 0)
@@ -1262,16 +1283,16 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)

dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);

- txout = NEXTTXD(txout);
+ txout = nexttxd(di, txout);
}

/* if last txd eof not set, fix it */
if (!(flags & D64_CTRL1_EOF))
- di->txd64[PREVTXD(txout)].ctrl1 =
+ di->txd64[prevtxd(di, txout)].ctrl1 =
cpu_to_le32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF);

/* save the packet */
- di->txp[PREVTXD(txout)] = p0;
+ di->txp[prevtxd(di, txout)] = p0;

/* bump the tx descriptor index */
di->txout = txout;
@@ -1282,7 +1303,7 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)
di->xmtptrbase + I2B(txout, struct dma64desc));

/* tx flow control */
- di->dma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
+ di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;

return 0;

@@ -1341,14 +1362,14 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
(active_desc - di->xmtptrbase) & D64_XS0_CD_MASK;
active_desc = B2I(active_desc, struct dma64desc);
if (end != active_desc)
- end = PREVTXD(active_desc);
+ end = prevtxd(di, active_desc);
}
}

if ((start == 0) && (end > di->txout))
goto bogus;

- for (i = start; i != end && !txp; i = NEXTTXD(i)) {
+ for (i = start; i != end && !txp; i = nexttxd(di, i)) {
dma_addr_t pa;
uint size;

@@ -1370,7 +1391,7 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
di->txin = i;

/* tx flow control */
- di->dma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
+ di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;

return txp;

@@ -1401,6 +1422,6 @@ void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
tx_info = (struct ieee80211_tx_info *)skb->cb;
(callback_fnc)(tx_info, arg_a);
}
- i = NEXTTXD(i);
+ i = nexttxd(di, i);
}
}
--
1.7.4.1