Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless

John says:

--------------------
I apologize for not having sent this sooner.  FWIW, I was in a car
somewhere between Illinois and North Carolina for most of the day
Sunday and Monday... :-)

This is (obviously) the last non-fix pull request for wireless bits
intended for 3.5.  It includes AP support for mwifiex, a variety of HCI
and other updates for NFC, some brcmfmac and brcmsmac refactoring,
a large batch of ssb and bcma updates, a batch of ath6kl updates,
some cfg80211 and mac80211 updates/refactoring from Johannes Berg,
a rather large collection of Bluetooth updates by way of Gustavo,
and a variety of other bits here and there.
--------------------

Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
David S. Miller 2012-05-22 16:07:23 -04:00
commit c3719a1ef5
173 changed files with 6618 additions and 5499 deletions

View file

@ -693,8 +693,8 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
ie, 2 + vif->ssid_len + beacon_ie_len,
0, GFP_KERNEL);
if (bss)
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
"cfg80211\n", bssid);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"added bss %pM to cfg80211\n", bssid);
kfree(ie);
} else
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
@ -882,6 +882,32 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
vif->sme_state = SME_DISCONNECTED;
}
static int ath6kl_set_probed_ssids(struct ath6kl *ar,
struct ath6kl_vif *vif,
struct cfg80211_ssid *ssids, int n_ssids)
{
u8 i;
if (n_ssids > MAX_PROBED_SSID_INDEX)
return -EINVAL;
for (i = 0; i < n_ssids; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
ssids[i].ssid_len ?
SPECIFIC_SSID_FLAG : ANY_SSID_FLAG,
ssids[i].ssid_len,
ssids[i].ssid);
}
/* Make sure no old entries are left behind */
for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
DISABLE_SSID_FLAG, 0, NULL);
}
return 0;
}
static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_scan_request *request)
{
@ -899,36 +925,25 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
if (!ar->usr_bss_filter) {
clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
ret = ath6kl_wmi_bssfilter_cmd(
ar->wmi, vif->fw_vif_idx,
(test_bit(CONNECTED, &vif->flags) ?
ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
ALL_BSS_FILTER, 0);
if (ret) {
ath6kl_err("couldn't set bss filtering\n");
return ret;
}
}
if (request->n_ssids && request->ssids[0].ssid_len) {
u8 i;
if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
for (i = 0; i < request->n_ssids; i++)
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
i + 1, SPECIFIC_SSID_FLAG,
request->ssids[i].ssid_len,
request->ssids[i].ssid);
}
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
request->n_ssids);
if (ret < 0)
return ret;
/* this also clears IE in fw if it's not set */
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_PROBE_REQ,
request->ie, request->ie_len);
if (ret) {
ath6kl_err("failed to set Probe Request appie for "
"scan");
ath6kl_err("failed to set Probe Request appie for scan");
return ret;
}
@ -945,8 +960,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
if (channels == NULL) {
ath6kl_warn("failed to set scan channels, "
"scan all channels");
ath6kl_warn("failed to set scan channels, scan all channels");
n_channels = 0;
}
@ -1018,6 +1032,20 @@ out:
vif->scan_req = NULL;
}
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
enum wmi_phy_mode mode)
{
enum nl80211_channel_type type;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"channel switch notify nw_type %d freq %d mode %d\n",
vif->nw_type, freq, mode);
type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
cfg80211_ch_switch_notify(vif->ndev, freq, type);
}
static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, bool pairwise,
const u8 *mac_addr,
@ -1111,9 +1139,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
ar->ap_mode_bkey.key_len = key->key_len;
memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
if (!test_bit(CONNECTED, &vif->flags)) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
"key configuration until AP mode has been "
"started\n");
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"Delay initial group key configuration until AP mode has been started\n");
/*
* The key will be set in ath6kl_connect_ap_mode() once
* the connected event is received from the target.
@ -1129,8 +1156,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
* the AP mode has properly started
* (ath6kl_install_statioc_wep_keys).
*/
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
"until AP mode has been started\n");
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"Delay WEP key configuration until AP mode has been started\n");
vif->wep_key_list[key_index].key_len = key->key_len;
memcpy(vif->wep_key_list[key_index].key, key->key,
key->key_len);
@ -1962,8 +1989,7 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
sizeof(discvr_pattern), discvr_offset,
discvr_pattern, discvr_mask);
if (ret) {
ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR "
"pattern\n");
ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
return ret;
}
}
@ -2031,6 +2057,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
u8 index = 0;
__be32 ips[MAX_IP_ADDRS];
/* The FW currently can't support multi-vif WoW properly. */
if (ar->num_vif > 1)
return -EIO;
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
@ -2044,6 +2074,13 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
return -EINVAL;
if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) {
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
vif->fw_vif_idx, false);
if (ret)
return ret;
}
/* Clear existing WOW patterns */
for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
@ -2147,8 +2184,8 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE);
if (ret) {
ath6kl_warn("Failed to configure host sleep mode for "
"wow resume: %d\n", ret);
ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
ret);
ar->state = ATH6KL_STATE_WOW;
return ret;
}
@ -2172,6 +2209,13 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
ar->state = ATH6KL_STATE_ON;
if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) {
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
vif->fw_vif_idx, true);
if (ret)
return ret;
}
netif_wake_queue(vif->ndev);
return 0;
@ -2186,8 +2230,10 @@ static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
if (!vif)
return -EIO;
if (!ath6kl_cfg80211_ready(vif))
if (!test_bit(WMI_READY, &ar->flag)) {
ath6kl_err("deepsleep failed as wmi is not ready\n");
return -EIO;
}
ath6kl_cfg80211_stop_all(ar);
@ -2447,6 +2493,24 @@ static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
band, htcap);
}
static int ath6kl_restore_htcap(struct ath6kl_vif *vif)
{
struct wiphy *wiphy = vif->ar->wiphy;
int band, ret = 0;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!wiphy->bands[band])
continue;
ret = ath6kl_set_htcap(vif, band,
wiphy->bands[band]->ht_cap.ht_supported);
if (ret)
return ret;
}
return ret;
}
static bool ath6kl_is_p2p_ie(const u8 *pos)
{
return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
@ -2568,28 +2632,34 @@ static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
/* skip element id and length */
rsn_ie += 2;
/* skip version, group cipher */
if (rsn_ie_len < 6)
/* skip version */
if (rsn_ie_len < 2)
return -EINVAL;
rsn_ie += 6;
rsn_ie_len -= 6;
rsn_ie += 2;
rsn_ie_len -= 2;
/* skip group cipher suite */
if (rsn_ie_len < 4)
return 0;
rsn_ie += 4;
rsn_ie_len -= 4;
/* skip pairwise cipher suite */
if (rsn_ie_len < 2)
return -EINVAL;
cnt = *((u16 *) rsn_ie);
return 0;
cnt = get_unaligned_le16(rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
/* skip akm suite */
if (rsn_ie_len < 2)
return -EINVAL;
cnt = *((u16 *) rsn_ie);
return 0;
cnt = get_unaligned_le16(rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
if (rsn_ie_len < 2)
return -EINVAL;
return 0;
memcpy(rsn_capab, rsn_ie, 2);
@ -2766,6 +2836,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
return res;
}
memcpy(&vif->profile, &p, sizeof(p));
res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
if (res < 0)
return res;
@ -2801,13 +2872,7 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
clear_bit(CONNECTED, &vif->flags);
/* Restore ht setting in firmware */
if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true))
return -EIO;
if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true))
return -EIO;
return 0;
return ath6kl_restore_htcap(vif);
}
static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -3081,7 +3146,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
struct ath6kl_vif *vif = netdev_priv(dev);
u16 interval;
int ret;
u8 i;
if (ar->state != ATH6KL_STATE_ON)
return -EIO;
@ -3089,29 +3153,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
if (vif->sme_state != SME_DISCONNECTED)
return -EBUSY;
/* The FW currently can't support multi-vif WoW properly. */
if (ar->num_vif > 1)
return -EIO;
ath6kl_cfg80211_scan_complete_event(vif, true);
for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
i, DISABLE_SSID_FLAG,
0, NULL);
}
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
request->n_ssids);
if (ret < 0)
return ret;
/* fw uses seconds, also make sure that it's >0 */
interval = max_t(u16, 1, request->interval / 1000);
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
interval, interval,
10, 0, 0, 0, 3, 0, 0, 0);
if (request->n_ssids && request->ssids[0].ssid_len) {
for (i = 0; i < request->n_ssids; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
i, SPECIFIC_SSID_FLAG,
request->ssids[i].ssid_len,
request->ssids[i].ssid);
}
}
vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_WOW_MODE_ENABLE,
@ -3271,8 +3329,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
ath6kl_warn("ath6kl_deep_sleep_enable: "
"wmi_powermode_cmd failed\n");
ath6kl_warn("ath6kl_deep_sleep_enable: wmi_powermode_cmd failed\n");
return;
}
@ -3352,6 +3409,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
vif->next_mode = nw_type;
vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
vif->bg_scan_period = 0;
vif->htcap.ht_enable = true;
memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
@ -3393,6 +3451,7 @@ err:
int ath6kl_cfg80211_init(struct ath6kl *ar)
{
struct wiphy *wiphy = ar->wiphy;
bool band_2gig = false, band_5gig = false, ht = false;
int ret;
wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
@ -3413,8 +3472,46 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
/* max num of ssids that can be probed during scanning */
wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
switch (ar->hw.cap) {
case WMI_11AN_CAP:
ht = true;
case WMI_11A_CAP:
band_5gig = true;
break;
case WMI_11GN_CAP:
ht = true;
case WMI_11G_CAP:
band_2gig = true;
break;
case WMI_11AGN_CAP:
ht = true;
case WMI_11AG_CAP:
band_2gig = true;
band_5gig = true;
break;
default:
ath6kl_err("invalid phy capability!\n");
return -EINVAL;
}
/*
* Even if the fw has HT support, advertise HT cap only when
* the firmware has support to override RSN capability, otherwise
* 4-way handshake would fail.
*/
if (!(ht &&
test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
ar->fw_capabilities))) {
ath6kl_band_2ghz.ht_cap.cap = 0;
ath6kl_band_2ghz.ht_cap.ht_supported = false;
ath6kl_band_5ghz.ht_cap.cap = 0;
ath6kl_band_5ghz.ht_cap.ht_supported = false;
}
if (band_2gig)
wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
if (band_5gig)
wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->cipher_suites = cipher_suites;
@ -3430,7 +3527,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
wiphy->wowlan.pattern_min_len = 1;
wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
wiphy->max_sched_scan_ssids = 10;
wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX;
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
WIPHY_FLAG_HAVE_AP_SME |
@ -3447,8 +3544,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
ar->wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
ret = wiphy_register(wiphy);
if (ret < 0) {

View file

@ -28,6 +28,8 @@ enum ath6kl_cfg_suspend_mode {
struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
enum nl80211_iftype type,
u8 fw_vif_idx, u8 nw_type);
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
enum wmi_phy_mode mode);
void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted);
void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,

View file

@ -126,9 +126,9 @@ struct ath6kl_fw_ie {
#define AR6003_HW_2_0_FIRMWARE_FILE "athwlan.bin.z77"
#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "athtcmd_ram.bin"
#define AR6003_HW_2_0_PATCH_FILE "data.patch.bin"
#define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
#define AR6003_HW_2_0_BOARD_DATA_FILE AR6003_HW_2_0_FW_DIR "/bdata.bin"
#define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.0/bdata.SD31.bin"
AR6003_HW_2_0_FW_DIR "/bdata.SD31.bin"
/* AR6003 3.0 definitions */
#define AR6003_HW_2_1_1_VERSION 0x30000582
@ -139,25 +139,33 @@ struct ath6kl_fw_ie {
#define AR6003_HW_2_1_1_UTF_FIRMWARE_FILE "utf.bin"
#define AR6003_HW_2_1_1_TESTSCRIPT_FILE "nullTestFlow.bin"
#define AR6003_HW_2_1_1_PATCH_FILE "data.patch.bin"
#define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
#define AR6003_HW_2_1_1_BOARD_DATA_FILE AR6003_HW_2_1_1_FW_DIR "/bdata.bin"
#define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
AR6003_HW_2_1_1_FW_DIR "/bdata.SD31.bin"
/* AR6004 1.0 definitions */
#define AR6004_HW_1_0_VERSION 0x30000623
#define AR6004_HW_1_0_FW_DIR "ath6k/AR6004/hw1.0"
#define AR6004_HW_1_0_FIRMWARE_FILE "fw.ram.bin"
#define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin"
#define AR6004_HW_1_0_BOARD_DATA_FILE AR6004_HW_1_0_FW_DIR "/bdata.bin"
#define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6004/hw1.0/bdata.DB132.bin"
AR6004_HW_1_0_FW_DIR "/bdata.DB132.bin"
/* AR6004 1.1 definitions */
#define AR6004_HW_1_1_VERSION 0x30000001
#define AR6004_HW_1_1_FW_DIR "ath6k/AR6004/hw1.1"
#define AR6004_HW_1_1_FIRMWARE_FILE "fw.ram.bin"
#define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin"
#define AR6004_HW_1_1_BOARD_DATA_FILE AR6004_HW_1_1_FW_DIR "/bdata.bin"
#define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6004/hw1.1/bdata.DB132.bin"
AR6004_HW_1_1_FW_DIR "/bdata.DB132.bin"
/* AR6004 1.2 definitions */
#define AR6004_HW_1_2_VERSION 0x300007e8
#define AR6004_HW_1_2_FW_DIR "ath6k/AR6004/hw1.2"
#define AR6004_HW_1_2_FIRMWARE_FILE "fw.ram.bin"
#define AR6004_HW_1_2_BOARD_DATA_FILE AR6004_HW_1_2_FW_DIR "/bdata.bin"
#define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \
AR6004_HW_1_2_FW_DIR "/bdata.bin"
/* Per STA data, used in AP mode */
#define STA_PS_AWAKE BIT(0)
@ -502,6 +510,8 @@ enum ath6kl_vif_state {
WLAN_ENABLED,
STATS_UPDATE_PEND,
HOST_SLEEP_MODE_CMD_PROCESSED,
NETDEV_MCAST_ALL_ON,
NETDEV_MCAST_ALL_OFF,
};
struct ath6kl_vif {
@ -549,9 +559,11 @@ struct ath6kl_vif {
u16 assoc_bss_beacon_int;
u16 listen_intvl_t;
u16 bmiss_time_t;
u16 bg_scan_period;
u8 assoc_bss_dtim_period;
struct net_device_stats net_stats;
struct target_stats target_stats;
struct wmi_connect_cmd profile;
struct list_head mc_filter;
};
@ -640,6 +652,7 @@ struct ath6kl {
u8 sta_list_index;
struct ath6kl_req_key ap_mode_bkey;
struct sk_buff_head mcastpsq;
u32 want_ch_switch;
/*
* FIXME: protects access to mcastpsq but is actually useless as
@ -672,6 +685,7 @@ struct ath6kl {
u32 refclk_hz;
u32 uarttx_pin;
u32 testscript_addr;
enum wmi_phy_cap cap;
struct ath6kl_hw_fw {
const char *dir;
@ -805,7 +819,8 @@ void aggr_reset_state(struct aggr_info_conn *aggr_conn);
struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr);
struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver);
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
enum wmi_phy_cap cap);
int ath6kl_control_tx(void *devt, struct sk_buff *skb,
enum htc_endpoint_id eid);
void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel,

View file

@ -401,8 +401,10 @@ static ssize_t ath6kl_fwlog_block_read(struct file *file,
ret = wait_for_completion_interruptible(
&ar->debug.fwlog_completion);
if (ret == -ERESTARTSYS)
if (ret == -ERESTARTSYS) {
vfree(buf);
return ret;
}
spin_lock(&ar->debug.fwlog_queue.lock);
}
@ -1570,10 +1572,15 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
struct ath6kl_vif *vif;
u16 bgscan_int;
char buf[32];
ssize_t len;
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
@ -1585,6 +1592,8 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file,
if (bgscan_int == 0)
bgscan_int = 0xffff;
vif->bg_scan_period = bgscan_int;
ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3,
0, 0, 0);
@ -1809,6 +1818,7 @@ int ath6kl_debug_init_fs(struct ath6kl *ar)
void ath6kl_debug_cleanup(struct ath6kl *ar)
{
skb_queue_purge(&ar->debug.fwlog_queue);
complete(&ar->debug.fwlog_completion);
kfree(ar->debug.roam_tbl);
}

View file

@ -83,10 +83,7 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
* never goes inactive EVER.
*/
cur_ep_dist->dist_flags |= HTC_EP_ACTIVE;
} else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC)
/* this is the lowest priority data endpoint */
/* FIXME: this looks fishy, check */
cred_info->lowestpri_ep_dist = cur_ep_dist->list;
}
/*
* Streams have to be created (explicit | implicit) for all
@ -100,6 +97,13 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
*/
}
/*
* For ath6kl_credit_seek function,
* it use list_for_each_entry_reverse to walk around the whole ep list.
* Therefore assign this lowestpri_ep_dist after walk around the ep_list
*/
cred_info->lowestpri_ep_dist = cur_ep_dist->list;
WARN_ON(cred_info->cur_free_credits <= 0);
list_for_each_entry(cur_ep_dist, ep_list, list) {
@ -758,7 +762,7 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
u32 txb_mask;
u8 ac = WMM_NUM_AC;
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) &&
(WMI_CONTROL_SVC != endpoint->svc_id))
ac = target->dev->ar->ep2ac_map[endpoint->eid];
@ -793,16 +797,17 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
* itself
*/
txb_mask = ((1 << ac) - 1);
/*
* when the scatter request resources drop below a
* certain threshold, disable Tx bundling for all
* AC's with priority lower than the current requesting
* AC. Otherwise re-enable Tx bundling for them
*/
if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS)
target->tx_bndl_mask &= ~txb_mask;
else
target->tx_bndl_mask |= txb_mask;
/*
* when the scatter request resources drop below a
* certain threshold, disable Tx bundling for all
* AC's with priority lower than the current requesting
* AC. Otherwise re-enable Tx bundling for them
*/
if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS)
target->tx_bndl_mask &= ~txb_mask;
else
target->tx_bndl_mask |= txb_mask;
}
ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n",
@ -849,6 +854,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
int bundle_sent;
int n_pkts_bundle;
u8 ac = WMM_NUM_AC;
int status;
spin_lock_bh(&target->tx_lock);
@ -866,7 +872,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
*/
INIT_LIST_HEAD(&txq);
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) &&
(WMI_CONTROL_SVC != endpoint->svc_id))
ac = target->dev->ar->ep2ac_map[endpoint->eid];
@ -910,7 +916,12 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags,
0, packet->info.tx.seqno);
ath6kl_htc_tx_issue(target, packet);
status = ath6kl_htc_tx_issue(target, packet);
if (status) {
packet->status = status;
packet->completion(packet->context, packet);
}
}
spin_lock_bh(&target->tx_lock);

View file

@ -108,8 +108,6 @@ static void get_htc_packet_credit_based(struct htc_target *target,
/* get packet at head, but don't remove it */
packet = list_first_entry(&ep->txq, struct htc_packet, list);
if (packet == NULL)
break;
ath6kl_dbg(ATH6KL_DBG_HTC,
"%s: got head packet:0x%p , queue depth: %d\n",
@ -803,8 +801,6 @@ static int htc_send_packets_multiple(struct htc_target *target,
/* get first packet to find out which ep the packets will go into */
packet = list_first_entry(pkt_queue, struct htc_packet, list);
if (packet == NULL)
return -EINVAL;
if (packet->endpoint >= ENDPOINT_MAX) {
WARN_ON_ONCE(1);
@ -1382,6 +1378,9 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target,
/* copy all the callbacks */
ep->ep_cb = conn_req->ep_cb;
/* initialize tx_drop_packet_threshold */
ep->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM;
status = ath6kl_hif_pipe_map_service(ar, ep->svc_id,
&ep->pipe.pipeid_ul,
&ep->pipe.pipeid_dl);
@ -1636,10 +1635,6 @@ static int ath6kl_htc_pipe_add_rxbuf_multiple(struct htc_target *target,
return -EINVAL;
first = list_first_entry(pkt_queue, struct htc_packet, list);
if (first == NULL) {
WARN_ON_ONCE(1);
return -EINVAL;
}
if (first->endpoint >= ENDPOINT_MAX) {
WARN_ON_ONCE(1);

View file

@ -119,6 +119,24 @@ static const struct ath6kl_hw hw_list[] = {
.fw_board = AR6004_HW_1_1_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
},
{
.id = AR6004_HW_1_2_VERSION,
.name = "ar6004 hw 1.2",
.dataset_patch_addr = 0x436ecc,
.app_load_addr = 0x1234,
.board_ext_data_addr = 0x437000,
.reserved_ram_size = 9216,
.board_addr = 0x435c00,
.refclk_hz = 40000000,
.uarttx_pin = 11,
.fw = {
.dir = AR6004_HW_1_2_FW_DIR,
.fw = AR6004_HW_1_2_FIRMWARE_FILE,
},
.fw_board = AR6004_HW_1_2_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE,
},
};
/*
@ -445,9 +463,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
P2P_FLAG_MACADDR_REQ |
P2P_FLAG_HMODEL_REQ);
if (ret) {
ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P "
"capabilities (%d) - assuming P2P not "
"supported\n", ret);
ath6kl_dbg(ATH6KL_DBG_TRC,
"failed to request P2P capabilities (%d) - assuming P2P not supported\n",
ret);
ar->p2p = false;
}
}
@ -456,8 +474,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
/* Enable Probe Request reporting for P2P */
ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true);
if (ret) {
ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe "
"Request reporting (%d)\n", ret);
ath6kl_dbg(ATH6KL_DBG_TRC,
"failed to enable Probe Request reporting (%d)\n",
ret);
}
}

View file

@ -421,8 +421,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
if (!ik->valid)
break;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for "
"the initial group key for AP mode\n");
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"Delayed addkey for the initial group key for AP mode\n");
memset(key_rsc, 0, sizeof(key_rsc));
res = ath6kl_wmi_addkey_cmd(
ar->wmi, vif->fw_vif_idx, ik->key_index, ik->key_type,
@ -430,12 +430,19 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
ik->key,
KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG);
if (res) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed "
"addkey failed: %d\n", res);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"Delayed addkey failed: %d\n", res);
}
break;
}
if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) {
ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
/* we actually don't know the phymode, default to HT20 */
ath6kl_cfg80211_ch_switch_notify(vif, channel,
WMI_11G_HT20);
}
ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
set_bit(CONNECTED, &vif->flags);
netif_carrier_on(vif->ndev);
@ -541,7 +548,8 @@ void ath6kl_disconnect(struct ath6kl_vif *vif)
/* WMI Event handlers */
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
enum wmi_phy_cap cap)
{
struct ath6kl *ar = devt;
@ -551,6 +559,7 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
ar->version.wlan_ver = sw_ver;
ar->version.abi_ver = abi_ver;
ar->hw.cap = cap;
snprintf(ar->wiphy->fw_version,
sizeof(ar->wiphy->fw_version),
@ -584,6 +593,45 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status);
}
static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
{
struct ath6kl *ar = vif->ar;
vif->next_chan = channel;
vif->profile.ch = cpu_to_le16(channel);
switch (vif->nw_type) {
case AP_NETWORK:
return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
&vif->profile);
default:
ath6kl_err("won't switch channels nw_type=%d\n", vif->nw_type);
return -ENOTSUPP;
}
}
static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
{
struct ath6kl_vif *vif;
int res = 0;
if (!ar->want_ch_switch)
return;
spin_lock_bh(&ar->list_lock);
list_for_each_entry(vif, &ar->vif_list, list) {
if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
res = ath6kl_commit_ch_switch(vif, channel);
if (res)
ath6kl_err("channel switch failed nw_type %d res %d\n",
vif->nw_type, res);
}
spin_unlock_bh(&ar->list_lock);
}
void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
u16 listen_int, u16 beacon_int,
enum network_type net_type, u8 beacon_ie_len,
@ -601,9 +649,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
memcpy(vif->bssid, bssid, sizeof(vif->bssid));
vif->bss_ch = channel;
if ((vif->nw_type == INFRA_NETWORK))
if ((vif->nw_type == INFRA_NETWORK)) {
ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
vif->listen_intvl_t, 0);
ath6kl_check_ch_switch(ar, channel);
}
netif_wake_queue(vif->ndev);
@ -926,6 +976,11 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
struct ath6kl *ar = vif->ar;
if (vif->nw_type == AP_NETWORK) {
/* disconnect due to other STA vif switching channels */
if (reason == BSS_DISCONNECTED &&
prot_reason_status == WMI_AP_REASON_STA_ROAM)
ar->want_ch_switch |= 1 << vif->fw_vif_idx;
if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
return;
@ -1090,7 +1145,7 @@ static int ath6kl_set_features(struct net_device *dev,
static void ath6kl_set_multicast_list(struct net_device *ndev)
{
struct ath6kl_vif *vif = netdev_priv(ndev);
bool mc_all_on = false, mc_all_off = false;
bool mc_all_on = false;
int mc_count = netdev_mc_count(ndev);
struct netdev_hw_addr *ha;
bool found;
@ -1102,24 +1157,41 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
!test_bit(WLAN_ENABLED, &vif->flags))
return;
/* Enable multicast-all filter. */
mc_all_on = !!(ndev->flags & IFF_PROMISC) ||
!!(ndev->flags & IFF_ALLMULTI) ||
!!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST);
mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0;
if (mc_all_on)
set_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
else
clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
if (mc_all_on || mc_all_off) {
/* Enable/disable all multicast */
ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n",
mc_all_on ? "enabling" : "disabling");
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
if (!(ndev->flags & IFF_MULTICAST)) {
mc_all_on = false;
set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
} else {
clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
}
/* Enable/disable "multicast-all" filter*/
ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n",
mc_all_on ? "enabling" : "disabling");
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
mc_all_on);
if (ret)
ath6kl_warn("Failed to %s multicast receive\n",
mc_all_on ? "enable" : "disable");
if (ret) {
ath6kl_warn("Failed to %s multicast-all receive\n",
mc_all_on ? "enable" : "disable");
return;
}
if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags))
return;
/* Keep the driver and firmware mcast list in sync. */
list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
found = false;
netdev_for_each_mc_addr(ha, ndev) {

View file

@ -552,7 +552,7 @@ static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
if (!bus_req)
if (WARN_ON_ONCE(!bus_req))
return -ENOMEM;
bus_req->address = address;
@ -915,6 +915,9 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
}
cut_pwr:
if (func->card && func->card->host)
func->card->host->pm_flags &= ~MMC_PM_KEEP_POWER;
return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL);
}
@ -985,9 +988,8 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
}
if (status) {
ath6kl_err("%s: failed to write initial bytes of 0x%x "
"to window reg: 0x%X\n", __func__,
addr, reg_addr);
ath6kl_err("%s: failed to write initial bytes of 0x%x to window reg: 0x%X\n",
__func__, addr, reg_addr);
return status;
}
@ -1076,8 +1078,8 @@ static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
(u8 *)&ar->bmi.cmd_credits, 4,
HIF_RD_SYNC_BYTE_INC);
if (ret) {
ath6kl_err("Unable to decrement the command credit "
"count register: %d\n", ret);
ath6kl_err("Unable to decrement the command credit count register: %d\n",
ret);
return ret;
}
@ -1457,3 +1459,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);

View file

@ -362,15 +362,11 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
skb, skb->data, skb->len);
/* If target is not associated */
if (!test_bit(CONNECTED, &vif->flags)) {
dev_kfree_skb(skb);
return 0;
}
if (!test_bit(CONNECTED, &vif->flags))
goto fail_tx;
if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) {
dev_kfree_skb(skb);
return 0;
}
if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON))
goto fail_tx;
if (!test_bit(WMI_READY, &ar->flag))
goto fail_tx;

View file

@ -1037,6 +1037,14 @@ static void ath6kl_usb_stop(struct ath6kl *ar)
hif_stop(ar);
}
static void ath6kl_usb_cleanup_scatter(struct ath6kl *ar)
{
/*
* USB doesn't support it. Just return.
*/
return;
}
static const struct ath6kl_hif_ops ath6kl_usb_ops = {
.diag_read32 = ath6kl_usb_diag_read32,
.diag_write32 = ath6kl_usb_diag_write32,
@ -1049,6 +1057,7 @@ static const struct ath6kl_hif_ops ath6kl_usb_ops = {
.pipe_get_default = ath6kl_usb_get_default_pipe,
.pipe_map_service = ath6kl_usb_map_service_pipe,
.pipe_get_free_queue_number = ath6kl_usb_get_free_queue_number,
.cleanup_scatter = ath6kl_usb_cleanup_scatter,
};
/* ath6kl usb driver registered functions */
@ -1207,3 +1216,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);

View file

@ -16,6 +16,7 @@
*/
#include <linux/ip.h>
#include <linux/in.h>
#include "core.h"
#include "debug.h"
#include "testmode.h"
@ -289,6 +290,13 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
layer2_priority);
} else
usr_pri = layer2_priority & 0x7;
/*
* Queue the EAPOL frames in the same WMM_AC_VO queue
* as that of management frames.
*/
if (skb->protocol == cpu_to_be16(ETH_P_PAE))
usr_pri = WMI_VOICE_USER_PRIORITY;
}
/*
@ -460,8 +468,9 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
freq, dur);
chan = ieee80211_get_channel(ar->wiphy, freq);
if (!chan) {
ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel "
"(freq=%u)\n", freq);
ath6kl_dbg(ATH6KL_DBG_WMI,
"remain_on_chnl: Unknown channel (freq=%u)\n",
freq);
return -EINVAL;
}
id = vif->last_roc_id;
@ -488,12 +497,14 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
ev = (struct wmi_cancel_remain_on_chnl_event *) datap;
freq = le32_to_cpu(ev->freq);
dur = le32_to_cpu(ev->duration);
ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u "
"status=%u\n", freq, dur, ev->status);
ath6kl_dbg(ATH6KL_DBG_WMI,
"cancel_remain_on_chnl: freq=%u dur=%u status=%u\n",
freq, dur, ev->status);
chan = ieee80211_get_channel(ar->wiphy, freq);
if (!chan) {
ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown "
"channel (freq=%u)\n", freq);
ath6kl_dbg(ATH6KL_DBG_WMI,
"cancel_remain_on_chnl: Unknown channel (freq=%u)\n",
freq);
return -EINVAL;
}
if (vif->last_cancel_roc_id &&
@ -548,12 +559,12 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
freq = le32_to_cpu(ev->freq);
dlen = le16_to_cpu(ev->len);
if (datap + len < ev->data + dlen) {
ath6kl_err("invalid wmi_p2p_rx_probe_req_event: "
"len=%d dlen=%u\n", len, dlen);
ath6kl_err("invalid wmi_p2p_rx_probe_req_event: len=%d dlen=%u\n",
len, dlen);
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u "
"probe_req_report=%d\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"rx_probe_req: len=%u freq=%u probe_req_report=%d\n",
dlen, freq, vif->probe_req_report);
if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
@ -592,8 +603,8 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
freq = le32_to_cpu(ev->freq);
dlen = le16_to_cpu(ev->len);
if (datap + len < ev->data + dlen) {
ath6kl_err("invalid wmi_rx_action_event: "
"len=%d dlen=%u\n", len, dlen);
ath6kl_err("invalid wmi_rx_action_event: len=%d dlen=%u\n",
len, dlen);
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
@ -687,7 +698,7 @@ static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,
le32_to_cpu(ev->sw_version),
le32_to_cpu(ev->abi_version));
le32_to_cpu(ev->abi_version), ev->phy_cap);
return 0;
}
@ -777,16 +788,15 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
/* AP mode start/STA connected event */
struct net_device *dev = vif->ndev;
if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) {
ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM "
"(AP started)\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"%s: freq %d bssid %pM (AP started)\n",
__func__, le16_to_cpu(ev->u.ap_bss.ch),
ev->u.ap_bss.bssid);
ath6kl_connect_ap_mode_bss(
vif, le16_to_cpu(ev->u.ap_bss.ch));
} else {
ath6kl_dbg(ATH6KL_DBG_WMI, "%s: aid %u mac_addr %pM "
"auth=%u keymgmt=%u cipher=%u apsd_info=%u "
"(STA connected)\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"%s: aid %u mac_addr %pM auth=%u keymgmt=%u cipher=%u apsd_info=%u (STA connected)\n",
__func__, ev->u.ap_sta.aid,
ev->u.ap_sta.mac_addr,
ev->u.ap_sta.auth,
@ -1229,8 +1239,9 @@ static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,
ev = (struct wmi_neighbor_report_event *) datap;
if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info)
> len) {
ath6kl_dbg(ATH6KL_DBG_WMI, "truncated neighbor event "
"(num=%d len=%d)\n", ev->num_neighbors, len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"truncated neighbor event (num=%d len=%d)\n",
ev->num_neighbors, len);
return -EINVAL;
}
for (i = 0; i < ev->num_neighbors; i++) {
@ -1814,12 +1825,14 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)
{
struct ieee80211_supported_band *sband;
struct sk_buff *skb;
struct wmi_begin_scan_cmd *sc;
s8 size;
s8 size, *supp_rates;
int i, band, ret;
struct ath6kl *ar = wmi->parent_dev;
int num_rates;
u32 ratemask;
size = sizeof(struct wmi_begin_scan_cmd);
@ -1846,10 +1859,13 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
sc->num_ch = num_chan;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband =
ar->wiphy->bands[band];
u32 ratemask = rates[band];
u8 *supp_rates = sc->supp_rates[band].rates;
sband = ar->wiphy->bands[band];
if (!sband)
continue;
ratemask = rates[band];
supp_rates = sc->supp_rates[band].rates;
num_rates = 0;
for (i = 0; i < sband->n_bitrates; i++) {
@ -2129,8 +2145,8 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,
struct wmi_add_cipher_key_cmd *cmd;
int ret;
ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d "
"key_usage=%d key_len=%d key_op_ctrl=%d\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"addkey cmd: key_index=%u key_type=%d key_usage=%d key_len=%d key_op_ctrl=%d\n",
key_index, key_type, key_usage, key_len, key_op_ctrl);
if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
@ -3047,8 +3063,8 @@ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx,
res = ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_CONFIG_COMMIT_CMDID,
NO_SYNC_WMIFLAG);
ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u "
"ctrl_flags=0x%x-> res=%d\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"%s: nw_type=%u auth_mode=%u ch=%u ctrl_flags=0x%x-> res=%d\n",
__func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch),
le32_to_cpu(p->ctrl_flags), res);
return res;
@ -3208,8 +3224,9 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
if (!skb)
return -ENOMEM;
ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u "
"ie_len=%u\n", mgmt_frm_type, ie_len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"set_appie_cmd: mgmt_frm_type=%u ie_len=%u\n",
mgmt_frm_type, ie_len);
p = (struct wmi_set_appie_cmd *) skb->data;
p->mgmt_frm_type = mgmt_frm_type;
p->ie_len = ie_len;
@ -3310,8 +3327,9 @@ static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id,
wmi->last_mgmt_tx_frame = buf;
wmi->last_mgmt_tx_frame_len = data_len;
ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
"len=%u\n", id, freq, wait, data_len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
id, freq, wait, data_len);
p = (struct wmi_send_action_cmd *) skb->data;
p->id = cpu_to_le32(id);
p->freq = cpu_to_le32(freq);
@ -3348,8 +3366,9 @@ static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id,
wmi->last_mgmt_tx_frame = buf;
wmi->last_mgmt_tx_frame_len = data_len;
ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
"len=%u\n", id, freq, wait, data_len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
id, freq, wait, data_len);
p = (struct wmi_send_mgmt_cmd *) skb->data;
p->id = cpu_to_le32(id);
p->freq = cpu_to_le32(freq);
@ -3402,8 +3421,9 @@ int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
if (!skb)
return -ENOMEM;
ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM "
"len=%u\n", freq, dst, data_len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"send_probe_response_cmd: freq=%u dst=%pM len=%u\n",
freq, dst, data_len);
p = (struct wmi_p2p_probe_response_cmd *) skb->data;
p->freq = cpu_to_le32(freq);
memcpy(p->destination_addr, dst, ETH_ALEN);

View file

@ -106,6 +106,8 @@ struct wmi_data_sync_bufs {
#define WMM_AC_VI 2 /* video */
#define WMM_AC_VO 3 /* voice */
#define WMI_VOICE_USER_PRIORITY 0x7
struct wmi {
u16 stream_exist_for_ac[WMM_NUM_AC];
u8 fat_pipe_exist;
@ -1151,6 +1153,7 @@ enum wmi_phy_mode {
WMI_11AG_MODE = 0x3,
WMI_11B_MODE = 0x4,
WMI_11GONLY_MODE = 0x5,
WMI_11G_HT20 = 0x6,
};
#define WMI_MAX_CHANNELS 32
@ -1416,6 +1419,16 @@ struct wmi_ready_event_2 {
u8 phy_cap;
} __packed;
/* WMI_PHY_CAPABILITY */
enum wmi_phy_cap {
WMI_11A_CAP = 0x01,
WMI_11G_CAP = 0x02,
WMI_11AG_CAP = 0x03,
WMI_11AN_CAP = 0x04,
WMI_11GN_CAP = 0x05,
WMI_11AGN_CAP = 0x06,
};
/* Connect Event */
struct wmi_connect_event {
union {
@ -1468,6 +1481,17 @@ enum wmi_disconnect_reason {
IBSS_MERGE = 0xe,
};
/* AP mode disconnect proto_reasons */
enum ap_disconnect_reason {
WMI_AP_REASON_STA_LEFT = 101,
WMI_AP_REASON_FROM_HOST = 102,
WMI_AP_REASON_COMM_TIMEOUT = 103,
WMI_AP_REASON_MAX_STA = 104,
WMI_AP_REASON_ACL = 105,
WMI_AP_REASON_STA_ROAM = 106,
WMI_AP_REASON_DFS_CHANNEL = 107,
};
#define ATH6KL_COUNTRY_RD_SHIFT 16
struct ath6kl_wmi_regdomain {

View file

@ -892,34 +892,6 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
}
static bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
{
struct ath9k_rtt_hist *hist;
u32 *table;
int i;
bool restore;
if (!ah->caldata)
return false;
hist = &ah->caldata->rtt_hist;
if (!hist->num_readings)
return false;
ar9003_hw_rtt_enable(ah);
ar9003_hw_rtt_set_mask(ah, 0x00);
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
continue;
table = &hist->table[i][hist->num_readings][0];
ar9003_hw_rtt_load_hist(ah, i, table);
}
restore = ar9003_hw_rtt_force_restore(ah);
ar9003_hw_rtt_disable(ah);
return restore;
}
static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@ -942,9 +914,10 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
if (!ar9003_hw_rtt_restore(ah, chan))
run_rtt_cal = true;
ath_dbg(common, CALIBRATE, "RTT restore %s\n",
run_rtt_cal ? "failed" : "succeed");
if (run_rtt_cal)
ath_dbg(common, CALIBRATE, "RTT calibration to be done\n");
}
run_agc_cal = run_rtt_cal;
if (run_rtt_cal) {
@ -1069,17 +1042,14 @@ skip_tx_iqcal:
#undef CL_TAB_ENTRY
if (run_rtt_cal && caldata) {
struct ath9k_rtt_hist *hist = &caldata->rtt_hist;
if (is_reusable && (hist->num_readings < RTT_HIST_MAX)) {
u32 *table;
if (is_reusable) {
if (!ath9k_hw_rfbus_req(ah))
ath_err(ath9k_hw_common(ah),
"Could not stop baseband\n");
else
ar9003_hw_rtt_fill_hist(ah);
hist->num_readings++;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
continue;
table = &hist->table[i][hist->num_readings][0];
ar9003_hw_rtt_fill_hist(ah, i, table);
}
ath9k_hw_rfbus_done(ah);
}
ar9003_hw_rtt_disable(ah);

View file

@ -756,7 +756,7 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (caldata) {
caldata->done_txiqcal_once = false;
caldata->done_txclcal_once = false;
caldata->rtt_hist.num_readings = 0;
caldata->rtt_done = false;
}
if (!ath9k_hw_init_cal(ah, chan))

View file

@ -15,6 +15,7 @@
*/
#include "hw.h"
#include "hw-ops.h"
#include "ar9003_phy.h"
#include "ar9003_rtt.h"
@ -69,7 +70,7 @@ bool ar9003_hw_rtt_force_restore(struct ath_hw *ah)
}
static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain,
u32 index, u32 data28)
u32 index, u32 data28)
{
u32 val;
@ -100,12 +101,21 @@ static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain,
RTT_ACCESS_TIMEOUT);
}
void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table)
void ar9003_hw_rtt_load_hist(struct ath_hw *ah)
{
int i;
int chain, i;
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
ar9003_hw_rtt_load_hist_entry(ah, chain, i, table[i]);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if (!(ah->rxchainmask & (1 << chain)))
continue;
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
ar9003_hw_rtt_load_hist_entry(ah, chain, i,
ah->caldata->rtt_table[chain][i]);
ath_dbg(ath9k_hw_common(ah), CALIBRATE,
"Load RTT value at idx %d, chain %d: 0x%x\n",
i, chain, ah->caldata->rtt_table[chain][i]);
}
}
}
static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
@ -128,27 +138,71 @@ static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
RTT_ACCESS_TIMEOUT))
return RTT_BAD_VALUE;
val = REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain));
val = MS(REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain)),
AR_PHY_RTT_SW_RTT_TABLE_DATA);
return val;
}
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table)
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
{
int i;
int chain, i;
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
table[i] = ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if (!(ah->rxchainmask & (1 << chain)))
continue;
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
ah->caldata->rtt_table[chain][i] =
ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
ath_dbg(ath9k_hw_common(ah), CALIBRATE,
"RTT value at idx %d, chain %d is: 0x%x\n",
i, chain, ah->caldata->rtt_table[chain][i]);
}
}
ah->caldata->rtt_done = true;
}
void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
{
int i, j;
int chain, i;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if (!(ah->rxchainmask & (1 << chain)))
continue;
for (j = 0; j < MAX_RTT_TABLE_ENTRY; j++)
ar9003_hw_rtt_load_hist_entry(ah, i, j, 0);
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
ar9003_hw_rtt_load_hist_entry(ah, chain, i, 0);
}
if (ah->caldata)
ah->caldata->rtt_done = false;
}
bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
{
bool restore;
if (!ah->caldata)
return false;
if (!ah->caldata->rtt_done)
return false;
ar9003_hw_rtt_enable(ah);
ar9003_hw_rtt_set_mask(ah, 0x10);
if (!ath9k_hw_rfbus_req(ah)) {
ath_err(ath9k_hw_common(ah), "Could not stop baseband\n");
restore = false;
goto fail;
}
ar9003_hw_rtt_load_hist(ah);
restore = ar9003_hw_rtt_force_restore(ah);
fail:
ath9k_hw_rfbus_done(ah);
ar9003_hw_rtt_disable(ah);
return restore;
}

View file

@ -21,8 +21,9 @@ void ar9003_hw_rtt_enable(struct ath_hw *ah);
void ar9003_hw_rtt_disable(struct ath_hw *ah);
void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask);
bool ar9003_hw_rtt_force_restore(struct ath_hw *ah);
void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table);
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table);
void ar9003_hw_rtt_load_hist(struct ath_hw *ah);
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah);
void ar9003_hw_rtt_clear_hist(struct ath_hw *ah);
bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan);
#endif

View file

@ -1702,10 +1702,10 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
* For AR9462, make sure that calibration data for
* re-using are present.
*/
if (AR_SREV_9462(ah) && (!ah->caldata ||
!ah->caldata->done_txiqcal_once ||
!ah->caldata->done_txclcal_once ||
!ah->caldata->rtt_hist.num_readings))
if (AR_SREV_9462(ah) && (ah->caldata &&
(!ah->caldata->done_txiqcal_once ||
!ah->caldata->done_txclcal_once ||
!ah->caldata->rtt_done)))
goto fail;
ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n",
@ -1941,7 +1941,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (caldata) {
caldata->done_txiqcal_once = false;
caldata->done_txclcal_once = false;
caldata->rtt_hist.num_readings = 0;
}
if (!ath9k_hw_init_cal(ah, chan))
return -EIO;

View file

@ -348,12 +348,6 @@ enum ath9k_int {
CHANNEL_HT40MINUS)
#define MAX_RTT_TABLE_ENTRY 6
#define RTT_HIST_MAX 3
struct ath9k_rtt_hist {
u32 table[AR9300_MAX_CHAINS][RTT_HIST_MAX][MAX_RTT_TABLE_ENTRY];
u8 num_readings;
};
#define MAX_IQCAL_MEASUREMENT 8
#define MAX_CL_TAB_ENTRY 16
@ -363,6 +357,7 @@ struct ath9k_hw_cal_data {
int32_t CalValid;
int8_t iCoff;
int8_t qCoff;
bool rtt_done;
bool paprd_done;
bool nfcal_pending;
bool nfcal_interference;
@ -373,8 +368,8 @@ struct ath9k_hw_cal_data {
u32 num_measures[AR9300_MAX_CHAINS];
int tx_corr_coeff[MAX_IQCAL_MEASUREMENT][AR9300_MAX_CHAINS];
u32 tx_clcal[AR9300_MAX_CHAINS][MAX_CL_TAB_ENTRY];
u32 rtt_table[AR9300_MAX_CHAINS][MAX_RTT_TABLE_ENTRY];
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
struct ath9k_rtt_hist rtt_hist;
};
struct ath9k_channel {

View file

@ -107,11 +107,9 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core)
dev->dma_dev = core->dma_dev;
dev->irq = core->irq;
/*
dev->board_vendor = core->bus->boardinfo.vendor;
dev->board_type = core->bus->boardinfo.type;
dev->board_rev = core->bus->boardinfo.rev;
*/
dev->board_rev = core->bus->sprom.board_rev;
dev->chip_id = core->bus->chipinfo.id;
dev->chip_rev = core->bus->chipinfo.rev;
@ -210,7 +208,7 @@ struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev)
dev->board_vendor = sdev->bus->boardinfo.vendor;
dev->board_type = sdev->bus->boardinfo.type;
dev->board_rev = sdev->bus->boardinfo.rev;
dev->board_rev = sdev->bus->sprom.board_rev;
dev->chip_id = sdev->bus->chip_id;
dev->chip_rev = sdev->bus->chip_rev;

View file

@ -1109,7 +1109,7 @@ static bool b43_dma_translation_in_low_word(struct b43_wldev *dev,
#ifdef CONFIG_B43_SSB
if (dev->dev->bus_type == B43_BUS_SSB &&
dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
!(dev->dev->sdev->bus->host_pci->is_pcie &&
!(pci_is_pcie(dev->dev->sdev->bus->host_pci) &&
ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64))
return 1;
#endif

View file

@ -5243,10 +5243,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
/* boardflags workarounds */
if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
bus->chip_id == 0x4301 && bus->sprom.board_rev == 0x74)
bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
bus->boardinfo.type == 0x4E && bus->sprom.board_rev > 0x40)
bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
if (bus->bustype == SSB_BUSTYPE_PCI) {
pdev = bus->host_pci;

View file

@ -1573,8 +1573,6 @@ static void b43legacy_request_firmware(struct work_struct *work)
const char *filename;
int err;
/* do dummy read */
ssb_read32(dev->dev, SSB_TMSHIGH);
if (!fw->ucode) {
if (rev == 2)
filename = "ucode2";
@ -3781,7 +3779,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus)
/* boardflags workarounds */
if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
bus->boardinfo.type == 0x4E &&
bus->boardinfo.rev > 0x40)
bus->sprom.board_rev > 0x40)
bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL;
}

View file

@ -408,7 +408,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
if (is_bcm_board_vendor(dev) &&
(dev->dev->bus->boardinfo.type == 0x0416) &&
(dev->dev->bus->boardinfo.rev == 0x0017))
(dev->dev->bus->sprom.board_rev == 0x0017))
return;
b43legacy_ilt_write(dev, 0x5001, 0x0002);
@ -424,7 +424,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
if (is_bcm_board_vendor(dev) &&
(dev->dev->bus->boardinfo.type == 0x0416) &&
(dev->dev->bus->boardinfo.rev == 0x0017))
(dev->dev->bus->sprom.board_rev == 0x0017))
return;
b43legacy_ilt_write(dev, 0x0401, 0x0002);

View file

@ -1998,7 +1998,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
if (phy->type == B43legacy_PHYTYPE_G) {
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421 &&
dev->dev->bus->boardinfo.rev >= 30)
dev->dev->bus->sprom.board_rev >= 30)
att = 3;
else if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x416)
@ -2008,7 +2008,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
} else {
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421 &&
dev->dev->bus->boardinfo.rev >= 30)
dev->dev->bus->sprom.board_rev >= 30)
att = 7;
else
att = 6;
@ -2018,7 +2018,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
if (phy->type == B43legacy_PHYTYPE_G) {
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421 &&
dev->dev->bus->boardinfo.rev >= 30)
dev->dev->bus->sprom.board_rev >= 30)
att = 3;
else if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type ==
@ -2052,9 +2052,9 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
}
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421) {
if (dev->dev->bus->boardinfo.rev < 0x43)
if (dev->dev->bus->sprom.board_rev < 0x43)
att = 2;
else if (dev->dev->bus->boardinfo.rev < 0x51)
else if (dev->dev->bus->sprom.board_rev < 0x51)
att = 3;
}
if (att == 0xFFFF)

View file

@ -85,18 +85,15 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
sdiodev->irq_wake = true;
/* must configure SDIO_CCCR_IENx to enable irq */
data = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_0,
SDIO_CCCR_IENx, &ret);
data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx,
data, &ret);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
/* redirect, configure ane enable io for interrupt signal */
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH)
data |= SDIO_SEPINT_ACT_HI;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
data, &ret);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
return 0;
}
@ -105,9 +102,8 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
brcmf_dbg(TRACE, "Entering\n");
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
0, NULL);
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx, 0, NULL);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
if (sdiodev->irq_wake) {
disable_irq_wake(sdiodev->irq);
@ -158,153 +154,147 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
}
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
int *err)
{
int status;
s32 retry = 0;
u8 data = 0;
do {
if (retry) /* wait for 1 ms till bus get settled down */
udelay(1000);
status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num,
addr, (u8 *) &data);
} while (status != 0
&& (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
if (err)
*err = status;
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
fnc_num, addr, data);
return data;
}
void
brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
u8 data, int *err)
{
int status;
s32 retry = 0;
do {
if (retry) /* wait for 1 ms till bus get settled down */
udelay(1000);
status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num,
addr, (u8 *) &data);
} while (status != 0
&& (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
if (err)
*err = status;
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
fnc_num, addr, data);
}
int
brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
{
int err = 0;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
(address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
if (!err)
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_SBADDRMID,
(address >> 16) & SBSDIO_SBADDRMID_MASK,
&err);
if (!err)
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_SBADDRHIGH,
(address >> 24) & SBSDIO_SBADDRHIGH_MASK,
&err);
int err = 0, i;
u8 addr[3];
s32 retry;
addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
for (i = 0; i < 3; i++) {
retry = 0;
do {
if (retry)
usleep_range(1000, 2000);
err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
&addr[i]);
} while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
if (err) {
brcmf_dbg(ERROR, "failed at addr:0x%0x\n",
SBSDIO_FUNC1_SBADDRLOW + i);
break;
}
}
return err;
}
u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size)
static int
brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
void *data, bool write)
{
int status;
u32 word = 0;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
u8 func_num, reg_size;
u32 bar;
s32 retry = 0;
int ret;
brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr);
if (bar0 != sdiodev->sbwad) {
if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0))
return 0xFFFFFFFF;
sdiodev->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1,
addr, &word, size);
sdiodev->regfail = (status != 0);
brcmf_dbg(INFO, "u32data = 0x%x\n", word);
/* if ok, return appropriately masked word */
if (status == 0) {
switch (size) {
case sizeof(u8):
return word & 0xff;
case sizeof(u16):
return word & 0xffff;
case sizeof(u32):
return word;
default:
sdiodev->regfail = true;
/*
* figure out how to read the register based on address range
* 0x00 ~ 0x7FF: function 0 CCCR and FBR
* 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
* The rest: function 1 silicon backplane core registers
*/
if ((addr & ~REG_F0_REG_MASK) == 0) {
func_num = SDIO_FUNC_0;
reg_size = 1;
} else if ((addr & ~REG_F1_MISC_MASK) == 0) {
func_num = SDIO_FUNC_1;
reg_size = 1;
} else {
func_num = SDIO_FUNC_1;
reg_size = 4;
/* Set the window for SB core register */
bar = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
if (bar != sdiodev->sbwad) {
ret = brcmf_sdcard_set_sbaddr_window(sdiodev, bar);
if (ret != 0) {
memset(data, 0xFF, reg_size);
return ret;
}
sdiodev->sbwad = bar;
}
}
/* otherwise, bad sdio access or invalid size */
brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size);
return 0xFFFFFFFF;
}
u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
u32 data)
{
int status;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
addr, size * 8, data);
if (bar0 != sdiodev->sbwad) {
err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
if (err)
return err;
sdiodev->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr &= SBSDIO_SB_OFT_ADDR_MASK;
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status =
brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1,
addr, &data, size);
sdiodev->regfail = (status != 0);
}
if (status == 0)
return 0;
do {
if (!write)
memset(data, 0, reg_size);
if (retry) /* wait for 1 ms till bus get settled down */
usleep_range(1000, 2000);
if (reg_size == 1)
ret = brcmf_sdioh_request_byte(sdiodev, write,
func_num, addr, data);
else
ret = brcmf_sdioh_request_word(sdiodev, write,
func_num, addr, data, 4);
} while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n",
data, addr, size);
return 0xFFFFFFFF;
if (ret != 0)
brcmf_dbg(ERROR, "failed with %d\n", ret);
return ret;
}
bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
{
return sdiodev->regfail;
u8 data;
int retval;
brcmf_dbg(INFO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
brcmf_dbg(INFO, "data:0x%02x\n", data);
if (ret)
*ret = retval;
return data;
}
u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
{
u32 data;
int retval;
brcmf_dbg(INFO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
brcmf_dbg(INFO, "data:0x%08x\n", data);
if (ret)
*ret = retval;
return data;
}
void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
u8 data, int *ret)
{
int retval;
brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
if (ret)
*ret = retval;
}
void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
u32 data, int *ret)
{
int retval;
brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
if (ret)
*ret = retval;
}
static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,

View file

@ -346,43 +346,17 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
return status;
}
/* Read client card reg */
static int
brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr,
int regsize, u32 *data)
{
if ((func == 0) || (regsize == 1)) {
u8 temp = 0;
brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr,
&temp);
*data = temp;
*data &= 0xff;
brcmf_dbg(DATA, "byte read data=0x%02x\n", *data);
} else {
brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr,
data, regsize);
if (regsize == 2)
*data &= 0xffff;
brcmf_dbg(DATA, "word read data=0x%08x\n", *data);
}
return SUCCESS;
}
static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr)
{
/* read 24 bits and return valid 17 bit addr */
int i;
int i, ret;
u32 scratch, regdata;
__le32 scratch_le;
u8 *ptr = (u8 *)&scratch_le;
for (i = 0; i < 3; i++) {
if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1,
&regdata)) != SUCCESS)
regdata = brcmf_sdio_regrl(sdiodev, regaddr, &ret);
if (ret != 0)
brcmf_dbg(ERROR, "Can't read!\n");
*ptr++ = (u8) regdata;

View file

@ -629,43 +629,29 @@ static bool data_ok(struct brcmf_sdio *bus)
* Reads a register in the SDIO hardware block. This block occupies a series of
* adresses on the 32 bit backplane bus.
*/
static void
r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
static int
r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
{
u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
*retryvar = 0;
do {
*regvar = brcmf_sdcard_reg_read(bus->sdiodev,
bus->ci->c_inf[idx].base + reg_offset,
sizeof(u32));
} while (brcmf_sdcard_regfail(bus->sdiodev) &&
(++(*retryvar) <= retry_limit));
if (*retryvar) {
bus->regfails += (*retryvar-1);
if (*retryvar > retry_limit) {
brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset);
*regvar = 0;
}
}
int ret;
*regvar = brcmf_sdio_regrl(bus->sdiodev,
bus->ci->c_inf[idx].base + offset, &ret);
return ret;
}
static void
w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset, u32 *retryvar)
static int
w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
{
u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
*retryvar = 0;
do {
brcmf_sdcard_reg_write(bus->sdiodev,
bus->ci->c_inf[idx].base + reg_offset,
sizeof(u32), regval);
} while (brcmf_sdcard_regfail(bus->sdiodev) &&
(++(*retryvar) <= retry_limit));
if (*retryvar) {
bus->regfails += (*retryvar-1);
if (*retryvar > retry_limit)
brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n",
reg_offset);
}
int ret;
brcmf_sdio_regwl(bus->sdiodev,
bus->ci->c_inf[idx].base + reg_offset,
regval, &ret);
return ret;
}
#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
@ -697,16 +683,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
clkreq =
bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
clkreq, &err);
if (err) {
brcmf_dbg(ERROR, "HT Avail request error: %d\n", err);
return -EBADE;
}
/* Check current status */
clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
clkctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err) {
brcmf_dbg(ERROR, "HT Avail read error: %d\n", err);
return -EBADE;
@ -715,9 +701,8 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
/* Go to pending and await interrupt if appropriate */
if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
/* Allow only clock-available interrupt */
devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
if (err) {
brcmf_dbg(ERROR, "Devctl error setting CA: %d\n",
err);
@ -725,30 +710,28 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
}
devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
brcmf_dbg(INFO, "CLKCTL: set PENDING\n");
bus->clkstate = CLK_PENDING;
return 0;
} else if (bus->clkstate == CLK_PENDING) {
/* Cancel CA-only interrupt filter */
devctl =
brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
}
/* Otherwise, wait here (polling) for HT Avail */
timeout = jiffies +
msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
clkctl = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
&err);
clkctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR,
&err);
if (time_after(jiffies, timeout))
break;
else
@ -781,17 +764,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
if (bus->clkstate == CLK_PENDING) {
/* Cancel CA-only interrupt filter */
devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
}
bus->clkstate = CLK_SDONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
clkreq, &err);
brcmf_dbg(INFO, "CLKCTL: turned OFF\n");
if (err) {
brcmf_dbg(ERROR, "Failed access turning clock off: %d\n",
@ -874,7 +856,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
{
uint retries = 0;
int ret;
brcmf_dbg(INFO, "request %s (currently %s)\n",
sleep ? "SLEEP" : "WAKE",
@ -894,22 +876,20 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
/* Tell device to start using OOB wakeup */
w_sdreg32(bus, SMB_USE_OOB,
offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
if (retries > retry_limit)
ret = w_sdreg32(bus, SMB_USE_OOB,
offsetof(struct sdpcmd_regs, tosbmailbox));
if (ret != 0)
brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n");
/* Turn off our contribution to the HT clock request */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
/* Isolate the bus */
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL,
SBSDIO_DEVCTL_PADS_ISO, NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
SBSDIO_DEVCTL_PADS_ISO, NULL);
/* Change state */
bus->sleeping = true;
@ -917,21 +897,20 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
} else {
/* Waking up: bus power up is ok, set local state */
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
0, NULL);
/* Make sure the controller has the bus up */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
/* Send misc interrupt to indicate OOB not needed */
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata),
&retries);
if (retries <= retry_limit)
w_sdreg32(bus, SMB_DEV_INT,
offsetof(struct sdpcmd_regs, tosbmailbox),
&retries);
ret = w_sdreg32(bus, 0,
offsetof(struct sdpcmd_regs, tosbmailboxdata));
if (ret == 0)
ret = w_sdreg32(bus, SMB_DEV_INT,
offsetof(struct sdpcmd_regs, tosbmailbox));
if (retries > retry_limit)
if (ret != 0)
brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n");
/* Make sure we have SD bus access */
@ -955,17 +934,17 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
u32 intstatus = 0;
u32 hmb_data;
u8 fcbits;
uint retries = 0;
int ret;
brcmf_dbg(TRACE, "Enter\n");
/* Read mailbox data and ack that we did so */
r_sdreg32(bus, &hmb_data,
offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries);
ret = r_sdreg32(bus, &hmb_data,
offsetof(struct sdpcmd_regs, tohostmailboxdata));
if (retries <= retry_limit)
if (ret == 0)
w_sdreg32(bus, SMB_INT_ACK,
offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
offsetof(struct sdpcmd_regs, tosbmailbox));
bus->f1regdata += 2;
/* Dongle recomposed rx frames, accept them again */
@ -1040,17 +1019,16 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
if (abort)
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_FRAMECTRL,
SFC_RF_TERM, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
SFC_RF_TERM, &err);
bus->f1regdata++;
/* 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);
hi = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_RFRAMEBCHI, &err);
lo = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_RFRAMEBCLO, &err);
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
@ -1070,11 +1048,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
if (rtx) {
bus->rxrtx++;
w_sdreg32(bus, SMB_NAK,
offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
err = w_sdreg32(bus, SMB_NAK,
offsetof(struct sdpcmd_regs, tosbmailbox));
bus->f1regdata++;
if (retries <= retry_limit)
if (err == 0)
bus->rxskip = true;
}
@ -1082,7 +1060,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
bus->nextlen = 0;
/* If we can't reach the device, signal failure */
if (err || brcmf_sdcard_regfail(bus->sdiodev))
if (err)
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
}
@ -2178,21 +2156,16 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
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);
brcmf_sdio_regwb(bus->sdiodev, 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);
hi = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCHI, NULL);
lo = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCLO, NULL);
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
break;
@ -2219,7 +2192,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
{
struct sk_buff *pkt;
u32 intstatus = 0;
uint retries = 0;
int ret = 0, prec_out;
uint cnt = 0;
uint datalen;
@ -2249,11 +2221,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
/* 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);
ret = r_sdreg32(bus, &intstatus,
offsetof(struct sdpcmd_regs,
intstatus));
bus->f2txdata++;
if (brcmf_sdcard_regfail(bus->sdiodev))
if (ret != 0)
break;
if (intstatus & bus->hostintmask)
bus->ipend = true;
@ -2275,7 +2247,6 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
{
u32 local_hostintmask;
u8 saveclk;
uint retries;
int err;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
@ -2303,7 +2274,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
/* Disable and clear interrupts at the chip level also */
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
local_hostintmask = bus->hostintmask;
bus->hostintmask = 0;
@ -2311,24 +2282,23 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
/* Force clocks on backplane to be sure F2 interrupt propagates */
saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
saveclk = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (!err) {
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
(saveclk | SBSDIO_FORCE_HT), &err);
brcmf_sdio_regwb(bus->sdiodev, 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);
brcmf_sdio_regwb(bus->sdiodev, 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);
offsetof(struct sdpcmd_regs, intstatus));
/* Turn off the backplane clock (only) */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
@ -2373,12 +2343,12 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
{
u32 intstatus, newstatus = 0;
uint retries = 0;
uint rxlimit = bus->rxbound; /* Rx frames to read before resched */
uint txlimit = bus->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 */
int err;
brcmf_dbg(TRACE, "Enter\n");
@ -2389,13 +2359,12 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
/* If waiting for HTAVAIL, check status */
if (bus->clkstate == CLK_PENDING) {
int err;
u8 clkctl, devctl = 0;
#ifdef DEBUG
/* Check for inconsistent device control */
devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
@ -2403,8 +2372,8 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
#endif /* DEBUG */
/* Read CSR, if clock on switch to AVAIL, else ignore */
clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
clkctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err) {
brcmf_dbg(ERROR, "error reading CSR: %d\n",
err);
@ -2415,17 +2384,16 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
devctl, clkctl);
if (SBSDIO_HTAV(clkctl)) {
devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
err);
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
}
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
if (err) {
brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
err);
@ -2447,17 +2415,17 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
/* Pending interrupt indicates new device status */
if (bus->ipend) {
bus->ipend = false;
r_sdreg32(bus, &newstatus,
offsetof(struct sdpcmd_regs, intstatus), &retries);
err = r_sdreg32(bus, &newstatus,
offsetof(struct sdpcmd_regs, intstatus));
bus->f1regdata++;
if (brcmf_sdcard_regfail(bus->sdiodev))
if (err != 0)
newstatus = 0;
newstatus &= bus->hostintmask;
bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
if (newstatus) {
w_sdreg32(bus, newstatus,
offsetof(struct sdpcmd_regs, intstatus),
&retries);
err = w_sdreg32(bus, newstatus,
offsetof(struct sdpcmd_regs,
intstatus));
bus->f1regdata++;
}
}
@ -2472,11 +2440,11 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
*/
if (intstatus & I_HMB_FC_CHANGE) {
intstatus &= ~I_HMB_FC_CHANGE;
w_sdreg32(bus, I_HMB_FC_CHANGE,
offsetof(struct sdpcmd_regs, intstatus), &retries);
err = w_sdreg32(bus, I_HMB_FC_CHANGE,
offsetof(struct sdpcmd_regs, intstatus));
r_sdreg32(bus, &newstatus,
offsetof(struct sdpcmd_regs, intstatus), &retries);
err = r_sdreg32(bus, &newstatus,
offsetof(struct sdpcmd_regs, intstatus));
bus->f1regdata += 2;
bus->fcstate =
!!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
@ -2546,21 +2514,18 @@ clkwait:
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
SFC_WF_TERM, &err);
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);
hi = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCHI,
&err);
lo = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCLO,
&err);
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
break;
@ -2587,10 +2552,8 @@ clkwait:
else await next interrupt */
/* On failed register access, all bets are off:
no resched or interrupts */
if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) ||
brcmf_sdcard_regfail(bus->sdiodev)) {
brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n",
brcmf_sdcard_regfail(bus->sdiodev));
if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) {
brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation\n");
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
bus->intstatus = 0;
} else if (bus->clkstate == CLK_PENDING) {
@ -2886,19 +2849,16 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_FRAMECTRL,
SFC_WF_TERM, NULL);
brcmf_sdio_regwb(bus->sdiodev, 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);
hi = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCHI, NULL);
lo = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCLO, NULL);
bus->f1regdata += 2;
if (hi == 0 && lo == 0)
break;
@ -3188,7 +3148,6 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
{
uint retries;
int bcmerror = 0;
struct chip_info *ci = bus->ci;
@ -3222,7 +3181,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
}
w_sdreg32(bus, 0xFFFFFFFF,
offsetof(struct sdpcmd_regs, intstatus), &retries);
offsetof(struct sdpcmd_regs, intstatus));
ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
@ -3444,7 +3403,6 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
unsigned long timeout;
uint retries = 0;
u8 ready, enable;
int err, ret = 0;
u8 saveclk;
@ -3472,13 +3430,11 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
goto exit;
/* Force clocks on backplane to be sure F2 interrupt propagates */
saveclk =
brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
saveclk = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (!err) {
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
(saveclk | SBSDIO_FORCE_HT), &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
(saveclk | SBSDIO_FORCE_HT), &err);
}
if (err) {
brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
@ -3487,17 +3443,16 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
/* Enable function 2 (frame transfers) */
w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries);
offsetof(struct sdpcmd_regs, tosbmailboxdata));
enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
enable, NULL);
brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
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);
ready = brcmf_sdio_regrb(bus->sdiodev,
SDIO_CCCR_IORx, NULL);
if (time_after(jiffies, timeout))
break;
else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
@ -3512,21 +3467,18 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
/* Set up the interrupt mask and enable interrupts */
bus->hostintmask = HOSTINTMASK;
w_sdreg32(bus, bus->hostintmask,
offsetof(struct sdpcmd_regs, hostintmask), &retries);
offsetof(struct sdpcmd_regs, hostintmask));
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_WATERMARK, 8, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_WATERMARK, 8, &err);
} else {
/* Disable F2 again */
enable = SDIO_FUNC_ENABLE_1;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
SDIO_CCCR_IOEx, enable, NULL);
brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
ret = -ENODEV;
}
/* Restore previous clock setting */
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
if (ret == 0) {
ret = brcmf_sdio_intr_register(bus->sdiodev);
@ -3606,9 +3558,9 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
if (!bus->dpc_sched) {
u8 devpend;
devpend = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_0, SDIO_CCCR_INTx,
NULL);
devpend = brcmf_sdio_regrb(bus->sdiodev,
SDIO_CCCR_INTx,
NULL);
intstatus =
devpend & (INTR_STATUS_FUNC1 |
INTR_STATUS_FUNC2);
@ -3732,24 +3684,18 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
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");
pr_debug("F1 signature read @0x18000000=0x%4x\n",
brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4));
brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
/*
* Force PLL off until brcmf_sdio_chip_attach()
* programs PLL control regs
*/
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
BRCMF_INIT_CLKCTL1, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
BRCMF_INIT_CLKCTL1, &err);
if (!err)
clkctl =
brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
clkctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
@ -3782,9 +3728,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
reg_addr = bus->ci->c_inf[idx].base +
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);
reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL);
brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL);
brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
@ -3809,16 +3754,15 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *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);
brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx,
SDIO_FUNC_ENABLE_1, NULL);
bus->sdiodev->bus_if->state = 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);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
/* ...and initialize clock/power states */
bus->clkstate = CLK_SDONLY;

View file

@ -93,8 +93,9 @@ brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidhigh),
NULL);
return SBCOREREV(regdata);
}
@ -118,8 +119,9 @@ brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
return (SSB_TMSLOW_CLOCK == regdata);
@ -135,13 +137,13 @@ brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
4);
regdata = brcmf_sdio_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
return ret;
@ -151,84 +153,85 @@ static void
brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci, u16 coreid)
{
u32 regdata;
u32 regdata, base;
u8 idx;
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
base = ci->c_inf[idx].base;
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
if (regdata & SSB_TMSLOW_RESET)
return;
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
/*
* set target reject and spin until busy is clear
* (preserve core-specific bits)
*/
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
4, regdata | SSB_TMSLOW_REJECT);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
NULL);
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
regdata | SSB_TMSLOW_REJECT, NULL);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
NULL);
udelay(1);
SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
SPINWAIT((brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbtmstatehigh),
NULL) &
SSB_TMSHIGH_BUSY), 100000);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbtmstatehigh),
NULL);
if (regdata & SSB_TMSHIGH_BUSY)
brcmf_dbg(ERROR, "core state still busy\n");
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
NULL);
if (regdata & SSB_IDLOW_INITIATOR) {
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4) |
SSB_IMSTATE_REJECT;
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
regdata);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
regdata |= SSB_IMSTATE_REJECT;
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
regdata, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
udelay(1);
SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
SPINWAIT((brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL) &
SSB_IMSTATE_BUSY), 100000);
}
/* set reset and reject while enabling the clocks */
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
(SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
regdata, NULL);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
NULL);
udelay(10);
/* clear the initiator reject bit */
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
NULL);
if (regdata & SSB_IDLOW_INITIATOR) {
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
~SSB_IMSTATE_REJECT;
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
regdata);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
regdata &= ~SSB_IMSTATE_REJECT;
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
regdata, NULL);
}
}
/* leave reset and reject asserted */
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
(SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
(SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
udelay(1);
}
@ -242,20 +245,19 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
/* if core is already in reset, just return */
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
4);
regdata = brcmf_sdio_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
if ((regdata & BCMA_RESET_CTL_RESET) != 0)
return;
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
4, 0);
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, 0, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
udelay(10);
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
4, BCMA_RESET_CTL_RESET);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
BCMA_RESET_CTL_RESET, NULL);
udelay(1);
}
@ -279,41 +281,47 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
* set reset while enabling the clock and
* forcing them on throughout the core
*/
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
brcmf_sdio_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
udelay(1);
/* clear any serror */
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
NULL);
if (regdata & SSB_TMSHIGH_SERR)
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
brcmf_sdio_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
0, NULL);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate),
NULL);
if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
brcmf_sdio_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate),
regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
NULL);
/* clear reset and allow it to propagate throughout the core */
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
udelay(1);
/* leave clock enabled */
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
4, SSB_TMSLOW_CLOCK);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_CLOCK, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
udelay(1);
}
@ -330,18 +338,18 @@ brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
/* now do initialization sequence */
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
4, 0);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
0, NULL);
udelay(1);
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
4, BCMA_IOCTL_CLK);
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
udelay(1);
}
@ -358,8 +366,9 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
*/
ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
ci->c_inf[0].base = regs;
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipid),
NULL);
ci->chip = regdata & CID_ID_MASK;
ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
@ -428,8 +437,7 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
/* Try forcing SDIO core to do ALPAvail request only */
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
if (err) {
brcmf_dbg(ERROR, "error writing for HT off\n");
return err;
@ -437,8 +445,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
/* If register supported, wait for ALPAvail and then force ALP */
/* This may take up to 15 milliseconds */
clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, NULL);
clkval = brcmf_sdio_regrb(sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, NULL);
if ((clkval & ~SBSDIO_AVBITS) != clkset) {
brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
@ -446,8 +454,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
return -EACCES;
}
SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
!SBSDIO_ALPAV(clkval)),
PMU_MAX_TRANSITION_DLY);
if (!SBSDIO_ALPAV(clkval)) {
@ -457,13 +465,11 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
}
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
udelay(65);
/* Also, disable the extra SDIO pull-ups */
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
return 0;
}
@ -472,18 +478,22 @@ static void
brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci)
{
u32 base = ci->c_inf[0].base;
/* get chipcommon rev */
ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
/* get chipcommon capabilites */
ci->c_inf[0].caps =
brcmf_sdcard_reg_read(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
ci->c_inf[0].caps = brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(base, capabilities),
NULL);
/* get pmu caps & rev */
if (ci->c_inf[0].caps & CC_CAP_PMU) {
ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
ci->pmucaps =
brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(base, pmucapabilities),
NULL);
ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
}
@ -523,10 +533,10 @@ int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
brcmf_sdio_chip_buscoresetup(sdiodev, ci);
brcmf_sdcard_reg_write(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
brcmf_sdcard_reg_write(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
0, NULL);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
0, NULL);
*ci_ptr = ci;
return 0;
@ -562,6 +572,7 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
u32 str_mask = 0;
u32 str_shift = 0;
char chn[8];
u32 base = ci->c_inf[0].base;
if (!(ci->c_inf[0].caps & CC_CAP_PMU))
return;
@ -591,17 +602,17 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
}
}
brcmf_sdcard_reg_write(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
4, 1);
cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
1, NULL);
cc_data_temp =
brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(base, chipcontrol_addr),
NULL);
cc_data_temp &= ~str_mask;
drivestrength_sel <<= str_shift;
cc_data_temp |= drivestrength_sel;
brcmf_sdcard_reg_write(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
4, cc_data_temp);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
cc_data_temp, NULL);
brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
drivestrength, cc_data_temp);

View file

@ -40,6 +40,10 @@
/* Maximum number of I/O funcs */
#define SDIOD_MAX_IOFUNCS 7
/* mask of register map */
#define REG_F0_REG_MASK 0x7FF
#define REG_F1_MISC_MASK 0x1FFFF
/* as of sdiod rev 0, supports 3 functions */
#define SBSDIO_NUM_FUNCTION 3
@ -142,7 +146,6 @@ struct brcmf_sdio_dev {
u8 num_funcs; /* Supported funcs on client */
u32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
u32 sbwad; /* Save backplane window address */
bool regfail; /* status of last reg_r/w call */
void *bus;
atomic_t suspend; /* suspend flag */
wait_queue_head_t request_byte_wait;
@ -164,31 +167,13 @@ struct brcmf_sdio_dev {
extern int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev);
extern int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev);
/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface).
* fn: function number
* addr: unmodified SDIO-space address
* data: data byte to write
* err: pointer to error code (or NULL)
*/
extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint func,
u32 addr, int *err);
extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint func,
u32 addr, u8 data, int *err);
/* Synchronous access to device (client) core registers via CMD53 to F1.
* addr: backplane address (i.e. >= regsva from attach)
* size: register width in bytes (2 or 4)
* data: data for register write
*/
extern u32
brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size);
extern u32
brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
u32 data);
/* Indicate if last reg read/write failed */
extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev);
/* sdio device register access interface */
extern u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
extern u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
extern void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
u8 data, int *ret);
extern void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
u32 data, int *ret);
/* Buffer transfer to/from device (client) core via cmd53.
* fn: function number

View file

@ -39,10 +39,7 @@ BRCMSMAC_OFILES := \
phy/phytbl_lcn.o \
phy/phytbl_n.o \
phy/phy_qmath.o \
otp.o \
srom.o \
dma.o \
nicpci.o \
brcms_trace_events.o
MODULEPFX := brcmsmac

View file

@ -19,7 +19,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
#include <linux/pci.h>
#include <defs.h>
#include <chipcommon.h>
@ -29,8 +28,6 @@
#include "types.h"
#include "pub.h"
#include "pmu.h"
#include "srom.h"
#include "nicpci.h"
#include "aiutils.h"
/* slow_clk_ctl */
@ -321,7 +318,6 @@
#define IS_SIM(chippkg) \
((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
#define PCI(sih) (ai_get_buscoretype(sih) == PCI_CORE_ID)
#define PCIE(sih) (ai_get_buscoretype(sih) == PCIE_CORE_ID)
#define PCI_FORCEHT(sih) (PCIE(sih) && (ai_get_chip_id(sih) == BCM4716_CHIP_ID))
@ -454,36 +450,9 @@ struct aidmp {
u32 componentid3; /* 0xffc */
};
/* return true if PCIE capability exists in the pci config space */
static bool ai_ispcie(struct si_info *sii)
{
u8 cap_ptr;
cap_ptr =
pcicore_find_pci_capability(sii->pcibus, PCI_CAP_ID_EXP, NULL,
NULL);
if (!cap_ptr)
return false;
return true;
}
static bool ai_buscore_prep(struct si_info *sii)
{
/* kludge to enable the clock on the 4306 which lacks a slowclock */
if (!ai_ispcie(sii))
ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON);
return true;
}
static bool
ai_buscore_setup(struct si_info *sii, struct bcma_device *cc)
{
struct bcma_device *pci = NULL;
struct bcma_device *pcie = NULL;
struct bcma_device *core;
/* no cores found, bail out */
if (cc->bus->nr_cores == 0)
return false;
@ -492,8 +461,7 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc)
sii->pub.ccrev = cc->id.rev;
/* get chipcommon chipstatus */
if (ai_get_ccrev(&sii->pub) >= 11)
sii->chipst = bcma_read32(cc, CHIPCREGOFFS(chipstatus));
sii->chipst = bcma_read32(cc, CHIPCREGOFFS(chipstatus));
/* get chipcommon capabilites */
sii->pub.cccaps = bcma_read32(cc, CHIPCREGOFFS(capabilities));
@ -506,64 +474,18 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc)
}
/* figure out buscore */
list_for_each_entry(core, &cc->bus->cores, list) {
uint cid, crev;
cid = core->id.id;
crev = core->id.rev;
if (cid == PCI_CORE_ID) {
pci = core;
} else if (cid == PCIE_CORE_ID) {
pcie = core;
}
}
if (pci && pcie) {
if (ai_ispcie(sii))
pci = NULL;
else
pcie = NULL;
}
if (pci) {
sii->buscore = pci;
} else if (pcie) {
sii->buscore = pcie;
}
/* fixup necessary chip/core configurations */
if (!sii->pch) {
sii->pch = pcicore_init(&sii->pub, sii->icbus->drv_pci.core);
if (sii->pch == NULL)
return false;
}
if (ai_pci_fixcfg(&sii->pub))
return false;
sii->buscore = ai_findcore(&sii->pub, PCIE_CORE_ID, 0);
return true;
}
/*
* get boardtype and boardrev
*/
static __used void ai_nvram_process(struct si_info *sii)
{
uint w = 0;
/* do a pci config read to get subsystem id and subvendor id */
pci_read_config_dword(sii->pcibus, PCI_SUBSYSTEM_VENDOR_ID, &w);
sii->pub.boardvendor = w & 0xffff;
sii->pub.boardtype = (w >> 16) & 0xffff;
}
static struct si_info *ai_doattach(struct si_info *sii,
struct bcma_bus *pbus)
{
struct si_pub *sih = &sii->pub;
u32 w, savewin;
struct bcma_device *cc;
uint socitype;
struct ssb_sprom *sprom = &pbus->sprom;
savewin = 0;
@ -573,38 +495,15 @@ static struct si_info *ai_doattach(struct si_info *sii,
/* switch to Chipcommon core */
cc = pbus->drv_cc.core;
/* bus/core/clk setup for register access */
if (!ai_buscore_prep(sii))
return NULL;
sih->chip = pbus->chipinfo.id;
sih->chiprev = pbus->chipinfo.rev;
sih->chippkg = pbus->chipinfo.pkg;
sih->boardvendor = pbus->boardinfo.vendor;
sih->boardtype = pbus->boardinfo.type;
/*
* ChipID recognition.
* We assume we can read chipid at offset 0 from the regs arg.
* If we add other chiptypes (or if we need to support old sdio
* hosts w/o chipcommon), some way of recognizing them needs to
* be added here.
*/
w = bcma_read32(cc, CHIPCREGOFFS(chipid));
socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
/* Might as wll fill in chip id rev & pkg */
sih->chip = w & CID_ID_MASK;
sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
/* scan for cores */
if (socitype != SOCI_AI)
return NULL;
SI_MSG("Found chip type AI (0x%08x)\n", w);
if (!ai_buscore_setup(sii, cc))
goto exit;
/* Init nvram from sprom/otp if they exist */
if (srom_var_init(&sii->pub))
goto exit;
ai_nvram_process(sii);
/* === NVRAM, clock is ready === */
bcma_write32(cc, CHIPCREGOFFS(gpiopullup), 0);
bcma_write32(cc, CHIPCREGOFFS(gpiopulldown), 0);
@ -617,15 +516,13 @@ static struct si_info *ai_doattach(struct si_info *sii,
}
/* setup the GPIO based LED powersave register */
w = getintvar(sih, BRCMS_SROM_LEDDC);
w = (sprom->leddc_on_time << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
(sprom->leddc_off_time << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT);
if (w == 0)
w = DEFAULT_GPIOTIMERVAL;
ai_cc_reg(sih, offsetof(struct chipcregs, gpiotimerval),
~0, w);
if (PCIE(sih))
pcicore_attach(sii->pch, SI_DOATTACH);
if (ai_get_chip_id(sih) == BCM43224_CHIP_ID) {
/*
* enable 12 mA drive strenth for 43224 and
@ -659,9 +556,6 @@ static struct si_info *ai_doattach(struct si_info *sii,
return sii;
exit:
if (sii->pch)
pcicore_deinit(sii->pch);
sii->pch = NULL;
return NULL;
}
@ -700,11 +594,6 @@ void ai_detach(struct si_pub *sih)
if (sii == NULL)
return;
if (sii->pch)
pcicore_deinit(sii->pch);
sii->pch = NULL;
srom_free_vars(sih);
kfree(sii);
}
@ -755,21 +644,7 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val)
/* return the slow clock source - LPO, XTAL, or PCI */
static uint ai_slowclk_src(struct si_pub *sih, struct bcma_device *cc)
{
struct si_info *sii;
u32 val;
sii = (struct si_info *)sih;
if (ai_get_ccrev(&sii->pub) < 6) {
pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT,
&val);
if (val & PCI_CFG_GPIO_SCS)
return SCC_SS_PCI;
return SCC_SS_XTAL;
} else if (ai_get_ccrev(&sii->pub) < 10) {
return bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) &
SCC_SS_MASK;
} else /* Insta-clock */
return SCC_SS_XTAL;
return SCC_SS_XTAL;
}
/*
@ -779,36 +654,12 @@ static uint ai_slowclk_src(struct si_pub *sih, struct bcma_device *cc)
static uint ai_slowclk_freq(struct si_pub *sih, bool max_freq,
struct bcma_device *cc)
{
u32 slowclk;
uint div;
slowclk = ai_slowclk_src(sih, cc);
if (ai_get_ccrev(sih) < 6) {
if (slowclk == SCC_SS_PCI)
return max_freq ? (PCIMAXFREQ / 64)
: (PCIMINFREQ / 64);
else
return max_freq ? (XTALMAXFREQ / 32)
: (XTALMINFREQ / 32);
} else if (ai_get_ccrev(sih) < 10) {
div = 4 *
(((bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) &
SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
if (slowclk == SCC_SS_LPO)
return max_freq ? LPOMAXFREQ : LPOMINFREQ;
else if (slowclk == SCC_SS_XTAL)
return max_freq ? (XTALMAXFREQ / div)
: (XTALMINFREQ / div);
else if (slowclk == SCC_SS_PCI)
return max_freq ? (PCIMAXFREQ / div)
: (PCIMINFREQ / div);
} else {
/* Chipc rev 10 is InstaClock */
div = bcma_read32(cc, CHIPCREGOFFS(system_clk_ctl));
div = 4 * ((div >> SYCC_CD_SHIFT) + 1);
return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div);
}
return 0;
/* Chipc rev 10 is InstaClock */
div = bcma_read32(cc, CHIPCREGOFFS(system_clk_ctl));
div = 4 * ((div >> SYCC_CD_SHIFT) + 1);
return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div);
}
static void
@ -831,8 +682,7 @@ ai_clkctl_setdelay(struct si_pub *sih, struct bcma_device *cc)
/* Starting with 4318 it is ILP that is used for the delays */
slowmaxfreq =
ai_slowclk_freq(sih,
(ai_get_ccrev(sih) >= 10) ? false : true, cc);
ai_slowclk_freq(sih, false, cc);
pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
@ -854,9 +704,8 @@ void ai_clkctl_init(struct si_pub *sih)
return;
/* set all Instaclk chip ILP to 1 MHz */
if (ai_get_ccrev(sih) >= 10)
bcma_maskset32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_CD_MASK,
(ILP_DIV_1MHZ << SYCC_CD_SHIFT));
bcma_maskset32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_CD_MASK,
(ILP_DIV_1MHZ << SYCC_CD_SHIFT));
ai_clkctl_setdelay(sih, cc);
}
@ -891,140 +740,6 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih)
return fpdelay;
}
/* turn primary xtal and/or pll off/on */
int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on)
{
struct si_info *sii;
u32 in, out, outen;
sii = (struct si_info *)sih;
/* pcie core doesn't have any mapping to control the xtal pu */
if (PCIE(sih))
return -1;
pci_read_config_dword(sii->pcibus, PCI_GPIO_IN, &in);
pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT, &out);
pci_read_config_dword(sii->pcibus, PCI_GPIO_OUTEN, &outen);
/*
* Avoid glitching the clock if GPRS is already using it.
* We can't actually read the state of the PLLPD so we infer it
* by the value of XTAL_PU which *is* readable via gpioin.
*/
if (on && (in & PCI_CFG_GPIO_XTAL))
return 0;
if (what & XTAL)
outen |= PCI_CFG_GPIO_XTAL;
if (what & PLL)
outen |= PCI_CFG_GPIO_PLL;
if (on) {
/* turn primary xtal on */
if (what & XTAL) {
out |= PCI_CFG_GPIO_XTAL;
if (what & PLL)
out |= PCI_CFG_GPIO_PLL;
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUT, out);
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUTEN, outen);
udelay(XTAL_ON_DELAY);
}
/* turn pll on */
if (what & PLL) {
out &= ~PCI_CFG_GPIO_PLL;
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUT, out);
mdelay(2);
}
} else {
if (what & XTAL)
out &= ~PCI_CFG_GPIO_XTAL;
if (what & PLL)
out |= PCI_CFG_GPIO_PLL;
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUT, out);
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUTEN, outen);
}
return 0;
}
/* clk control mechanism through chipcommon, no policy checking */
static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
{
struct bcma_device *cc;
u32 scc;
/* chipcommon cores prior to rev6 don't support dynamic clock control */
if (ai_get_ccrev(&sii->pub) < 6)
return false;
cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
if (!(ai_get_cccaps(&sii->pub) & CC_CAP_PWR_CTL) &&
(ai_get_ccrev(&sii->pub) < 20))
return mode == CLK_FAST;
switch (mode) {
case CLK_FAST: /* FORCEHT, fast (pll) clock */
if (ai_get_ccrev(&sii->pub) < 10) {
/*
* don't forget to force xtal back
* on before we clear SCC_DYN_XTAL..
*/
ai_clkctl_xtal(&sii->pub, XTAL, ON);
bcma_maskset32(cc, CHIPCREGOFFS(slow_clk_ctl),
(SCC_XC | SCC_FS | SCC_IP), SCC_IP);
} else if (ai_get_ccrev(&sii->pub) < 20) {
bcma_set32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_HR);
} else {
bcma_set32(cc, CHIPCREGOFFS(clk_ctl_st), CCS_FORCEHT);
}
/* wait for the PLL */
if (ai_get_cccaps(&sii->pub) & CC_CAP_PMU) {
u32 htavail = CCS_HTAVAIL;
SPINWAIT(((bcma_read32(cc, CHIPCREGOFFS(clk_ctl_st)) &
htavail) == 0), PMU_MAX_TRANSITION_DLY);
} else {
udelay(PLL_DELAY);
}
break;
case CLK_DYNAMIC: /* enable dynamic clock control */
if (ai_get_ccrev(&sii->pub) < 10) {
scc = bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl));
scc &= ~(SCC_FS | SCC_IP | SCC_XC);
if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
scc |= SCC_XC;
bcma_write32(cc, CHIPCREGOFFS(slow_clk_ctl), scc);
/*
* for dynamic control, we have to
* release our xtal_pu "force on"
*/
if (scc & SCC_XC)
ai_clkctl_xtal(&sii->pub, XTAL, OFF);
} else if (ai_get_ccrev(&sii->pub) < 20) {
/* Instaclock */
bcma_mask32(cc, CHIPCREGOFFS(system_clk_ctl), ~SYCC_HR);
} else {
bcma_mask32(cc, CHIPCREGOFFS(clk_ctl_st), ~CCS_FORCEHT);
}
break;
default:
break;
}
return mode == CLK_FAST;
}
/*
* clock control policy function throught chipcommon
*
@ -1033,133 +748,53 @@ static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
* this is a wrapper over the next internal function
* to allow flexible policy settings for outside caller
*/
bool ai_clkctl_cc(struct si_pub *sih, uint mode)
bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode)
{
struct si_info *sii;
struct bcma_device *cc;
sii = (struct si_info *)sih;
/* chipcommon cores prior to rev6 don't support dynamic clock control */
if (ai_get_ccrev(sih) < 6)
return false;
if (PCI_FORCEHT(sih))
return mode == CLK_FAST;
return mode == BCMA_CLKMODE_FAST;
return _ai_clkctl_cc(sii, mode);
cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
bcma_core_set_clockmode(cc, mode);
return mode == BCMA_CLKMODE_FAST;
}
void ai_pci_up(struct si_pub *sih)
{
struct si_info *sii;
struct bcma_device *cc;
sii = (struct si_info *)sih;
if (PCI_FORCEHT(sih))
_ai_clkctl_cc(sii, CLK_FAST);
if (PCI_FORCEHT(sih)) {
cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
bcma_core_set_clockmode(cc, BCMA_CLKMODE_FAST);
}
if (PCIE(sih))
pcicore_up(sii->pch, SI_PCIUP);
}
/* Unconfigure and/or apply various WARs when system is going to sleep mode */
void ai_pci_sleep(struct si_pub *sih)
{
struct si_info *sii;
sii = (struct si_info *)sih;
pcicore_sleep(sii->pch);
bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true);
}
/* Unconfigure and/or apply various WARs when going down */
void ai_pci_down(struct si_pub *sih)
{
struct si_info *sii;
struct bcma_device *cc;
sii = (struct si_info *)sih;
/* release FORCEHT since chip is going to "down" state */
if (PCI_FORCEHT(sih))
_ai_clkctl_cc(sii, CLK_DYNAMIC);
pcicore_down(sii->pch, SI_PCIDOWN);
}
/*
* Configure the pci core for pci client (NIC) action
* coremask is the bitvec of cores by index to be enabled.
*/
void ai_pci_setup(struct si_pub *sih, uint coremask)
{
struct si_info *sii;
u32 w;
sii = (struct si_info *)sih;
/*
* Enable sb->pci interrupts. Assume
* PCI rev 2.3 support was added in pci core rev 6 and things changed..
*/
if (PCIE(sih) || (PCI(sih) && (ai_get_buscorerev(sih) >= 6))) {
/* pci config write to set this core bit in PCIIntMask */
pci_read_config_dword(sii->pcibus, PCI_INT_MASK, &w);
w |= (coremask << PCI_SBIM_SHIFT);
pci_write_config_dword(sii->pcibus, PCI_INT_MASK, w);
if (PCI_FORCEHT(sih)) {
cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
bcma_core_set_clockmode(cc, BCMA_CLKMODE_DYNAMIC);
}
if (PCI(sih)) {
pcicore_pci_setup(sii->pch);
}
}
/*
* Fixup SROMless PCI device's configuration.
* The current core may be changed upon return.
*/
int ai_pci_fixcfg(struct si_pub *sih)
{
struct si_info *sii = (struct si_info *)sih;
/* Fixup PI in SROM shadow area to enable the correct PCI core access */
/* check 'pi' is correct and fix it if not */
pcicore_fixcfg(sii->pch);
pcicore_hwup(sii->pch);
return 0;
}
/* mask&set gpiocontrol bits */
u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority)
{
uint regoff;
regoff = offsetof(struct chipcregs, gpiocontrol);
return ai_cc_reg(sih, regoff, mask, val);
}
void ai_chipcontrl_epa4331(struct si_pub *sih, bool on)
{
struct bcma_device *cc;
u32 val;
cc = ai_findcore(sih, CC_CORE_ID, 0);
if (on) {
if (ai_get_chippkg(sih) == 9 || ai_get_chippkg(sih) == 0xb)
/* Ext PA Controls for 4331 12x9 Package */
bcma_set32(cc, CHIPCREGOFFS(chipcontrol),
CCTRL4331_EXTPA_EN |
CCTRL4331_EXTPA_ON_GPIO2_5);
else
/* Ext PA Controls for 4331 12x12 Package */
bcma_set32(cc, CHIPCREGOFFS(chipcontrol),
CCTRL4331_EXTPA_EN);
} else {
val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5);
bcma_mask32(cc, CHIPCREGOFFS(chipcontrol),
~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5));
}
if (PCIE(sih))
bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false);
}
/* Enable BT-COEX & Ex-PA for 4313 */
@ -1181,6 +816,9 @@ bool ai_deviceremoved(struct si_pub *sih)
sii = (struct si_info *)sih;
if (sii->icbus->hosttype != BCMA_HOSTTYPE_PCI)
return false;
pci_read_config_dword(sii->pcibus, PCI_VENDOR_ID, &w);
if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM)
return true;
@ -1188,45 +826,6 @@ bool ai_deviceremoved(struct si_pub *sih)
return false;
}
bool ai_is_sprom_available(struct si_pub *sih)
{
struct si_info *sii = (struct si_info *)sih;
if (ai_get_ccrev(sih) >= 31) {
struct bcma_device *cc;
u32 sromctrl;
if ((ai_get_cccaps(sih) & CC_CAP_SROM) == 0)
return false;
cc = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
sromctrl = bcma_read32(cc, CHIPCREGOFFS(sromcontrol));
return sromctrl & SRC_PRESENT;
}
switch (ai_get_chip_id(sih)) {
case BCM4313_CHIP_ID:
return (sii->chipst & CST4313_SPROM_PRESENT) != 0;
default:
return true;
}
}
bool ai_is_otp_disabled(struct si_pub *sih)
{
struct si_info *sii = (struct si_info *)sih;
switch (ai_get_chip_id(sih)) {
case BCM4313_CHIP_ID:
return (sii->chipst & CST4313_OTP_PRESENT) == 0;
/* These chips always have their OTP on */
case BCM43224_CHIP_ID:
case BCM43225_CHIP_ID:
default:
return false;
}
}
uint ai_get_buscoretype(struct si_pub *sih)
{
struct si_info *sii = (struct si_info *)sih;

View file

@ -113,10 +113,6 @@
#define XTAL 0x1 /* primary crystal oscillator (2050) */
#define PLL 0x2 /* main chip pll */
/* clkctl clk mode */
#define CLK_FAST 0 /* force fast (pll) clock */
#define CLK_DYNAMIC 2 /* enable dynamic clock control */
/* GPIO usage priorities */
#define GPIO_DRV_PRIORITY 0 /* Driver */
#define GPIO_APP_PRIORITY 1 /* Application */
@ -172,9 +168,7 @@ struct si_info {
struct si_pub pub; /* back plane public state (must be first) */
struct bcma_bus *icbus; /* handle to soc interconnect bus */
struct pci_dev *pcibus; /* handle to pci bus */
struct pcicore_info *pch; /* PCI/E core handle */
struct bcma_device *buscore;
struct list_head var_list; /* list of srom variables */
u32 chipst; /* chip status */
};
@ -197,38 +191,20 @@ extern u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val);
extern struct si_pub *ai_attach(struct bcma_bus *pbus);
extern void ai_detach(struct si_pub *sih);
extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val);
extern void ai_pci_setup(struct si_pub *sih, uint coremask);
extern void ai_clkctl_init(struct si_pub *sih);
extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih);
extern bool ai_clkctl_cc(struct si_pub *sih, uint mode);
extern int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on);
extern bool ai_deviceremoved(struct si_pub *sih);
extern u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val,
u8 priority);
/* OTP status */
extern bool ai_is_otp_disabled(struct si_pub *sih);
/* SPROM availability */
extern bool ai_is_sprom_available(struct si_pub *sih);
extern void ai_pci_sleep(struct si_pub *sih);
extern void ai_pci_down(struct si_pub *sih);
extern void ai_pci_up(struct si_pub *sih);
extern int ai_pci_fixcfg(struct si_pub *sih);
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);
extern uint ai_get_buscoretype(struct si_pub *sih);
extern uint ai_get_buscorerev(struct si_pub *sih);
static inline int ai_get_ccrev(struct si_pub *sih)
{
return sih->ccrev;
}
static inline u32 ai_get_cccaps(struct si_pub *sih)
{
return sih->cccaps;

View file

@ -108,7 +108,7 @@ brcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel,
struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
{
struct antsel_info *asi;
struct si_pub *sih = wlc->hw->sih;
struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC);
if (!asi)
@ -118,7 +118,7 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
asi->pub = wlc->pub;
asi->antsel_type = ANTSEL_NA;
asi->antsel_avail = false;
asi->antsel_antswitch = (u8) getintvar(sih, BRCMS_SROM_ANTSWITCH);
asi->antsel_antswitch = sprom->antswitch;
if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) {
switch (asi->antsel_antswitch) {
@ -128,12 +128,12 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
/* 4321/2 board with 2x3 switch logic */
asi->antsel_type = ANTSEL_2x3;
/* Antenna selection availability */
if (((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) ||
((u16) getintvar(sih, BRCMS_SROM_AA5G) == 7)) {
if ((sprom->ant_available_bg == 7) ||
(sprom->ant_available_a == 7)) {
asi->antsel_avail = true;
} else if (
(u16) getintvar(sih, BRCMS_SROM_AA2G) == 3 ||
(u16) getintvar(sih, BRCMS_SROM_AA5G) == 3) {
sprom->ant_available_bg == 3 ||
sprom->ant_available_a == 3) {
asi->antsel_avail = false;
} else {
asi->antsel_avail = false;
@ -146,8 +146,8 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
break;
}
} else if ((asi->pub->sromrev == 4) &&
((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) &&
((u16) getintvar(sih, BRCMS_SROM_AA5G) == 0)) {
(sprom->ant_available_bg == 7) &&
(sprom->ant_available_a == 0)) {
/* hack to match old 4321CB2 cards with 2of3 antenna switch */
asi->antsel_type = ANTSEL_2x3;
asi->antsel_avail = true;

View file

@ -1110,7 +1110,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
char country_abbrev[BRCM_CNTRY_BUF_SZ];
const struct country_info *country;
struct brcms_pub *pub = wlc->pub;
char *ccode;
struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
@ -1122,9 +1122,8 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
wlc->cmi = wlc_cm;
/* store the country code for passing up as a regulatory hint */
ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE);
if (ccode && brcms_c_country_valid(ccode))
strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
if (sprom->alpha2 && brcms_c_country_valid(sprom->alpha2))
strncpy(wlc->pub->srom_ccode, sprom->alpha2, sizeof(sprom->alpha2));
/*
* internal country information which must match

View file

@ -25,7 +25,6 @@
#include <linux/bcma/bcma.h>
#include <net/mac80211.h>
#include <defs.h>
#include "nicpci.h"
#include "phy/phy_int.h"
#include "d11.h"
#include "channel.h"
@ -770,7 +769,7 @@ void brcms_dpc(unsigned long data)
* Precondition: Since this function is called in brcms_pci_probe() context,
* no locking is required.
*/
static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev)
static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev)
{
int status;
struct device *device = &pdev->dev;
@ -1022,7 +1021,7 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
spin_lock_init(&wl->isr_lock);
/* prepare ucode */
if (brcms_request_fw(wl, pdev->bus->host_pci) < 0) {
if (brcms_request_fw(wl, pdev) < 0) {
wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
"%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
brcms_release_fw(wl);
@ -1043,12 +1042,12 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
wl->pub->ieee_hw = hw;
/* register our interrupt handler */
if (request_irq(pdev->bus->host_pci->irq, brcms_isr,
if (request_irq(pdev->irq, brcms_isr,
IRQF_SHARED, KBUILD_MODNAME, wl)) {
wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
goto fail;
}
wl->irq = pdev->bus->host_pci->irq;
wl->irq = pdev->irq;
/* register module */
brcms_c_module_register(wl->pub, "linux", wl, NULL);
@ -1098,7 +1097,7 @@ static int __devinit brcms_bcma_probe(struct bcma_device *pdev)
dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n",
pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class,
pdev->bus->host_pci->irq);
pdev->irq);
if ((pdev->id.manuf != BCMA_MANUF_BCM) ||
(pdev->id.id != BCMA_CORE_80211))

View file

@ -1219,7 +1219,7 @@ static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
}
/* control chip clock to save power, enable dynamic clock or force fast clock */
static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, enum bcma_clkmode mode)
{
if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) {
/* new chips with PMU, CCS_FORCEHT will distribute the HT clock
@ -1229,7 +1229,7 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
*/
if (wlc_hw->clk) {
if (mode == CLK_FAST) {
if (mode == BCMA_CLKMODE_FAST) {
bcma_set32(wlc_hw->d11core,
D11REGOFFS(clk_ctl_st),
CCS_FORCEHT);
@ -1260,7 +1260,7 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
~CCS_FORCEHT);
}
}
wlc_hw->forcefastclk = (mode == CLK_FAST);
wlc_hw->forcefastclk = (mode == BCMA_CLKMODE_FAST);
} else {
/* old chips w/o PMU, force HT through cc,
@ -1567,7 +1567,7 @@ void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
wlc_phy_bw_state_set(wlc_hw->band->pi, bw);
@ -1576,7 +1576,7 @@ void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
/* restore the clk */
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
}
static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
@ -1882,27 +1882,20 @@ static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw)
return true;
}
static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw)
static void brcms_c_get_macaddr(struct brcms_hardware *wlc_hw, u8 etheraddr[ETH_ALEN])
{
enum brcms_srom_id var_id = BRCMS_SROM_MACADDR;
char *macaddr;
struct ssb_sprom *sprom = &wlc_hw->d11core->bus->sprom;
/* If macaddr exists, use it (Sromrev4, CIS, ...). */
macaddr = getvar(wlc_hw->sih, var_id);
if (macaddr != NULL)
return macaddr;
if (!is_zero_ether_addr(sprom->il0mac)) {
memcpy(etheraddr, sprom->il0mac, 6);
return;
}
if (wlc_hw->_nbands > 1)
var_id = BRCMS_SROM_ET1MACADDR;
memcpy(etheraddr, sprom->et1mac, 6);
else
var_id = BRCMS_SROM_IL0MACADDR;
macaddr = getvar(wlc_hw->sih, var_id);
if (macaddr == NULL)
wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr "
"getvar(%d) not found\n", wlc_hw->unit, var_id);
return macaddr;
memcpy(etheraddr, sprom->il0mac, 6);
}
/* power both the pll and external oscillator on/off */
@ -1917,9 +1910,6 @@ static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
if (!want && wlc_hw->pllreq)
return;
if (wlc_hw->sih)
ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
wlc_hw->sbclk = want;
if (!wlc_hw->sbclk) {
wlc_hw->clk = false;
@ -2004,7 +1994,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/* reset the dma engines except first time thru */
if (bcma_core_is_enabled(wlc_hw->d11core)) {
@ -2053,7 +2043,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
brcms_c_mctrl_reset(wlc_hw);
if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
brcms_b_phy_reset(wlc_hw);
@ -2065,7 +2055,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
/* restore the clk setting */
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
}
/* txfifo sizes needs to be modified(increased) since the newer cores
@ -2218,7 +2208,7 @@ static void brcms_c_gpio_init(struct brcms_c_info *wlc)
gm |= gc |= BOARD_GPIO_PACTRL;
/* apply to gpiocontrol register */
ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
bcma_chipco_gpio_control(&wlc_hw->d11core->bus->drv_cc, gm, gc);
}
static void brcms_ucode_write(struct brcms_hardware *wlc_hw,
@ -3371,7 +3361,7 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/* disable interrupts */
macintmask = brcms_intrsoff(wlc->wl);
@ -3405,7 +3395,7 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
/* restore the clk */
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
}
static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
@ -4436,17 +4426,22 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
uint unit, bool piomode)
{
struct brcms_hardware *wlc_hw;
char *macaddr = NULL;
uint err = 0;
uint j;
bool wme = false;
struct shared_phy_params sha_params;
struct wiphy *wiphy = wlc->wiphy;
struct pci_dev *pcidev = core->bus->host_pci;
struct ssb_sprom *sprom = &core->bus->sprom;
BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
pcidev->vendor,
pcidev->device);
if (core->bus->hosttype == BCMA_HOSTTYPE_PCI)
BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
pcidev->vendor,
pcidev->device);
else
BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
core->bus->boardinfo.vendor,
core->bus->boardinfo.type);
wme = true;
@ -4472,7 +4467,8 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
}
/* verify again the device is supported */
if (!brcms_c_chipmatch(pcidev->vendor, pcidev->device)) {
if (core->bus->hosttype == BCMA_HOSTTYPE_PCI &&
!brcms_c_chipmatch(pcidev->vendor, pcidev->device)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported "
"vendor/device (0x%x/0x%x)\n",
unit, pcidev->vendor, pcidev->device);
@ -4480,8 +4476,13 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
goto fail;
}
wlc_hw->vendorid = pcidev->vendor;
wlc_hw->deviceid = pcidev->device;
if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
wlc_hw->vendorid = pcidev->vendor;
wlc_hw->deviceid = pcidev->device;
} else {
wlc_hw->vendorid = core->bus->boardinfo.vendor;
wlc_hw->deviceid = core->bus->boardinfo.type;
}
wlc_hw->d11core = core;
wlc_hw->corerev = core->id.rev;
@ -4501,7 +4502,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
* is still false; But it will be called again inside wlc_corereset,
* after d11 is out of reset.
*/
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
if (!brcms_b_validate_chip_access(wlc_hw)) {
@ -4512,7 +4513,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
}
/* get the board rev, used just below */
j = getintvar(wlc_hw->sih, BRCMS_SROM_BOARDREV);
j = sprom->board_rev;
/* promote srom boardrev of 0xFF to 1 */
if (j == BOARDREV_PROMOTABLE)
j = BOARDREV_PROMOTED;
@ -4525,11 +4526,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
err = 15;
goto fail;
}
wlc_hw->sromrev = (u8) getintvar(wlc_hw->sih, BRCMS_SROM_REV);
wlc_hw->boardflags = (u32) getintvar(wlc_hw->sih,
BRCMS_SROM_BOARDFLAGS);
wlc_hw->boardflags2 = (u32) getintvar(wlc_hw->sih,
BRCMS_SROM_BOARDFLAGS2);
wlc_hw->sromrev = sprom->revision;
wlc_hw->boardflags = sprom->boardflags_lo + (sprom->boardflags_hi << 16);
wlc_hw->boardflags2 = sprom->boardflags2_lo + (sprom->boardflags2_hi << 16);
if (wlc_hw->boardflags & BFL_NOPLLDOWN)
brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
@ -4702,25 +4701,18 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
*/
/* init etheraddr state variables */
macaddr = brcms_c_get_macaddr(wlc_hw);
if (macaddr == NULL) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n",
unit);
err = 21;
goto fail;
}
if (!mac_pton(macaddr, wlc_hw->etheraddr) ||
is_broadcast_ether_addr(wlc_hw->etheraddr) ||
brcms_c_get_macaddr(wlc_hw, wlc_hw->etheraddr);
if (is_broadcast_ether_addr(wlc_hw->etheraddr) ||
is_zero_ether_addr(wlc_hw->etheraddr)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n",
unit, macaddr);
wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr\n",
unit);
err = 22;
goto fail;
}
BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih),
macaddr);
BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x\n",
wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih));
return err;
@ -4770,16 +4762,16 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
int aa;
uint unit;
int bandtype;
struct si_pub *sih = wlc->hw->sih;
struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
unit = wlc->pub->unit;
bandtype = wlc->band->bandtype;
/* get antennas available */
if (bandtype == BRCM_BAND_5G)
aa = (s8) getintvar(sih, BRCMS_SROM_AA5G);
aa = sprom->ant_available_a;
else
aa = (s8) getintvar(sih, BRCMS_SROM_AA2G);
aa = sprom->ant_available_bg;
if ((aa < 1) || (aa > 15)) {
wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
@ -4799,9 +4791,9 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
/* Compute Antenna Gain */
if (bandtype == BRCM_BAND_5G)
wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG1);
wlc->band->antgain = sprom->antenna_gain.a1;
else
wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG0);
wlc->band->antgain = sprom->antenna_gain.a0;
brcms_c_attach_antgain_init(wlc);
@ -4952,15 +4944,6 @@ static int brcms_b_detach(struct brcms_c_info *wlc)
callbacks = 0;
if (wlc_hw->sih) {
/*
* detach interrupt sync mechanism since interrupt is disabled
* and per-port interrupt object may has been freed. this must
* be done before sb core switch
*/
ai_pci_sleep(wlc_hw->sih);
}
brcms_b_detach_dmapio(wlc_hw);
band = wlc_hw->band;
@ -5047,9 +5030,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
ai_pci_fixcfg(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/*
* TODO: test suspend/resume
@ -5078,8 +5059,6 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
{
uint coremask;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/*
@ -5088,15 +5067,14 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/*
* Configure pci/pcmcia here instead of in brcms_c_attach()
* to allow mfg hotswap: down, hotswap (chip power cycle), up.
*/
coremask = (1 << wlc_hw->wlc->core->coreidx);
ai_pci_setup(wlc_hw->sih, coremask);
bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci, wlc_hw->d11core,
true);
/*
* Need to read the hwradio status here to cover the case where the
@ -5126,7 +5104,7 @@ static int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
/* FULLY enable dynamic power control and d11 core interrupt */
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
brcms_intrson(wlc_hw->wlc->wl);
return 0;
}
@ -5267,7 +5245,7 @@ static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
brcms_intrsoff(wlc_hw->wlc->wl);
/* ensure we're running on the pll clock again */
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
}
/* down phy at the last of this stage */
callbacks += wlc_phy_down(wlc_hw->band->pi);

View file

@ -1,826 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <defs.h>
#include <soc.h>
#include <chipcommon.h>
#include "aiutils.h"
#include "pub.h"
#include "nicpci.h"
/* SPROM offsets */
#define SRSH_ASPM_OFFSET 4 /* word 4 */
#define SRSH_ASPM_ENB 0x18 /* bit 3, 4 */
#define SRSH_ASPM_L1_ENB 0x10 /* bit 4 */
#define SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */
#define SRSH_PCIE_MISC_CONFIG 5 /* word 5 */
#define SRSH_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */
#define SRSH_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */
#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */
#define SRSH_BD_OFFSET 6 /* word 6 */
/* chipcontrol */
#define CHIPCTRL_4321_PLL_DOWN 0x800000/* serdes PLL down override */
/* MDIO control */
#define MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */
#define MDIOCTL_DIVISOR_VAL 0x2
#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */
#define MDIOCTL_ACCESS_DONE 0x100 /* Transaction complete */
/* MDIO Data */
#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */
#define MDIODATA_TA 0x00020000 /* Turnaround */
#define MDIODATA_REGADDR_SHF 18 /* Regaddr shift */
#define MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */
#define MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */
#define MDIODATA_DEVADDR_MASK 0x0f800000
/* Physmedia devaddr Mask */
/* MDIO Data for older revisions < 10 */
#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift */
#define MDIODATA_REGADDR_MASK_OLD 0x003c0000
/* Regaddr Mask */
#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift */
#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000
/* Physmedia devaddr Mask */
/* Transactions flags */
#define MDIODATA_WRITE 0x10000000
#define MDIODATA_READ 0x20000000
#define MDIODATA_START 0x40000000
#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */
#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */
/* serdes regs (rev < 10) */
#define MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */
#define MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */
#define MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */
/* SERDES RX registers */
#define SERDES_RX_CTRL 1 /* Rx cntrl */
#define SERDES_RX_TIMER1 2 /* Rx Timer1 */
#define SERDES_RX_CDR 6 /* CDR */
#define SERDES_RX_CDRBW 7 /* CDR BW */
/* SERDES RX control register */
#define SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */
#define SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */
/* SERDES PLL registers */
#define SERDES_PLL_CTRL 1 /* PLL control reg */
#define PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */
/* Linkcontrol reg offset in PCIE Cap */
#define PCIE_CAP_LINKCTRL_OFFSET 16 /* offset in pcie cap */
#define PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */
#define PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */
#define PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */
#define PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */
#define PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */
#define PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */
#define PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */
/* Power management threshold */
#define PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* bits 8 - 15 */
#define PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */
#define PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */
#define PCIE_ASPMTIMER_EXTEND 0x01000000
/* > rev7:
* enable extend ASPM timer
*/
/* different register spaces to access thru pcie indirect access */
#define PCIE_CONFIGREGS 1 /* Access to config space */
#define PCIE_PCIEREGS 2 /* Access to pcie registers */
/* PCIE protocol PHY diagnostic registers */
#define PCIE_PLP_STATUSREG 0x204 /* Status */
/* Status reg PCIE_PLP_STATUSREG */
#define PCIE_PLP_POLARITYINV_STAT 0x10
/* PCIE protocol DLLP diagnostic registers */
#define PCIE_DLLP_LCREG 0x100 /* Link Control */
#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
/* PCIE protocol TLP diagnostic registers */
#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */
/* Sonics to PCI translation types */
#define SBTOPCI_PREF 0x4 /* prefetch enable */
#define SBTOPCI_BURST 0x8 /* burst enable */
#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
#define PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */
/* PCI core index in SROM shadow area */
#define SRSH_PI_OFFSET 0 /* first word */
#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
#define SRSH_PI_SHIFT 12 /* bit 15:12 */
#define PCIREGOFFS(field) offsetof(struct sbpciregs, field)
#define PCIEREGOFFS(field) offsetof(struct sbpcieregs, field)
/* Sonics side: PCI core and host control registers */
struct sbpciregs {
u32 control; /* PCI control */
u32 PAD[3];
u32 arbcontrol; /* PCI arbiter control */
u32 clkrun; /* Clkrun Control (>=rev11) */
u32 PAD[2];
u32 intstatus; /* Interrupt status */
u32 intmask; /* Interrupt mask */
u32 sbtopcimailbox; /* Sonics to PCI mailbox */
u32 PAD[9];
u32 bcastaddr; /* Sonics broadcast address */
u32 bcastdata; /* Sonics broadcast data */
u32 PAD[2];
u32 gpioin; /* ro: gpio input (>=rev2) */
u32 gpioout; /* rw: gpio output (>=rev2) */
u32 gpioouten; /* rw: gpio output enable (>= rev2) */
u32 gpiocontrol; /* rw: gpio control (>= rev2) */
u32 PAD[36];
u32 sbtopci0; /* Sonics to PCI translation 0 */
u32 sbtopci1; /* Sonics to PCI translation 1 */
u32 sbtopci2; /* Sonics to PCI translation 2 */
u32 PAD[189];
u32 pcicfg[4][64]; /* 0x400 - 0x7FF, PCI Cfg Space (>=rev8) */
u16 sprom[36]; /* SPROM shadow Area */
u32 PAD[46];
};
/* SB side: PCIE core and host control registers */
struct sbpcieregs {
u32 control; /* host mode only */
u32 PAD[2];
u32 biststatus; /* bist Status: 0x00C */
u32 gpiosel; /* PCIE gpio sel: 0x010 */
u32 gpioouten; /* PCIE gpio outen: 0x14 */
u32 PAD[2];
u32 intstatus; /* Interrupt status: 0x20 */
u32 intmask; /* Interrupt mask: 0x24 */
u32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */
u32 PAD[53];
u32 sbtopcie0; /* sb to pcie translation 0: 0x100 */
u32 sbtopcie1; /* sb to pcie translation 1: 0x104 */
u32 sbtopcie2; /* sb to pcie translation 2: 0x108 */
u32 PAD[5];
/* pcie core supports in direct access to config space */
u32 configaddr; /* pcie config space access: Address field: 0x120 */
u32 configdata; /* pcie config space access: Data field: 0x124 */
/* mdio access to serdes */
u32 mdiocontrol; /* controls the mdio access: 0x128 */
u32 mdiodata; /* Data to the mdio access: 0x12c */
/* pcie protocol phy/dllp/tlp register indirect access mechanism */
u32 pcieindaddr; /* indirect access to
* the internal register: 0x130
*/
u32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */
u32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */
u32 PAD[177];
u32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */
u16 sprom[64]; /* SPROM shadow Area */
};
struct pcicore_info {
struct bcma_device *core;
struct si_pub *sih; /* System interconnect handle */
struct pci_dev *dev;
u8 pciecap_lcreg_offset;/* PCIE capability LCreg offset
* in the config space
*/
bool pcie_pr42767;
u8 pcie_polarity;
u8 pcie_war_aspm_ovr; /* Override ASPM/Clkreq settings */
u8 pmecap_offset; /* PM Capability offset in the config space */
bool pmecap; /* Capable of generating PME */
};
#define PCIE_ASPM(sih) \
((ai_get_buscoretype(sih) == PCIE_CORE_ID) && \
((ai_get_buscorerev(sih) >= 3) && \
(ai_get_buscorerev(sih) <= 5)))
/* delay needed between the mdio control/ mdiodata register data access */
static void pr28829_delay(void)
{
udelay(10);
}
/* Initialize the PCI core.
* It's caller's responsibility to make sure that this is done only once
*/
struct pcicore_info *pcicore_init(struct si_pub *sih, struct bcma_device *core)
{
struct pcicore_info *pi;
/* alloc struct pcicore_info */
pi = kzalloc(sizeof(struct pcicore_info), GFP_ATOMIC);
if (pi == NULL)
return NULL;
pi->sih = sih;
pi->dev = core->bus->host_pci;
pi->core = core;
if (core->id.id == PCIE_CORE_ID) {
u8 cap_ptr;
cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_EXP,
NULL, NULL);
pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET;
}
return pi;
}
void pcicore_deinit(struct pcicore_info *pch)
{
kfree(pch);
}
/* return cap_offset if requested capability exists in the PCI config space */
/* Note that it's caller's responsibility to make sure it's a pci bus */
u8
pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
unsigned char *buf, u32 *buflen)
{
u8 cap_id;
u8 cap_ptr = 0;
u32 bufsize;
u8 byte_val;
/* check for Header type 0 */
pci_read_config_byte(dev, PCI_HEADER_TYPE, &byte_val);
if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
goto end;
/* check if the capability pointer field exists */
pci_read_config_byte(dev, PCI_STATUS, &byte_val);
if (!(byte_val & PCI_STATUS_CAP_LIST))
goto end;
pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr);
/* check if the capability pointer is 0x00 */
if (cap_ptr == 0x00)
goto end;
/* loop thru the capability list
* and see if the pcie capability exists
*/
pci_read_config_byte(dev, cap_ptr, &cap_id);
while (cap_id != req_cap_id) {
pci_read_config_byte(dev, cap_ptr + 1, &cap_ptr);
if (cap_ptr == 0x00)
break;
pci_read_config_byte(dev, cap_ptr, &cap_id);
}
if (cap_id != req_cap_id)
goto end;
/* found the caller requested capability */
if (buf != NULL && buflen != NULL) {
u8 cap_data;
bufsize = *buflen;
if (!bufsize)
goto end;
*buflen = 0;
/* copy the capability data excluding cap ID and next ptr */
cap_data = cap_ptr + 2;
if ((bufsize + cap_data) > PCI_SZPCR)
bufsize = PCI_SZPCR - cap_data;
*buflen = bufsize;
while (bufsize--) {
pci_read_config_byte(dev, cap_data, buf);
cap_data++;
buf++;
}
}
end:
return cap_ptr;
}
/* ***** Register Access API */
static uint
pcie_readreg(struct bcma_device *core, uint addrtype, uint offset)
{
uint retval = 0xFFFFFFFF;
switch (addrtype) {
case PCIE_CONFIGREGS:
bcma_write32(core, PCIEREGOFFS(configaddr), offset);
(void)bcma_read32(core, PCIEREGOFFS(configaddr));
retval = bcma_read32(core, PCIEREGOFFS(configdata));
break;
case PCIE_PCIEREGS:
bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset);
(void)bcma_read32(core, PCIEREGOFFS(pcieindaddr));
retval = bcma_read32(core, PCIEREGOFFS(pcieinddata));
break;
}
return retval;
}
static uint pcie_writereg(struct bcma_device *core, uint addrtype,
uint offset, uint val)
{
switch (addrtype) {
case PCIE_CONFIGREGS:
bcma_write32(core, PCIEREGOFFS(configaddr), offset);
bcma_write32(core, PCIEREGOFFS(configdata), val);
break;
case PCIE_PCIEREGS:
bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset);
bcma_write32(core, PCIEREGOFFS(pcieinddata), val);
break;
default:
break;
}
return 0;
}
static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk)
{
uint mdiodata, i = 0;
uint pcie_serdes_spinwait = 200;
mdiodata = (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA |
(MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
(MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) |
(blk << 4));
bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata);
pr28829_delay();
/* retry till the transaction is complete */
while (i < pcie_serdes_spinwait) {
if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) &
MDIOCTL_ACCESS_DONE)
break;
udelay(1000);
i++;
}
if (i >= pcie_serdes_spinwait)
return false;
return true;
}
static int
pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write,
uint *val)
{
uint mdiodata;
uint i = 0;
uint pcie_serdes_spinwait = 10;
/* enable mdio access to SERDES */
bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol),
MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
if (ai_get_buscorerev(pi->sih) >= 10) {
/* new serdes is slower in rw,
* using two layers of reg address mapping
*/
if (!pcie_mdiosetblock(pi, physmedia))
return 1;
mdiodata = ((MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
(regaddr << MDIODATA_REGADDR_SHF));
pcie_serdes_spinwait *= 20;
} else {
mdiodata = ((physmedia << MDIODATA_DEVADDR_SHF_OLD) |
(regaddr << MDIODATA_REGADDR_SHF_OLD));
}
if (!write)
mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA);
else
mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA |
*val);
bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata);
pr28829_delay();
/* retry till the transaction is complete */
while (i < pcie_serdes_spinwait) {
if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) &
MDIOCTL_ACCESS_DONE) {
if (!write) {
pr28829_delay();
*val = (bcma_read32(pi->core,
PCIEREGOFFS(mdiodata)) &
MDIODATA_MASK);
}
/* Disable mdio access to SERDES */
bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0);
return 0;
}
udelay(1000);
i++;
}
/* Timed out. Disable mdio access to SERDES. */
bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0);
return 1;
}
/* use the mdio interface to read from mdio slaves */
static int
pcie_mdioread(struct pcicore_info *pi, uint physmedia, uint regaddr,
uint *regval)
{
return pcie_mdioop(pi, physmedia, regaddr, false, regval);
}
/* use the mdio interface to write to mdio slaves */
static int
pcie_mdiowrite(struct pcicore_info *pi, uint physmedia, uint regaddr, uint val)
{
return pcie_mdioop(pi, physmedia, regaddr, true, &val);
}
/* ***** Support functions ***** */
static u8 pcie_clkreq(struct pcicore_info *pi, u32 mask, u32 val)
{
u32 reg_val;
u8 offset;
offset = pi->pciecap_lcreg_offset;
if (!offset)
return 0;
pci_read_config_dword(pi->dev, offset, &reg_val);
/* set operation */
if (mask) {
if (val)
reg_val |= PCIE_CLKREQ_ENAB;
else
reg_val &= ~PCIE_CLKREQ_ENAB;
pci_write_config_dword(pi->dev, offset, reg_val);
pci_read_config_dword(pi->dev, offset, &reg_val);
}
if (reg_val & PCIE_CLKREQ_ENAB)
return 1;
else
return 0;
}
static void pcie_extendL1timer(struct pcicore_info *pi, bool extend)
{
u32 w;
struct si_pub *sih = pi->sih;
if (ai_get_buscoretype(sih) != PCIE_CORE_ID ||
ai_get_buscorerev(sih) < 7)
return;
w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
if (extend)
w |= PCIE_ASPMTIMER_EXTEND;
else
w &= ~PCIE_ASPMTIMER_EXTEND;
pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
}
/* centralized clkreq control policy */
static void pcie_clkreq_upd(struct pcicore_info *pi, uint state)
{
struct si_pub *sih = pi->sih;
switch (state) {
case SI_DOATTACH:
if (PCIE_ASPM(sih))
pcie_clkreq(pi, 1, 0);
break;
case SI_PCIDOWN:
/* turn on serdes PLL down */
if (ai_get_buscorerev(sih) == 6) {
ai_cc_reg(sih,
offsetof(struct chipcregs, chipcontrol_addr),
~0, 0);
ai_cc_reg(sih,
offsetof(struct chipcregs, chipcontrol_data),
~0x40, 0);
} else if (pi->pcie_pr42767) {
pcie_clkreq(pi, 1, 1);
}
break;
case SI_PCIUP:
/* turn off serdes PLL down */
if (ai_get_buscorerev(sih) == 6) {
ai_cc_reg(sih,
offsetof(struct chipcregs, chipcontrol_addr),
~0, 0);
ai_cc_reg(sih,
offsetof(struct chipcregs, chipcontrol_data),
~0x40, 0x40);
} else if (PCIE_ASPM(sih)) { /* disable clkreq */
pcie_clkreq(pi, 1, 0);
}
break;
}
}
/* ***** PCI core WARs ***** */
/* Done only once at attach time */
static void pcie_war_polarity(struct pcicore_info *pi)
{
u32 w;
if (pi->pcie_polarity != 0)
return;
w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_PLP_STATUSREG);
/* Detect the current polarity at attach and force that polarity and
* disable changing the polarity
*/
if ((w & PCIE_PLP_POLARITYINV_STAT) == 0)
pi->pcie_polarity = SERDES_RX_CTRL_FORCE;
else
pi->pcie_polarity = (SERDES_RX_CTRL_FORCE |
SERDES_RX_CTRL_POLARITY);
}
/* enable ASPM and CLKREQ if srom doesn't have it */
/* Needs to happen when update to shadow SROM is needed
* : Coming out of 'standby'/'hibernate'
* : If pcie_war_aspm_ovr state changed
*/
static void pcie_war_aspm_clkreq(struct pcicore_info *pi)
{
struct si_pub *sih = pi->sih;
u16 val16;
u32 w;
if (!PCIE_ASPM(sih))
return;
/* bypass this on QT or VSIM */
val16 = bcma_read16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET]));
val16 &= ~SRSH_ASPM_ENB;
if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB)
val16 |= SRSH_ASPM_ENB;
else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB)
val16 |= SRSH_ASPM_L1_ENB;
else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB)
val16 |= SRSH_ASPM_L0s_ENB;
bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET]), val16);
pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w);
w &= ~PCIE_ASPM_ENAB;
w |= pi->pcie_war_aspm_ovr;
pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w);
val16 = bcma_read16(pi->core,
PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5]));
if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) {
val16 |= SRSH_CLKREQ_ENB;
pi->pcie_pr42767 = true;
} else
val16 &= ~SRSH_CLKREQ_ENB;
bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5]),
val16);
}
/* Apply the polarity determined at the start */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_war_serdes(struct pcicore_info *pi)
{
u32 w = 0;
if (pi->pcie_polarity != 0)
pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL,
pi->pcie_polarity);
pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w);
if (w & PLL_CTRL_FREQDET_EN) {
w &= ~PLL_CTRL_FREQDET_EN;
pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w);
}
}
/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_misc_config_fixup(struct pcicore_info *pi)
{
u16 val16;
val16 = bcma_read16(pi->core,
PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG]));
if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) {
val16 |= SRSH_L23READY_EXIT_NOPERST;
bcma_write16(pi->core,
PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG]), val16);
}
}
/* quick hack for testing */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_war_noplldown(struct pcicore_info *pi)
{
/* turn off serdes PLL down */
ai_cc_reg(pi->sih, offsetof(struct chipcregs, chipcontrol),
CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN);
/* clear srom shadow backdoor */
bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_BD_OFFSET]), 0);
}
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_war_pci_setup(struct pcicore_info *pi)
{
struct si_pub *sih = pi->sih;
u32 w;
if (ai_get_buscorerev(sih) == 0 || ai_get_buscorerev(sih) == 1) {
w = pcie_readreg(pi->core, PCIE_PCIEREGS,
PCIE_TLP_WORKAROUNDSREG);
w |= 0x8;
pcie_writereg(pi->core, PCIE_PCIEREGS,
PCIE_TLP_WORKAROUNDSREG, w);
}
if (ai_get_buscorerev(sih) == 1) {
w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG);
w |= 0x40;
pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w);
}
if (ai_get_buscorerev(sih) == 0) {
pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
} else if (PCIE_ASPM(sih)) {
/* Change the L1 threshold for better performance */
w = pcie_readreg(pi->core, PCIE_PCIEREGS,
PCIE_DLLP_PMTHRESHREG);
w &= ~PCIE_L1THRESHOLDTIME_MASK;
w |= PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT;
pcie_writereg(pi->core, PCIE_PCIEREGS,
PCIE_DLLP_PMTHRESHREG, w);
pcie_war_serdes(pi);
pcie_war_aspm_clkreq(pi);
} else if (ai_get_buscorerev(pi->sih) == 7)
pcie_war_noplldown(pi);
/* Note that the fix is actually in the SROM,
* that's why this is open-ended
*/
if (ai_get_buscorerev(pi->sih) >= 6)
pcie_misc_config_fixup(pi);
}
/* ***** Functions called during driver state changes ***** */
void pcicore_attach(struct pcicore_info *pi, int state)
{
struct si_pub *sih = pi->sih;
u32 bfl2 = (u32)getintvar(sih, BRCMS_SROM_BOARDFLAGS2);
/* Determine if this board needs override */
if (PCIE_ASPM(sih)) {
if (bfl2 & BFL2_PCIEWAR_OVR)
pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB;
else
pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB;
}
/* These need to happen in this order only */
pcie_war_polarity(pi);
pcie_war_serdes(pi);
pcie_war_aspm_clkreq(pi);
pcie_clkreq_upd(pi, state);
}
void pcicore_hwup(struct pcicore_info *pi)
{
if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID)
return;
pcie_war_pci_setup(pi);
}
void pcicore_up(struct pcicore_info *pi, int state)
{
if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID)
return;
/* Restore L1 timer for better performance */
pcie_extendL1timer(pi, true);
pcie_clkreq_upd(pi, state);
}
/* When the device is going to enter D3 state
* (or the system is going to enter S3/S4 states)
*/
void pcicore_sleep(struct pcicore_info *pi)
{
u32 w;
if (!pi || !PCIE_ASPM(pi->sih))
return;
pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w);
w &= ~PCIE_CAP_LCREG_ASPML1;
pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w);
pi->pcie_pr42767 = false;
}
void pcicore_down(struct pcicore_info *pi, int state)
{
if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID)
return;
pcie_clkreq_upd(pi, state);
/* Reduce L1 timer for better power savings */
pcie_extendL1timer(pi, false);
}
void pcicore_fixcfg(struct pcicore_info *pi)
{
struct bcma_device *core = pi->core;
u16 val16;
uint regoff;
switch (pi->core->id.id) {
case BCMA_CORE_PCI:
regoff = PCIREGOFFS(sprom[SRSH_PI_OFFSET]);
break;
case BCMA_CORE_PCIE:
regoff = PCIEREGOFFS(sprom[SRSH_PI_OFFSET]);
break;
default:
return;
}
val16 = bcma_read16(pi->core, regoff);
if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) !=
(u16)core->core_index) {
val16 = ((u16)core->core_index << SRSH_PI_SHIFT) |
(val16 & ~SRSH_PI_MASK);
bcma_write16(pi->core, regoff, val16);
}
}
/* precondition: current core is pci core */
void
pcicore_pci_setup(struct pcicore_info *pi)
{
bcma_set32(pi->core, PCIREGOFFS(sbtopci2),
SBTOPCI_PREF | SBTOPCI_BURST);
if (pi->core->id.rev >= 11) {
bcma_set32(pi->core, PCIREGOFFS(sbtopci2),
SBTOPCI_RC_READMULTI);
bcma_set32(pi->core, PCIREGOFFS(clkrun), PCI_CLKRUN_DSBL);
(void)bcma_read32(pi->core, PCIREGOFFS(clkrun));
}
}

View file

@ -1,77 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_NICPCI_H_
#define _BRCM_NICPCI_H_
#include "types.h"
/* PCI configuration address space size */
#define PCI_SZPCR 256
/* Brcm PCI configuration registers */
/* backplane address space accessed by BAR0 */
#define PCI_BAR0_WIN 0x80
/* sprom property control */
#define PCI_SPROM_CONTROL 0x88
/* mask of PCI and other cores interrupts */
#define PCI_INT_MASK 0x94
/* backplane core interrupt mask bits offset */
#define PCI_SBIM_SHIFT 8
/* backplane address space accessed by second 4KB of BAR0 */
#define PCI_BAR0_WIN2 0xac
/* pci config space gpio input (>=rev3) */
#define PCI_GPIO_IN 0xb0
/* pci config space gpio output (>=rev3) */
#define PCI_GPIO_OUT 0xb4
/* pci config space gpio output enable (>=rev3) */
#define PCI_GPIO_OUTEN 0xb8
/* bar0 + 4K accesses external sprom */
#define PCI_BAR0_SPROM_OFFSET (4 * 1024)
/* bar0 + 6K accesses pci core registers */
#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024)
/*
* pci core SB registers are at the end of the
* 8KB window, so their address is the "regular"
* address plus 4K
*/
#define PCI_BAR0_PCISBR_OFFSET (4 * 1024)
/* bar0 window size Match with corerev 13 */
#define PCI_BAR0_WINSZ (16 * 1024)
/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */
/* bar0 + 8K accesses pci/pcie core registers */
#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024)
/* bar0 + 12K accesses chipc core registers */
#define PCI_16KB0_CCREGS_OFFSET (12 * 1024)
struct sbpciregs;
struct sbpcieregs;
extern struct pcicore_info *pcicore_init(struct si_pub *sih,
struct bcma_device *core);
extern void pcicore_deinit(struct pcicore_info *pch);
extern void pcicore_attach(struct pcicore_info *pch, int state);
extern void pcicore_hwup(struct pcicore_info *pch);
extern void pcicore_up(struct pcicore_info *pch, int state);
extern void pcicore_sleep(struct pcicore_info *pch);
extern void pcicore_down(struct pcicore_info *pch, int state);
extern u8 pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
unsigned char *buf, u32 *buflen);
extern void pcicore_fixcfg(struct pcicore_info *pch);
extern void pcicore_pci_setup(struct pcicore_info *pch);
#endif /* _BRCM_NICPCI_H_ */

View file

@ -1,410 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <brcm_hw_ids.h>
#include <chipcommon.h>
#include "aiutils.h"
#include "otp.h"
#define OTPS_GUP_MASK 0x00000f00
#define OTPS_GUP_SHIFT 8
/* h/w subregion is programmed */
#define OTPS_GUP_HW 0x00000100
/* s/w subregion is programmed */
#define OTPS_GUP_SW 0x00000200
/* chipid/pkgopt subregion is programmed */
#define OTPS_GUP_CI 0x00000400
/* fuse subregion is programmed */
#define OTPS_GUP_FUSE 0x00000800
/* Fields in otpprog in rev >= 21 */
#define OTPP_COL_MASK 0x000000ff
#define OTPP_COL_SHIFT 0
#define OTPP_ROW_MASK 0x0000ff00
#define OTPP_ROW_SHIFT 8
#define OTPP_OC_MASK 0x0f000000
#define OTPP_OC_SHIFT 24
#define OTPP_READERR 0x10000000
#define OTPP_VALUE_MASK 0x20000000
#define OTPP_VALUE_SHIFT 29
#define OTPP_START_BUSY 0x80000000
#define OTPP_READ 0x40000000
/* Opcodes for OTPP_OC field */
#define OTPPOC_READ 0
#define OTPPOC_BIT_PROG 1
#define OTPPOC_VERIFY 3
#define OTPPOC_INIT 4
#define OTPPOC_SET 5
#define OTPPOC_RESET 6
#define OTPPOC_OCST 7
#define OTPPOC_ROW_LOCK 8
#define OTPPOC_PRESCN_TEST 9
#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
#define OTPP_TRIES 10000000 /* # of tries for OTPP */
#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
/* Fixed size subregions sizes in words */
#define OTPGU_CI_SZ 2
struct otpinfo;
/* OTP function struct */
struct otp_fn_s {
int (*init)(struct si_pub *sih, struct otpinfo *oi);
int (*read_region)(struct otpinfo *oi, int region, u16 *data,
uint *wlen);
};
struct otpinfo {
struct bcma_device *core; /* chipc core */
const struct otp_fn_s *fn; /* OTP functions */
struct si_pub *sih; /* Saved sb handle */
/* IPX OTP section */
u16 wsize; /* Size of otp in words */
u16 rows; /* Geometry */
u16 cols; /* Geometry */
u32 status; /* Flag bits (lock/prog/rv).
* (Reflected only when OTP is power cycled)
*/
u16 hwbase; /* hardware subregion offset */
u16 hwlim; /* hardware subregion boundary */
u16 swbase; /* software subregion offset */
u16 swlim; /* software subregion boundary */
u16 fbase; /* fuse subregion offset */
u16 flim; /* fuse subregion boundary */
int otpgu_base; /* offset to General Use Region */
};
/* OTP layout */
/* CC revs 21, 24 and 27 OTP General Use Region word offset */
#define REVA4_OTPGU_BASE 12
/* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
#define REVB8_OTPGU_BASE 20
/* CC rev 36 OTP General Use Region word offset */
#define REV36_OTPGU_BASE 12
/* Subregion word offsets in General Use region */
#define OTPGU_HSB_OFF 0
#define OTPGU_SFB_OFF 1
#define OTPGU_CI_OFF 2
#define OTPGU_P_OFF 3
#define OTPGU_SROM_OFF 4
/* Flag bit offsets in General Use region */
#define OTPGU_HWP_OFF 60
#define OTPGU_SWP_OFF 61
#define OTPGU_CIP_OFF 62
#define OTPGU_FUSEP_OFF 63
#define OTPGU_CIP_MSK 0x4000
#define OTPGU_P_MSK 0xf000
#define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16)
/* OTP Size */
#define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */
#define OTP_SZ_FU_288 (288/8) /* 288 bits */
#define OTP_SZ_FU_216 (216/8) /* 216 bits */
#define OTP_SZ_FU_72 (72/8) /* 72 bits */
#define OTP_SZ_CHECKSUM (16/8) /* 16 bits */
#define OTP4315_SWREG_SZ 178 /* 178 bytes */
#define OTP_SZ_FU_144 (144/8) /* 144 bits */
static u16
ipxotp_otpr(struct otpinfo *oi, uint wn)
{
return bcma_read16(oi->core,
CHIPCREGOFFS(sromotp[wn]));
}
/*
* Calculate max HW/SW region byte size by subtracting fuse region
* and checksum size, osizew is oi->wsize (OTP size - GU size) in words
*/
static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
{
int ret = 0;
switch (ai_get_chip_id(sih)) {
case BCM43224_CHIP_ID:
case BCM43225_CHIP_ID:
ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
break;
case BCM4313_CHIP_ID:
ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
break;
default:
break; /* Don't know about this chip */
}
return ret;
}
static void _ipxotp_init(struct otpinfo *oi)
{
uint k;
u32 otpp, st;
int ccrev = ai_get_ccrev(oi->sih);
/*
* record word offset of General Use Region
* for various chipcommon revs
*/
if (ccrev == 21 || ccrev == 24
|| ccrev == 27) {
oi->otpgu_base = REVA4_OTPGU_BASE;
} else if (ccrev == 36) {
/*
* OTP size greater than equal to 2KB (128 words),
* otpgu_base is similar to rev23
*/
if (oi->wsize >= 128)
oi->otpgu_base = REVB8_OTPGU_BASE;
else
oi->otpgu_base = REV36_OTPGU_BASE;
} else if (ccrev == 23 || ccrev >= 25) {
oi->otpgu_base = REVB8_OTPGU_BASE;
}
/* First issue an init command so the status is up to date */
otpp =
OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK);
bcma_write32(oi->core, CHIPCREGOFFS(otpprog), otpp);
st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog));
for (k = 0; (st & OTPP_START_BUSY) && (k < OTPP_TRIES); k++)
st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog));
if (k >= OTPP_TRIES)
return;
/* Read OTP lock bits and subregion programmed indication bits */
oi->status = bcma_read32(oi->core, CHIPCREGOFFS(otpstatus));
if ((ai_get_chip_id(oi->sih) == BCM43224_CHIP_ID)
|| (ai_get_chip_id(oi->sih) == BCM43225_CHIP_ID)) {
u32 p_bits;
p_bits = (ipxotp_otpr(oi, oi->otpgu_base + OTPGU_P_OFF) &
OTPGU_P_MSK) >> OTPGU_P_SHIFT;
oi->status |= (p_bits << OTPS_GUP_SHIFT);
}
/*
* h/w region base and fuse region limit are fixed to
* the top and the bottom of the general use region.
* Everything else can be flexible.
*/
oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF;
oi->hwlim = oi->wsize;
if (oi->status & OTPS_GUP_HW) {
oi->hwlim =
ipxotp_otpr(oi, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
oi->swbase = oi->hwlim;
} else
oi->swbase = oi->hwbase;
/* subtract fuse and checksum from beginning */
oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2;
if (oi->status & OTPS_GUP_SW) {
oi->swlim =
ipxotp_otpr(oi, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
oi->fbase = oi->swlim;
} else
oi->fbase = oi->swbase;
oi->flim = oi->wsize;
}
static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi)
{
/* Make sure we're running IPX OTP */
if (!OTPTYPE_IPX(ai_get_ccrev(sih)))
return -EBADE;
/* Make sure OTP is not disabled */
if (ai_is_otp_disabled(sih))
return -EBADE;
/* Check for otp size */
switch ((ai_get_cccaps(sih) & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
case 0:
/* Nothing there */
return -EBADE;
case 1: /* 32x64 */
oi->rows = 32;
oi->cols = 64;
oi->wsize = 128;
break;
case 2: /* 64x64 */
oi->rows = 64;
oi->cols = 64;
oi->wsize = 256;
break;
case 5: /* 96x64 */
oi->rows = 96;
oi->cols = 64;
oi->wsize = 384;
break;
case 7: /* 16x64 *//* 1024 bits */
oi->rows = 16;
oi->cols = 64;
oi->wsize = 64;
break;
default:
/* Don't know the geometry */
return -EBADE;
}
/* Retrieve OTP region info */
_ipxotp_init(oi);
return 0;
}
static int
ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen)
{
uint base, i, sz;
/* Validate region selection */
switch (region) {
case OTP_HW_RGN:
sz = (uint) oi->hwlim - oi->hwbase;
if (!(oi->status & OTPS_GUP_HW)) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->hwbase;
break;
case OTP_SW_RGN:
sz = ((uint) oi->swlim - oi->swbase);
if (!(oi->status & OTPS_GUP_SW)) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->swbase;
break;
case OTP_CI_RGN:
sz = OTPGU_CI_SZ;
if (!(oi->status & OTPS_GUP_CI)) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->otpgu_base + OTPGU_CI_OFF;
break;
case OTP_FUSE_RGN:
sz = (uint) oi->flim - oi->fbase;
if (!(oi->status & OTPS_GUP_FUSE)) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->fbase;
break;
case OTP_ALL_RGN:
sz = ((uint) oi->flim - oi->hwbase);
if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->hwbase;
break;
default:
return -EINVAL;
}
/* Read the data */
for (i = 0; i < sz; i++)
data[i] = ipxotp_otpr(oi, base + i);
*wlen = sz;
return 0;
}
static const struct otp_fn_s ipxotp_fn = {
(int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init,
(int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region,
};
static int otp_init(struct si_pub *sih, struct otpinfo *oi)
{
int ret;
memset(oi, 0, sizeof(struct otpinfo));
oi->core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
if (OTPTYPE_IPX(ai_get_ccrev(sih)))
oi->fn = &ipxotp_fn;
if (oi->fn == NULL)
return -EBADE;
oi->sih = sih;
ret = (oi->fn->init)(sih, oi);
return ret;
}
int
otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) {
struct otpinfo otpinfo;
struct otpinfo *oi = &otpinfo;
int err = 0;
if (ai_is_otp_disabled(sih)) {
err = -EPERM;
goto out;
}
err = otp_init(sih, oi);
if (err)
goto out;
err = ((oi)->fn->read_region)(oi, region, data, wlen);
out:
return err;
}

View file

@ -1,36 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_OTP_H_
#define _BRCM_OTP_H_
#include "types.h"
/* OTP regions */
#define OTP_HW_RGN 1
#define OTP_SW_RGN 2
#define OTP_CI_RGN 4
#define OTP_FUSE_RGN 8
/* From h/w region to end of OTP including checksum */
#define OTP_ALL_RGN 0xf
/* OTP Size */
#define OTP_SZ_MAX (6144/8) /* maximum bytes in one CIS */
extern int otp_read_region(struct si_pub *sih, int region, u16 *data,
uint *wlen);
#endif /* _BRCM_OTP_H_ */

View file

@ -4817,28 +4817,23 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
s8 txpwr = 0;
int i;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
struct phy_shim_info *shim = pi->sh->physhim;
struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
if (CHSPEC_IS2G(pi->radio_chanspec)) {
u16 cckpo = 0;
u32 offset_ofdm, offset_mcs;
pi_lcn->lcnphy_tr_isolation_mid =
(u8)wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
pi_lcn->lcnphy_rx_power_offset =
(u8)wlapi_getintvar(shim, BRCMS_SROM_RXPO2G);
pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
pi->txpa_2g[0] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B0);
pi->txpa_2g[1] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B1);
pi->txpa_2g[2] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B2);
pi->txpa_2g[0] = sprom->pa0b0;
pi->txpa_2g[1] = sprom->pa0b1;
pi->txpa_2g[2] = sprom->pa0b2;
pi_lcn->lcnphy_rssi_vf =
(u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMF2G);
pi_lcn->lcnphy_rssi_vc =
(u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMC2G);
pi_lcn->lcnphy_rssi_gs =
(u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISAV2G);
pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
@ -4848,7 +4843,7 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
txpwr = (s8)wlapi_getintvar(shim, BRCMS_SROM_MAXP2GA0);
txpwr = sprom->core_pwr_info[0].maxpwr_2g;
pi->tx_srom_max_2g = txpwr;
for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
@ -4856,8 +4851,8 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
}
cckpo = (u16)wlapi_getintvar(shim, BRCMS_SROM_CCK2GPO);
offset_ofdm = (u32)wlapi_getintvar(shim, BRCMS_SROM_OFDM2GPO);
cckpo = sprom->cck2gpo;
offset_ofdm = sprom->ofdm2gpo;
if (cckpo) {
uint max_pwr_chan = txpwr;
@ -4876,7 +4871,7 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
} else {
u8 opo = 0;
opo = (u8)wlapi_getintvar(shim, BRCMS_SROM_OPO);
opo = sprom->opo;
for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
pi->tx_srom_max_rate_2g[i] = txpwr;
@ -4886,12 +4881,8 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
((offset_ofdm & 0xf) * 2);
offset_ofdm >>= 4;
}
offset_mcs =
wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO1) << 16;
offset_mcs |=
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO0);
offset_mcs = sprom->mcs2gpo[1] << 16;
offset_mcs |= sprom->mcs2gpo[0];
pi_lcn->lcnphy_mcs20_po = offset_mcs;
for (i = TXP_FIRST_SISO_MCS_20;
i <= TXP_LAST_SISO_MCS_20; i++) {
@ -4901,25 +4892,17 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
}
}
pi_lcn->lcnphy_rawtempsense =
(u16)wlapi_getintvar(shim, BRCMS_SROM_RAWTEMPSENSE);
pi_lcn->lcnphy_measPower =
(u8)wlapi_getintvar(shim, BRCMS_SROM_MEASPOWER);
pi_lcn->lcnphy_tempsense_slope =
(u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_SLOPE);
pi_lcn->lcnphy_hw_iqcal_en =
(bool)wlapi_getintvar(shim, BRCMS_SROM_HW_IQCAL_EN);
pi_lcn->lcnphy_iqcal_swp_dis =
(bool)wlapi_getintvar(shim, BRCMS_SROM_IQCAL_SWP_DIS);
pi_lcn->lcnphy_tempcorrx =
(u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPCORRX);
pi_lcn->lcnphy_tempsense_option =
(u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_OPTION);
pi_lcn->lcnphy_freqoffset_corr =
(u8)wlapi_getintvar(shim, BRCMS_SROM_FREQOFFSET_CORR);
if ((u8)wlapi_getintvar(shim, BRCMS_SROM_AA2G) > 1)
pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
pi_lcn->lcnphy_measPower = sprom->measpower;
pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
if (sprom->ant_available_bg > 1)
wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
(u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G));
sprom->ant_available_bg);
}
pi_lcn->lcnphy_cck_dig_filt_type = -1;

View file

@ -14386,30 +14386,30 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
{
u16 bw40po, cddpo, stbcpo, bwduppo;
uint band_num;
struct phy_shim_info *shim = pi->sh->physhim;
struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
if (pi->sh->sromrev >= 9)
return;
bw40po = (u16) wlapi_getintvar(shim, BRCMS_SROM_BW40PO);
bw40po = sprom->bw40po;
pi->bw402gpo = bw40po & 0xf;
pi->bw405gpo = (bw40po & 0xf0) >> 4;
pi->bw405glpo = (bw40po & 0xf00) >> 8;
pi->bw405ghpo = (bw40po & 0xf000) >> 12;
cddpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_CDDPO);
cddpo = sprom->cddpo;
pi->cdd2gpo = cddpo & 0xf;
pi->cdd5gpo = (cddpo & 0xf0) >> 4;
pi->cdd5glpo = (cddpo & 0xf00) >> 8;
pi->cdd5ghpo = (cddpo & 0xf000) >> 12;
stbcpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_STBCPO);
stbcpo = sprom->stbcpo;
pi->stbc2gpo = stbcpo & 0xf;
pi->stbc5gpo = (stbcpo & 0xf0) >> 4;
pi->stbc5glpo = (stbcpo & 0xf00) >> 8;
pi->stbc5ghpo = (stbcpo & 0xf000) >> 12;
bwduppo = (u16) wlapi_getintvar(shim, BRCMS_SROM_BWDUPPO);
bwduppo = sprom->bwduppo;
pi->bwdup2gpo = bwduppo & 0xf;
pi->bwdup5gpo = (bwduppo & 0xf0) >> 4;
pi->bwdup5glpo = (bwduppo & 0xf00) >> 8;
@ -14419,242 +14419,137 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
band_num++) {
switch (band_num) {
case 0:
pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP2GA0);
sprom->core_pwr_info[0].maxpwr_2g;
pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_2g =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP2GA1);
sprom->core_pwr_info[1].maxpwr_2g;
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW0A0);
sprom->core_pwr_info[0].pa_2g[0];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW0A1);
sprom->core_pwr_info[1].pa_2g[0];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW1A0);
sprom->core_pwr_info[0].pa_2g[1];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW1A1);
sprom->core_pwr_info[1].pa_2g[1];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW2A0);
sprom->core_pwr_info[0].pa_2g[2];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW2A1);
sprom->core_pwr_info[1].pa_2g[2];
pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_2g =
(s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA0);
sprom->core_pwr_info[0].itssi_2g;
pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_2g =
(s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA1);
sprom->core_pwr_info[1].itssi_2g;
pi->cck2gpo = (u16) wlapi_getintvar(shim,
BRCMS_SROM_CCK2GPO);
pi->cck2gpo = sprom->cck2gpo;
pi->ofdm2gpo =
(u32) wlapi_getintvar(shim,
BRCMS_SROM_OFDM2GPO);
pi->ofdm2gpo = sprom->ofdm2gpo;
pi->mcs2gpo[0] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO0);
pi->mcs2gpo[1] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO1);
pi->mcs2gpo[2] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO2);
pi->mcs2gpo[3] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO3);
pi->mcs2gpo[4] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO4);
pi->mcs2gpo[5] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO5);
pi->mcs2gpo[6] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO6);
pi->mcs2gpo[7] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO7);
pi->mcs2gpo[0] = sprom->mcs2gpo[0];
pi->mcs2gpo[1] = sprom->mcs2gpo[1];
pi->mcs2gpo[2] = sprom->mcs2gpo[2];
pi->mcs2gpo[3] = sprom->mcs2gpo[3];
pi->mcs2gpo[4] = sprom->mcs2gpo[4];
pi->mcs2gpo[5] = sprom->mcs2gpo[5];
pi->mcs2gpo[6] = sprom->mcs2gpo[6];
pi->mcs2gpo[7] = sprom->mcs2gpo[7];
break;
case 1:
pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm =
(s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0);
sprom->core_pwr_info[0].maxpwr_5g;
pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GA1);
sprom->core_pwr_info[1].maxpwr_5g;
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW0A0);
sprom->core_pwr_info[0].pa_5g[0];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW0A1);
sprom->core_pwr_info[1].pa_5g[0];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW1A0);
sprom->core_pwr_info[0].pa_5g[1];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW1A1);
sprom->core_pwr_info[1].pa_5g[1];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW2A0);
sprom->core_pwr_info[0].pa_5g[2];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW2A1);
sprom->core_pwr_info[1].pa_5g[2];
pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_5gm =
(s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA0);
sprom->core_pwr_info[0].itssi_5g;
pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_5gm =
(s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA1);
sprom->core_pwr_info[1].itssi_5g;
pi->ofdm5gpo =
(u32) wlapi_getintvar(shim,
BRCMS_SROM_OFDM5GPO);
pi->ofdm5gpo = sprom->ofdm5gpo;
pi->mcs5gpo[0] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO0);
pi->mcs5gpo[1] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO1);
pi->mcs5gpo[2] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO2);
pi->mcs5gpo[3] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO3);
pi->mcs5gpo[4] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO4);
pi->mcs5gpo[5] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO5);
pi->mcs5gpo[6] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO6);
pi->mcs5gpo[7] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO7);
pi->mcs5gpo[0] = sprom->mcs5gpo[0];
pi->mcs5gpo[1] = sprom->mcs5gpo[1];
pi->mcs5gpo[2] = sprom->mcs5gpo[2];
pi->mcs5gpo[3] = sprom->mcs5gpo[3];
pi->mcs5gpo[4] = sprom->mcs5gpo[4];
pi->mcs5gpo[5] = sprom->mcs5gpo[5];
pi->mcs5gpo[6] = sprom->mcs5gpo[6];
pi->mcs5gpo[7] = sprom->mcs5gpo[7];
break;
case 2:
pi->nphy_pwrctrl_info[0].max_pwr_5gl =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GLA0);
sprom->core_pwr_info[0].maxpwr_5gl;
pi->nphy_pwrctrl_info[1].max_pwr_5gl =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GLA1);
sprom->core_pwr_info[1].maxpwr_5gl;
pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW0A0);
sprom->core_pwr_info[0].pa_5gl[0];
pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW0A1);
sprom->core_pwr_info[1].pa_5gl[0];
pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW1A0);
sprom->core_pwr_info[0].pa_5gl[1];
pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW1A1);
sprom->core_pwr_info[1].pa_5gl[1];
pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW2A0);
sprom->core_pwr_info[0].pa_5gl[2];
pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW2A1);
sprom->core_pwr_info[1].pa_5gl[2];
pi->nphy_pwrctrl_info[0].idle_targ_5gl = 0;
pi->nphy_pwrctrl_info[1].idle_targ_5gl = 0;
pi->ofdm5glpo =
(u32) wlapi_getintvar(shim,
BRCMS_SROM_OFDM5GLPO);
pi->ofdm5glpo = sprom->ofdm5glpo;
pi->mcs5glpo[0] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO0);
pi->mcs5glpo[1] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO1);
pi->mcs5glpo[2] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO2);
pi->mcs5glpo[3] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO3);
pi->mcs5glpo[4] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO4);
pi->mcs5glpo[5] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO5);
pi->mcs5glpo[6] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO6);
pi->mcs5glpo[7] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO7);
pi->mcs5glpo[0] = sprom->mcs5glpo[0];
pi->mcs5glpo[1] = sprom->mcs5glpo[1];
pi->mcs5glpo[2] = sprom->mcs5glpo[2];
pi->mcs5glpo[3] = sprom->mcs5glpo[3];
pi->mcs5glpo[4] = sprom->mcs5glpo[4];
pi->mcs5glpo[5] = sprom->mcs5glpo[5];
pi->mcs5glpo[6] = sprom->mcs5glpo[6];
pi->mcs5glpo[7] = sprom->mcs5glpo[7];
break;
case 3:
pi->nphy_pwrctrl_info[0].max_pwr_5gh =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GHA0);
sprom->core_pwr_info[0].maxpwr_5gh;
pi->nphy_pwrctrl_info[1].max_pwr_5gh =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GHA1);
sprom->core_pwr_info[1].maxpwr_5gh;
pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW0A0);
sprom->core_pwr_info[0].pa_5gh[0];
pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW0A1);
sprom->core_pwr_info[1].pa_5gh[0];
pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW1A0);
sprom->core_pwr_info[0].pa_5gh[1];
pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW1A1);
sprom->core_pwr_info[1].pa_5gh[1];
pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW2A0);
sprom->core_pwr_info[0].pa_5gh[2];
pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW2A1);
sprom->core_pwr_info[1].pa_5gh[2];
pi->nphy_pwrctrl_info[0].idle_targ_5gh = 0;
pi->nphy_pwrctrl_info[1].idle_targ_5gh = 0;
pi->ofdm5ghpo =
(u32) wlapi_getintvar(shim,
BRCMS_SROM_OFDM5GHPO);
pi->ofdm5ghpo = sprom->ofdm5ghpo;
pi->mcs5ghpo[0] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO0);
pi->mcs5ghpo[1] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO1);
pi->mcs5ghpo[2] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO2);
pi->mcs5ghpo[3] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO3);
pi->mcs5ghpo[4] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO4);
pi->mcs5ghpo[5] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO5);
pi->mcs5ghpo[6] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO6);
pi->mcs5ghpo[7] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO7);
pi->mcs5ghpo[0] = sprom->mcs5ghpo[0];
pi->mcs5ghpo[1] = sprom->mcs5ghpo[1];
pi->mcs5ghpo[2] = sprom->mcs5ghpo[2];
pi->mcs5ghpo[3] = sprom->mcs5ghpo[3];
pi->mcs5ghpo[4] = sprom->mcs5ghpo[4];
pi->mcs5ghpo[5] = sprom->mcs5ghpo[5];
pi->mcs5ghpo[6] = sprom->mcs5ghpo[6];
pi->mcs5ghpo[7] = sprom->mcs5ghpo[7];
break;
}
}
@ -14664,45 +14559,34 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi)
{
struct phy_shim_info *shim = pi->sh->physhim;
struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
pi->antswitch = (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWITCH);
pi->aa2g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G);
pi->aa5g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA5G);
pi->antswitch = sprom->antswitch;
pi->aa2g = sprom->ant_available_bg;
pi->aa5g = sprom->ant_available_a;
pi->srom_fem2g.tssipos = (u8) wlapi_getintvar(shim,
BRCMS_SROM_TSSIPOS2G);
pi->srom_fem2g.extpagain = (u8) wlapi_getintvar(shim,
BRCMS_SROM_EXTPAGAIN2G);
pi->srom_fem2g.pdetrange = (u8) wlapi_getintvar(shim,
BRCMS_SROM_PDETRANGE2G);
pi->srom_fem2g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
pi->srom_fem2g.antswctrllut =
(u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
pi->srom_fem2g.tssipos = sprom->fem.ghz2.tssipos;
pi->srom_fem2g.extpagain = sprom->fem.ghz2.extpa_gain;
pi->srom_fem2g.pdetrange = sprom->fem.ghz2.pdet_range;
pi->srom_fem2g.triso = sprom->fem.ghz2.tr_iso;
pi->srom_fem2g.antswctrllut = sprom->fem.ghz2.antswlut;
pi->srom_fem5g.tssipos = (u8) wlapi_getintvar(shim,
BRCMS_SROM_TSSIPOS5G);
pi->srom_fem5g.extpagain = (u8) wlapi_getintvar(shim,
BRCMS_SROM_EXTPAGAIN5G);
pi->srom_fem5g.pdetrange = (u8) wlapi_getintvar(shim,
BRCMS_SROM_PDETRANGE5G);
pi->srom_fem5g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO5G);
if (wlapi_getvar(shim, BRCMS_SROM_ANTSWCTL5G))
pi->srom_fem5g.antswctrllut =
(u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL5G);
pi->srom_fem5g.tssipos = sprom->fem.ghz5.tssipos;
pi->srom_fem5g.extpagain = sprom->fem.ghz5.extpa_gain;
pi->srom_fem5g.pdetrange = sprom->fem.ghz5.pdet_range;
pi->srom_fem5g.triso = sprom->fem.ghz5.tr_iso;
if (sprom->fem.ghz5.antswlut)
pi->srom_fem5g.antswctrllut = sprom->fem.ghz5.antswlut;
else
pi->srom_fem5g.antswctrllut =
(u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
pi->srom_fem5g.antswctrllut = sprom->fem.ghz2.antswlut;
wlc_phy_txpower_ipa_upd(pi);
pi->phy_txcore_disable_temp =
(s16) wlapi_getintvar(shim, BRCMS_SROM_TEMPTHRESH);
pi->phy_txcore_disable_temp = sprom->tempthresh;
if (pi->phy_txcore_disable_temp == 0)
pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
pi->phy_tempsense_offset = (s8) wlapi_getintvar(shim,
BRCMS_SROM_TEMPOFFSET);
pi->phy_tempsense_offset = sprom->tempoffset;
if (pi->phy_tempsense_offset != 0) {
if (pi->phy_tempsense_offset >
(NPHY_SROM_TEMPSHIFT + NPHY_SROM_MAXTEMPOFFSET))
@ -14717,8 +14601,7 @@ static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi)
pi->phy_txcore_enable_temp =
pi->phy_txcore_disable_temp - PHY_HYSTERESIS_DELTATEMP;
pi->phycal_tempdelta =
(u8) wlapi_getintvar(shim, BRCMS_SROM_PHYCAL_TEMPDELTA);
pi->phycal_tempdelta = sprom->phycal_tempdelta;
if (pi->phycal_tempdelta > NPHY_CAL_MAXTEMPDELTA)
pi->phycal_tempdelta = 0;
@ -21460,7 +21343,7 @@ void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init)
write_phy_reg(pi, 0xc8, 0x0);
write_phy_reg(pi, 0xc9, 0x0);
ai_gpiocontrol(pi->sh->sih, mask, mask, GPIO_DRV_PRIORITY);
bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc, mask, mask);
mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
mc &= ~MCTL_GPOUT_SEL_MASK;

View file

@ -214,12 +214,3 @@ wlapi_copyto_objmem(struct phy_shim_info *physhim, uint offset, const void *buf,
{
brcms_b_copyto_objmem(physhim->wlc_hw, offset, buf, l, sel);
}
char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
{
return getvar(physhim->wlc_hw->sih, id);
}
int wlapi_getintvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
{
return getintvar(physhim->wlc_hw->sih, id);
}

View file

@ -175,8 +175,5 @@ extern void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint,
extern void wlapi_high_update_phy_mode(struct phy_shim_info *physhim,
u32 phy_mode);
extern u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim);
extern char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id);
extern int wlapi_getintvar(struct phy_shim_info *physhim,
enum brcms_srom_id id);
#endif /* _BRCM_PHY_SHIM_H_ */

View file

@ -22,232 +22,6 @@
#include "types.h"
#include "defs.h"
enum brcms_srom_id {
BRCMS_SROM_NULL,
BRCMS_SROM_CONT,
BRCMS_SROM_AA2G,
BRCMS_SROM_AA5G,
BRCMS_SROM_AG0,
BRCMS_SROM_AG1,
BRCMS_SROM_AG2,
BRCMS_SROM_AG3,
BRCMS_SROM_ANTSWCTL2G,
BRCMS_SROM_ANTSWCTL5G,
BRCMS_SROM_ANTSWITCH,
BRCMS_SROM_BOARDFLAGS2,
BRCMS_SROM_BOARDFLAGS,
BRCMS_SROM_BOARDNUM,
BRCMS_SROM_BOARDREV,
BRCMS_SROM_BOARDTYPE,
BRCMS_SROM_BW40PO,
BRCMS_SROM_BWDUPPO,
BRCMS_SROM_BXA2G,
BRCMS_SROM_BXA5G,
BRCMS_SROM_CC,
BRCMS_SROM_CCK2GPO,
BRCMS_SROM_CCKBW202GPO,
BRCMS_SROM_CCKBW20UL2GPO,
BRCMS_SROM_CCODE,
BRCMS_SROM_CDDPO,
BRCMS_SROM_DEVID,
BRCMS_SROM_ET1MACADDR,
BRCMS_SROM_EXTPAGAIN2G,
BRCMS_SROM_EXTPAGAIN5G,
BRCMS_SROM_FREQOFFSET_CORR,
BRCMS_SROM_HW_IQCAL_EN,
BRCMS_SROM_IL0MACADDR,
BRCMS_SROM_IQCAL_SWP_DIS,
BRCMS_SROM_LEDBH0,
BRCMS_SROM_LEDBH1,
BRCMS_SROM_LEDBH2,
BRCMS_SROM_LEDBH3,
BRCMS_SROM_LEDDC,
BRCMS_SROM_LEGOFDM40DUPPO,
BRCMS_SROM_LEGOFDMBW202GPO,
BRCMS_SROM_LEGOFDMBW205GHPO,
BRCMS_SROM_LEGOFDMBW205GLPO,
BRCMS_SROM_LEGOFDMBW205GMPO,
BRCMS_SROM_LEGOFDMBW20UL2GPO,
BRCMS_SROM_LEGOFDMBW20UL5GHPO,
BRCMS_SROM_LEGOFDMBW20UL5GLPO,
BRCMS_SROM_LEGOFDMBW20UL5GMPO,
BRCMS_SROM_MACADDR,
BRCMS_SROM_MCS2GPO0,
BRCMS_SROM_MCS2GPO1,
BRCMS_SROM_MCS2GPO2,
BRCMS_SROM_MCS2GPO3,
BRCMS_SROM_MCS2GPO4,
BRCMS_SROM_MCS2GPO5,
BRCMS_SROM_MCS2GPO6,
BRCMS_SROM_MCS2GPO7,
BRCMS_SROM_MCS32PO,
BRCMS_SROM_MCS5GHPO0,
BRCMS_SROM_MCS5GHPO1,
BRCMS_SROM_MCS5GHPO2,
BRCMS_SROM_MCS5GHPO3,
BRCMS_SROM_MCS5GHPO4,
BRCMS_SROM_MCS5GHPO5,
BRCMS_SROM_MCS5GHPO6,
BRCMS_SROM_MCS5GHPO7,
BRCMS_SROM_MCS5GLPO0,
BRCMS_SROM_MCS5GLPO1,
BRCMS_SROM_MCS5GLPO2,
BRCMS_SROM_MCS5GLPO3,
BRCMS_SROM_MCS5GLPO4,
BRCMS_SROM_MCS5GLPO5,
BRCMS_SROM_MCS5GLPO6,
BRCMS_SROM_MCS5GLPO7,
BRCMS_SROM_MCS5GPO0,
BRCMS_SROM_MCS5GPO1,
BRCMS_SROM_MCS5GPO2,
BRCMS_SROM_MCS5GPO3,
BRCMS_SROM_MCS5GPO4,
BRCMS_SROM_MCS5GPO5,
BRCMS_SROM_MCS5GPO6,
BRCMS_SROM_MCS5GPO7,
BRCMS_SROM_MCSBW202GPO,
BRCMS_SROM_MCSBW205GHPO,
BRCMS_SROM_MCSBW205GLPO,
BRCMS_SROM_MCSBW205GMPO,
BRCMS_SROM_MCSBW20UL2GPO,
BRCMS_SROM_MCSBW20UL5GHPO,
BRCMS_SROM_MCSBW20UL5GLPO,
BRCMS_SROM_MCSBW20UL5GMPO,
BRCMS_SROM_MCSBW402GPO,
BRCMS_SROM_MCSBW405GHPO,
BRCMS_SROM_MCSBW405GLPO,
BRCMS_SROM_MCSBW405GMPO,
BRCMS_SROM_MEASPOWER,
BRCMS_SROM_OFDM2GPO,
BRCMS_SROM_OFDM5GHPO,
BRCMS_SROM_OFDM5GLPO,
BRCMS_SROM_OFDM5GPO,
BRCMS_SROM_OPO,
BRCMS_SROM_PA0B0,
BRCMS_SROM_PA0B1,
BRCMS_SROM_PA0B2,
BRCMS_SROM_PA0ITSSIT,
BRCMS_SROM_PA0MAXPWR,
BRCMS_SROM_PA1B0,
BRCMS_SROM_PA1B1,
BRCMS_SROM_PA1B2,
BRCMS_SROM_PA1HIB0,
BRCMS_SROM_PA1HIB1,
BRCMS_SROM_PA1HIB2,
BRCMS_SROM_PA1HIMAXPWR,
BRCMS_SROM_PA1ITSSIT,
BRCMS_SROM_PA1LOB0,
BRCMS_SROM_PA1LOB1,
BRCMS_SROM_PA1LOB2,
BRCMS_SROM_PA1LOMAXPWR,
BRCMS_SROM_PA1MAXPWR,
BRCMS_SROM_PDETRANGE2G,
BRCMS_SROM_PDETRANGE5G,
BRCMS_SROM_PHYCAL_TEMPDELTA,
BRCMS_SROM_RAWTEMPSENSE,
BRCMS_SROM_REGREV,
BRCMS_SROM_REV,
BRCMS_SROM_RSSISAV2G,
BRCMS_SROM_RSSISAV5G,
BRCMS_SROM_RSSISMC2G,
BRCMS_SROM_RSSISMC5G,
BRCMS_SROM_RSSISMF2G,
BRCMS_SROM_RSSISMF5G,
BRCMS_SROM_RXCHAIN,
BRCMS_SROM_RXPO2G,
BRCMS_SROM_RXPO5G,
BRCMS_SROM_STBCPO,
BRCMS_SROM_TEMPCORRX,
BRCMS_SROM_TEMPOFFSET,
BRCMS_SROM_TEMPSENSE_OPTION,
BRCMS_SROM_TEMPSENSE_SLOPE,
BRCMS_SROM_TEMPTHRESH,
BRCMS_SROM_TRI2G,
BRCMS_SROM_TRI5GH,
BRCMS_SROM_TRI5GL,
BRCMS_SROM_TRI5G,
BRCMS_SROM_TRISO2G,
BRCMS_SROM_TRISO5G,
BRCMS_SROM_TSSIPOS2G,
BRCMS_SROM_TSSIPOS5G,
BRCMS_SROM_TXCHAIN,
/*
* per-path identifiers (see srom.c)
*/
BRCMS_SROM_ITT2GA0,
BRCMS_SROM_ITT2GA1,
BRCMS_SROM_ITT2GA2,
BRCMS_SROM_ITT2GA3,
BRCMS_SROM_ITT5GA0,
BRCMS_SROM_ITT5GA1,
BRCMS_SROM_ITT5GA2,
BRCMS_SROM_ITT5GA3,
BRCMS_SROM_MAXP2GA0,
BRCMS_SROM_MAXP2GA1,
BRCMS_SROM_MAXP2GA2,
BRCMS_SROM_MAXP2GA3,
BRCMS_SROM_MAXP5GA0,
BRCMS_SROM_MAXP5GA1,
BRCMS_SROM_MAXP5GA2,
BRCMS_SROM_MAXP5GA3,
BRCMS_SROM_MAXP5GHA0,
BRCMS_SROM_MAXP5GHA1,
BRCMS_SROM_MAXP5GHA2,
BRCMS_SROM_MAXP5GHA3,
BRCMS_SROM_MAXP5GLA0,
BRCMS_SROM_MAXP5GLA1,
BRCMS_SROM_MAXP5GLA2,
BRCMS_SROM_MAXP5GLA3,
BRCMS_SROM_PA2GW0A0,
BRCMS_SROM_PA2GW0A1,
BRCMS_SROM_PA2GW0A2,
BRCMS_SROM_PA2GW0A3,
BRCMS_SROM_PA2GW1A0,
BRCMS_SROM_PA2GW1A1,
BRCMS_SROM_PA2GW1A2,
BRCMS_SROM_PA2GW1A3,
BRCMS_SROM_PA2GW2A0,
BRCMS_SROM_PA2GW2A1,
BRCMS_SROM_PA2GW2A2,
BRCMS_SROM_PA2GW2A3,
BRCMS_SROM_PA5GHW0A0,
BRCMS_SROM_PA5GHW0A1,
BRCMS_SROM_PA5GHW0A2,
BRCMS_SROM_PA5GHW0A3,
BRCMS_SROM_PA5GHW1A0,
BRCMS_SROM_PA5GHW1A1,
BRCMS_SROM_PA5GHW1A2,
BRCMS_SROM_PA5GHW1A3,
BRCMS_SROM_PA5GHW2A0,
BRCMS_SROM_PA5GHW2A1,
BRCMS_SROM_PA5GHW2A2,
BRCMS_SROM_PA5GHW2A3,
BRCMS_SROM_PA5GLW0A0,
BRCMS_SROM_PA5GLW0A1,
BRCMS_SROM_PA5GLW0A2,
BRCMS_SROM_PA5GLW0A3,
BRCMS_SROM_PA5GLW1A0,
BRCMS_SROM_PA5GLW1A1,
BRCMS_SROM_PA5GLW1A2,
BRCMS_SROM_PA5GLW1A3,
BRCMS_SROM_PA5GLW2A0,
BRCMS_SROM_PA5GLW2A1,
BRCMS_SROM_PA5GLW2A2,
BRCMS_SROM_PA5GLW2A3,
BRCMS_SROM_PA5GW0A0,
BRCMS_SROM_PA5GW0A1,
BRCMS_SROM_PA5GW0A2,
BRCMS_SROM_PA5GW0A3,
BRCMS_SROM_PA5GW1A0,
BRCMS_SROM_PA5GW1A1,
BRCMS_SROM_PA5GW1A2,
BRCMS_SROM_PA5GW1A3,
BRCMS_SROM_PA5GW2A0,
BRCMS_SROM_PA5GW2A1,
BRCMS_SROM_PA5GW2A2,
BRCMS_SROM_PA5GW2A3,
};
#define BRCMS_NUMRATES 16 /* max # of rates in a rateset */
/* phy types */
@ -565,8 +339,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 char *getvar(struct si_pub *sih, enum brcms_srom_id id);
extern int getintvar(struct si_pub *sih, enum brcms_srom_id id);
extern int brcms_c_module_register(struct brcms_pub *pub,
const char *name, struct brcms_info *hdl,
int (*down_fn)(void *handle));

View file

@ -1,980 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/io.h>
#include <linux/etherdevice.h>
#include <linux/crc8.h>
#include <stdarg.h>
#include <chipcommon.h>
#include <brcmu_utils.h>
#include "pub.h"
#include "nicpci.h"
#include "aiutils.h"
#include "otp.h"
#include "srom.h"
#include "soc.h"
/*
* SROM CRC8 polynomial value:
*
* x^8 + x^7 +x^6 + x^4 + x^2 + 1
*/
#define SROM_CRC8_POLY 0xAB
/* Maximum srom: 6 Kilobits == 768 bytes */
#define SROM_MAX 768
/* PCI fields */
#define PCI_F0DEVID 48
#define SROM_WORDS 64
#define SROM_SSID 2
#define SROM_WL1LHMAXP 29
#define SROM_WL1LPAB0 30
#define SROM_WL1LPAB1 31
#define SROM_WL1LPAB2 32
#define SROM_WL1HPAB0 33
#define SROM_WL1HPAB1 34
#define SROM_WL1HPAB2 35
#define SROM_MACHI_IL0 36
#define SROM_MACMID_IL0 37
#define SROM_MACLO_IL0 38
#define SROM_MACHI_ET1 42
#define SROM_MACMID_ET1 43
#define SROM_MACLO_ET1 44
#define SROM_BXARSSI2G 40
#define SROM_BXARSSI5G 41
#define SROM_TRI52G 42
#define SROM_TRI5GHL 43
#define SROM_RXPO52G 45
#define SROM_AABREV 46
/* Fields in AABREV */
#define SROM_BR_MASK 0x00ff
#define SROM_CC_MASK 0x0f00
#define SROM_CC_SHIFT 8
#define SROM_AA0_MASK 0x3000
#define SROM_AA0_SHIFT 12
#define SROM_AA1_MASK 0xc000
#define SROM_AA1_SHIFT 14
#define SROM_WL0PAB0 47
#define SROM_WL0PAB1 48
#define SROM_WL0PAB2 49
#define SROM_LEDBH10 50
#define SROM_LEDBH32 51
#define SROM_WL10MAXP 52
#define SROM_WL1PAB0 53
#define SROM_WL1PAB1 54
#define SROM_WL1PAB2 55
#define SROM_ITT 56
#define SROM_BFL 57
#define SROM_BFL2 28
#define SROM_AG10 58
#define SROM_CCODE 59
#define SROM_OPO 60
#define SROM_CRCREV 63
#define SROM4_WORDS 220
#define SROM4_TXCHAIN_MASK 0x000f
#define SROM4_RXCHAIN_MASK 0x00f0
#define SROM4_SWITCH_MASK 0xff00
/* Per-path fields */
#define MAX_PATH_SROM 4
#define SROM4_CRCREV 219
/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6.
* This is acombined srom for both MIMO and SISO boards, usable in
* the .130 4Kilobit OTP with hardware redundancy.
*/
#define SROM8_BREV 65
#define SROM8_BFL0 66
#define SROM8_BFL1 67
#define SROM8_BFL2 68
#define SROM8_BFL3 69
#define SROM8_MACHI 70
#define SROM8_MACMID 71
#define SROM8_MACLO 72
#define SROM8_CCODE 73
#define SROM8_REGREV 74
#define SROM8_LEDBH10 75
#define SROM8_LEDBH32 76
#define SROM8_LEDDC 77
#define SROM8_AA 78
#define SROM8_AG10 79
#define SROM8_AG32 80
#define SROM8_TXRXC 81
#define SROM8_BXARSSI2G 82
#define SROM8_BXARSSI5G 83
#define SROM8_TRI52G 84
#define SROM8_TRI5GHL 85
#define SROM8_RXPO52G 86
#define SROM8_FEM2G 87
#define SROM8_FEM5G 88
#define SROM8_FEM_ANTSWLUT_MASK 0xf800
#define SROM8_FEM_ANTSWLUT_SHIFT 11
#define SROM8_FEM_TR_ISO_MASK 0x0700
#define SROM8_FEM_TR_ISO_SHIFT 8
#define SROM8_FEM_PDET_RANGE_MASK 0x00f8
#define SROM8_FEM_PDET_RANGE_SHIFT 3
#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006
#define SROM8_FEM_EXTPA_GAIN_SHIFT 1
#define SROM8_FEM_TSSIPOS_MASK 0x0001
#define SROM8_FEM_TSSIPOS_SHIFT 0
#define SROM8_THERMAL 89
/* Temp sense related entries */
#define SROM8_MPWR_RAWTS 90
#define SROM8_TS_SLP_OPT_CORRX 91
/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable,
* IQSWP: IQ CAL swap disable */
#define SROM8_FOC_HWIQ_IQSWP 92
/* Temperature delta for PHY calibration */
#define SROM8_PHYCAL_TEMPDELTA 93
/* Per-path offsets & fields */
#define SROM8_PATH0 96
#define SROM8_PATH1 112
#define SROM8_PATH2 128
#define SROM8_PATH3 144
#define SROM8_2G_ITT_MAXP 0
#define SROM8_2G_PA 1
#define SROM8_5G_ITT_MAXP 4
#define SROM8_5GLH_MAXP 5
#define SROM8_5G_PA 6
#define SROM8_5GL_PA 9
#define SROM8_5GH_PA 12
/* All the miriad power offsets */
#define SROM8_2G_CCKPO 160
#define SROM8_2G_OFDMPO 161
#define SROM8_5G_OFDMPO 163
#define SROM8_5GL_OFDMPO 165
#define SROM8_5GH_OFDMPO 167
#define SROM8_2G_MCSPO 169
#define SROM8_5G_MCSPO 177
#define SROM8_5GL_MCSPO 185
#define SROM8_5GH_MCSPO 193
#define SROM8_CDDPO 201
#define SROM8_STBCPO 202
#define SROM8_BW40PO 203
#define SROM8_BWDUPPO 204
/* SISO PA parameters are in the path0 spaces */
#define SROM8_SISO 96
/* Legacy names for SISO PA paramters */
#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP)
#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA)
#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1)
#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2)
#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP)
#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP)
#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA)
#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1)
#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2)
#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA)
#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1)
#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2)
#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA)
#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1)
#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2)
/* SROM REV 9 */
#define SROM9_2GPO_CCKBW20 160
#define SROM9_2GPO_CCKBW20UL 161
#define SROM9_2GPO_LOFDMBW20 162
#define SROM9_2GPO_LOFDMBW20UL 164
#define SROM9_5GLPO_LOFDMBW20 166
#define SROM9_5GLPO_LOFDMBW20UL 168
#define SROM9_5GMPO_LOFDMBW20 170
#define SROM9_5GMPO_LOFDMBW20UL 172
#define SROM9_5GHPO_LOFDMBW20 174
#define SROM9_5GHPO_LOFDMBW20UL 176
#define SROM9_2GPO_MCSBW20 178
#define SROM9_2GPO_MCSBW20UL 180
#define SROM9_2GPO_MCSBW40 182
#define SROM9_5GLPO_MCSBW20 184
#define SROM9_5GLPO_MCSBW20UL 186
#define SROM9_5GLPO_MCSBW40 188
#define SROM9_5GMPO_MCSBW20 190
#define SROM9_5GMPO_MCSBW20UL 192
#define SROM9_5GMPO_MCSBW40 194
#define SROM9_5GHPO_MCSBW20 196
#define SROM9_5GHPO_MCSBW20UL 198
#define SROM9_5GHPO_MCSBW40 200
#define SROM9_PO_MCS32 202
#define SROM9_PO_LOFDM40DUP 203
/* SROM flags (see sromvar_t) */
/* value continues as described by the next entry */
#define SRFL_MORE 1
#define SRFL_NOFFS 2 /* value bits can't be all one's */
#define SRFL_PRHEX 4 /* value is in hexdecimal format */
#define SRFL_PRSIGN 8 /* value is in signed decimal format */
#define SRFL_CCODE 0x10 /* value is in country code format */
#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */
#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */
/* do not generate a nvram param, entry is for mfgc */
#define SRFL_NOVAR 0x80
/* Max. nvram variable table size */
#define MAXSZ_NVRAM_VARS 4096
/*
* indicates type of value.
*/
enum brcms_srom_var_type {
BRCMS_SROM_STRING,
BRCMS_SROM_SNUMBER,
BRCMS_SROM_UNUMBER
};
/*
* storage type for srom variable.
*
* var_list: for linked list operations.
* varid: identifier of the variable.
* var_type: type of variable.
* buf: variable value when var_type == BRCMS_SROM_STRING.
* uval: unsigned variable value when var_type == BRCMS_SROM_UNUMBER.
* sval: signed variable value when var_type == BRCMS_SROM_SNUMBER.
*/
struct brcms_srom_list_head {
struct list_head var_list;
enum brcms_srom_id varid;
enum brcms_srom_var_type var_type;
union {
char buf[0];
u32 uval;
s32 sval;
};
};
struct brcms_sromvar {
enum brcms_srom_id varid;
u32 revmask;
u32 flags;
u16 off;
u16 mask;
};
struct brcms_varbuf {
char *base; /* pointer to buffer base */
char *buf; /* pointer to current position */
unsigned int size; /* current (residual) size in bytes */
};
/*
* Assumptions:
* - Ethernet address spans across 3 consecutive words
*
* Table rules:
* - Add multiple entries next to each other if a value spans across multiple
* words (even multiple fields in the same word) with each entry except the
* last having it's SRFL_MORE bit set.
* - Ethernet address entry does not follow above rule and must not have
* SRFL_MORE bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
* - The last entry's name field must be NULL to indicate the end of the table.
* Other entries must have non-NULL name.
*/
static const struct brcms_sromvar pci_sromvars[] = {
{BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID,
0xffff},
{BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
{BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff},
{BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff},
{BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
{BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff},
{BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff},
{BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
{BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
{BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
{BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
{BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
{BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
{BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
{BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
{BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
{BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
{BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff},
{BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00},
{BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff},
{BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00},
{BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff},
{BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00},
{BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
{BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
{BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
{BRCMS_SROM_PA1LOB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
{BRCMS_SROM_PA1LOB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
{BRCMS_SROM_PA1LOB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
{BRCMS_SROM_PA1HIB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
{BRCMS_SROM_PA1HIB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
{BRCMS_SROM_PA1HIB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
{BRCMS_SROM_PA1ITSSIT, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
{BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
{BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
{BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
{BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
{BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
{BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
{BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
{BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
{BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
{BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
{BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
{BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
{BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00},
{BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
{BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
{BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
{BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
{BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
SROM4_TXCHAIN_MASK},
{BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
SROM4_RXCHAIN_MASK},
{BRCMS_SROM_ANTSWITCH, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
SROM4_SWITCH_MASK},
{BRCMS_SROM_TSSIPOS2G, 0xffffff00, 0, SROM8_FEM2G,
SROM8_FEM_TSSIPOS_MASK},
{BRCMS_SROM_EXTPAGAIN2G, 0xffffff00, 0, SROM8_FEM2G,
SROM8_FEM_EXTPA_GAIN_MASK},
{BRCMS_SROM_PDETRANGE2G, 0xffffff00, 0, SROM8_FEM2G,
SROM8_FEM_PDET_RANGE_MASK},
{BRCMS_SROM_TRISO2G, 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK},
{BRCMS_SROM_ANTSWCTL2G, 0xffffff00, 0, SROM8_FEM2G,
SROM8_FEM_ANTSWLUT_MASK},
{BRCMS_SROM_TSSIPOS5G, 0xffffff00, 0, SROM8_FEM5G,
SROM8_FEM_TSSIPOS_MASK},
{BRCMS_SROM_EXTPAGAIN5G, 0xffffff00, 0, SROM8_FEM5G,
SROM8_FEM_EXTPA_GAIN_MASK},
{BRCMS_SROM_PDETRANGE5G, 0xffffff00, 0, SROM8_FEM5G,
SROM8_FEM_PDET_RANGE_MASK},
{BRCMS_SROM_TRISO5G, 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK},
{BRCMS_SROM_ANTSWCTL5G, 0xffffff00, 0, SROM8_FEM5G,
SROM8_FEM_ANTSWLUT_MASK},
{BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00},
{BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
{BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
{BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
{BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC,
0xffff},
{BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
0x01ff},
{BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
0xfe00},
{BRCMS_SROM_TEMPSENSE_SLOPE, 0xffffff00, SRFL_PRHEX,
SROM8_TS_SLP_OPT_CORRX, 0x00ff},
{BRCMS_SROM_TEMPCORRX, 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX,
0xfc00},
{BRCMS_SROM_TEMPSENSE_OPTION, 0xffffff00, SRFL_PRHEX,
SROM8_TS_SLP_OPT_CORRX, 0x0300},
{BRCMS_SROM_FREQOFFSET_CORR, 0xffffff00, SRFL_PRHEX,
SROM8_FOC_HWIQ_IQSWP, 0x000f},
{BRCMS_SROM_IQCAL_SWP_DIS, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
0x0010},
{BRCMS_SROM_HW_IQCAL_EN, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
0x0020},
{BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA,
0x00ff},
{BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
{BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
{BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
{BRCMS_SROM_OFDM5GLPO, 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
{BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
{BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
{BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
{BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
{BRCMS_SROM_MCS2GPO3, 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff},
{BRCMS_SROM_MCS2GPO4, 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff},
{BRCMS_SROM_MCS2GPO5, 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff},
{BRCMS_SROM_MCS2GPO6, 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff},
{BRCMS_SROM_MCS2GPO7, 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff},
{BRCMS_SROM_MCS5GPO0, 0x00000100, 0, SROM8_5G_MCSPO, 0xffff},
{BRCMS_SROM_MCS5GPO1, 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff},
{BRCMS_SROM_MCS5GPO2, 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff},
{BRCMS_SROM_MCS5GPO3, 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff},
{BRCMS_SROM_MCS5GPO4, 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff},
{BRCMS_SROM_MCS5GPO5, 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff},
{BRCMS_SROM_MCS5GPO6, 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff},
{BRCMS_SROM_MCS5GPO7, 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff},
{BRCMS_SROM_MCS5GLPO0, 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff},
{BRCMS_SROM_MCS5GLPO1, 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff},
{BRCMS_SROM_MCS5GLPO2, 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff},
{BRCMS_SROM_MCS5GLPO3, 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff},
{BRCMS_SROM_MCS5GLPO4, 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff},
{BRCMS_SROM_MCS5GLPO5, 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff},
{BRCMS_SROM_MCS5GLPO6, 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff},
{BRCMS_SROM_MCS5GLPO7, 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff},
{BRCMS_SROM_MCS5GHPO0, 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff},
{BRCMS_SROM_MCS5GHPO1, 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff},
{BRCMS_SROM_MCS5GHPO2, 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff},
{BRCMS_SROM_MCS5GHPO3, 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff},
{BRCMS_SROM_MCS5GHPO4, 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff},
{BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
{BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
{BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
{BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff},
{BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff},
{BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff},
{BRCMS_SROM_BWDUPPO, 0x00000100, 0, SROM8_BWDUPPO, 0xffff},
/* power per rate from sromrev 9 */
{BRCMS_SROM_CCKBW202GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff},
{BRCMS_SROM_CCKBW20UL2GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff},
{BRCMS_SROM_LEGOFDMBW202GPO, 0xfffffe00, SRFL_MORE,
SROM9_2GPO_LOFDMBW20, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW20UL2GPO, 0xfffffe00, SRFL_MORE,
SROM9_2GPO_LOFDMBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW205GLPO, 0xfffffe00, SRFL_MORE,
SROM9_5GLPO_LOFDMBW20, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
SROM9_5GLPO_LOFDMBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW205GMPO, 0xfffffe00, SRFL_MORE,
SROM9_5GMPO_LOFDMBW20, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
SROM9_5GMPO_LOFDMBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW205GHPO, 0xfffffe00, SRFL_MORE,
SROM9_5GHPO_LOFDMBW20, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
SROM9_5GHPO_LOFDMBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW202GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff},
{BRCMS_SROM_MCSBW20UL2GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW402GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff},
{BRCMS_SROM_MCSBW205GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff},
{BRCMS_SROM_MCSBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
SROM9_5GLPO_MCSBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW405GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff},
{BRCMS_SROM_MCSBW205GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff},
{BRCMS_SROM_MCSBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
SROM9_5GMPO_MCSBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW405GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff},
{BRCMS_SROM_MCSBW205GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff},
{BRCMS_SROM_MCSBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
SROM9_5GHPO_MCSBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW405GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff},
{BRCMS_SROM_MCS32PO, 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff},
{BRCMS_SROM_LEGOFDM40DUPPO, 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff},
{BRCMS_SROM_NULL, 0, 0, 0, 0}
};
static const struct brcms_sromvar perpath_pci_sromvars[] = {
{BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
{BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
{BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
{BRCMS_SROM_PA2GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
{BRCMS_SROM_PA2GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
{BRCMS_SROM_PA2GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
{BRCMS_SROM_MAXP5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff},
{BRCMS_SROM_MAXP5GHA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff},
{BRCMS_SROM_MAXP5GLA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
{BRCMS_SROM_PA5GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
{BRCMS_SROM_PA5GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
{BRCMS_SROM_PA5GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
{BRCMS_SROM_PA5GLW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
{BRCMS_SROM_PA5GLW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1,
0xffff},
{BRCMS_SROM_PA5GLW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2,
0xffff},
{BRCMS_SROM_PA5GHW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
{BRCMS_SROM_PA5GHW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1,
0xffff},
{BRCMS_SROM_PA5GHW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2,
0xffff},
{BRCMS_SROM_NULL, 0, 0, 0, 0}
};
/* crc table has the same contents for every device instance, so it can be
* shared between devices. */
static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE];
static uint mask_shift(u16 mask)
{
uint i;
for (i = 0; i < (sizeof(mask) << 3); i++) {
if (mask & (1 << i))
return i;
}
return 0;
}
static uint mask_width(u16 mask)
{
int i;
for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) {
if (mask & (1 << i))
return (uint) (i - mask_shift(mask) + 1);
}
return 0;
}
static inline void le16_to_cpu_buf(u16 *buf, uint nwords)
{
while (nwords--)
*(buf + nwords) = le16_to_cpu(*(__le16 *)(buf + nwords));
}
static inline void cpu_to_le16_buf(u16 *buf, uint nwords)
{
while (nwords--)
*(__le16 *)(buf + nwords) = cpu_to_le16(*(buf + nwords));
}
/*
* convert binary srom data into linked list of srom variable items.
*/
static int
_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
{
struct brcms_srom_list_head *entry;
enum brcms_srom_id id;
u16 w;
u32 val = 0;
const struct brcms_sromvar *srv;
uint width;
uint flags;
u32 sr = (1 << sromrev);
uint p;
uint pb = SROM8_PATH0;
const uint psz = SROM8_PATH1 - SROM8_PATH0;
/* first store the srom revision */
entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->varid = BRCMS_SROM_REV;
entry->var_type = BRCMS_SROM_UNUMBER;
entry->uval = sromrev;
list_add(&entry->var_list, var_list);
for (srv = pci_sromvars; srv->varid != BRCMS_SROM_NULL; srv++) {
enum brcms_srom_var_type type;
u8 ea[ETH_ALEN];
u8 extra_space = 0;
if ((srv->revmask & sr) == 0)
continue;
flags = srv->flags;
id = srv->varid;
/* This entry is for mfgc only. Don't generate param for it, */
if (flags & SRFL_NOVAR)
continue;
if (flags & SRFL_ETHADDR) {
/*
* stored in string format XX:XX:XX:XX:XX:XX (17 chars)
*/
ea[0] = (srom[srv->off] >> 8) & 0xff;
ea[1] = srom[srv->off] & 0xff;
ea[2] = (srom[srv->off + 1] >> 8) & 0xff;
ea[3] = srom[srv->off + 1] & 0xff;
ea[4] = (srom[srv->off + 2] >> 8) & 0xff;
ea[5] = srom[srv->off + 2] & 0xff;
/* 17 characters + string terminator - union size */
extra_space = 18 - sizeof(s32);
type = BRCMS_SROM_STRING;
} else {
w = srom[srv->off];
val = (w & srv->mask) >> mask_shift(srv->mask);
width = mask_width(srv->mask);
while (srv->flags & SRFL_MORE) {
srv++;
if (srv->off == 0)
continue;
w = srom[srv->off];
val +=
((w & srv->mask) >> mask_shift(srv->
mask)) <<
width;
width += mask_width(srv->mask);
}
if ((flags & SRFL_NOFFS)
&& ((int)val == (1 << width) - 1))
continue;
if (flags & SRFL_CCODE) {
type = BRCMS_SROM_STRING;
} else if (flags & SRFL_LEDDC) {
/* LED Powersave duty cycle has to be scaled:
*(oncount >> 24) (offcount >> 8)
*/
u32 w32 = /* oncount */
(((val >> 8) & 0xff) << 24) |
/* offcount */
(((val & 0xff)) << 8);
type = BRCMS_SROM_UNUMBER;
val = w32;
} else if ((flags & SRFL_PRSIGN)
&& (val & (1 << (width - 1)))) {
type = BRCMS_SROM_SNUMBER;
val |= ~0 << width;
} else
type = BRCMS_SROM_UNUMBER;
}
entry = kzalloc(sizeof(struct brcms_srom_list_head) +
extra_space, GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->varid = id;
entry->var_type = type;
if (flags & SRFL_ETHADDR) {
snprintf(entry->buf, 18, "%pM", ea);
} else if (flags & SRFL_CCODE) {
if (val == 0)
entry->buf[0] = '\0';
else
snprintf(entry->buf, 3, "%c%c",
(val >> 8), (val & 0xff));
} else {
entry->uval = val;
}
list_add(&entry->var_list, var_list);
}
for (p = 0; p < MAX_PATH_SROM; p++) {
for (srv = perpath_pci_sromvars;
srv->varid != BRCMS_SROM_NULL; srv++) {
if ((srv->revmask & sr) == 0)
continue;
if (srv->flags & SRFL_NOVAR)
continue;
w = srom[pb + srv->off];
val = (w & srv->mask) >> mask_shift(srv->mask);
width = mask_width(srv->mask);
/* Cheating: no per-path var is more than
* 1 word */
if ((srv->flags & SRFL_NOFFS)
&& ((int)val == (1 << width) - 1))
continue;
entry =
kzalloc(sizeof(struct brcms_srom_list_head),
GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->varid = srv->varid+p;
entry->var_type = BRCMS_SROM_UNUMBER;
entry->uval = val;
list_add(&entry->var_list, var_list);
}
pb += psz;
}
return 0;
}
/*
* The crc check is done on a little-endian array, we need
* to switch the bytes around before checking crc (and
* then switch it back).
*/
static int do_crc_check(u16 *buf, unsigned nwords)
{
u8 crc;
cpu_to_le16_buf(buf, nwords);
crc = crc8(brcms_srom_crc8_table, (void *)buf, nwords << 1, CRC8_INIT_VALUE);
le16_to_cpu_buf(buf, nwords);
return crc == CRC8_GOOD_VALUE(brcms_srom_crc8_table);
}
/*
* Read in and validate sprom.
* Return 0 on success, nonzero on error.
*/
static int
sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc)
{
int err = 0;
uint i;
struct bcma_device *core;
uint sprom_offset;
/* determine core to read */
if (ai_get_ccrev(sih) < 32) {
core = ai_findcore(sih, BCMA_CORE_80211, 0);
sprom_offset = PCI_BAR0_SPROM_OFFSET;
} else {
core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
sprom_offset = CHIPCREGOFFS(sromotp);
}
/* read the sprom */
for (i = 0; i < nwords; i++)
buf[i] = bcma_read16(core, sprom_offset+i*2);
if (buf[0] == 0xffff)
/*
* The hardware thinks that an srom that starts with
* 0xffff is blank, regardless of the rest of the
* content, so declare it bad.
*/
return -ENODATA;
if (check_crc && !do_crc_check(buf, nwords))
err = -EIO;
return err;
}
static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords)
{
u8 *otp;
uint sz = OTP_SZ_MAX / 2; /* size in words */
int err = 0;
otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC);
if (otp == NULL)
return -ENOMEM;
err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
sz = min_t(uint, sz, nwords);
memcpy(buf, otp, sz * 2);
kfree(otp);
/* Check CRC */
if (buf[0] == 0xffff)
/* The hardware thinks that an srom that starts with 0xffff
* is blank, regardless of the rest of the content, so declare
* it bad.
*/
return -ENODATA;
/* fixup the endianness so crc8 will pass */
cpu_to_le16_buf(buf, sz);
if (crc8(brcms_srom_crc8_table, (u8 *) buf, sz * 2,
CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table))
err = -EIO;
else
/* now correct the endianness of the byte array */
le16_to_cpu_buf(buf, sz);
return err;
}
/*
* Initialize nonvolatile variable table from sprom.
* Return 0 on success, nonzero on error.
*/
int srom_var_init(struct si_pub *sih)
{
u16 *srom;
u8 sromrev = 0;
u32 sr;
int err = 0;
/*
* Apply CRC over SROM content regardless SROM is present or not.
*/
srom = kmalloc(SROM_MAX, GFP_ATOMIC);
if (!srom)
return -ENOMEM;
crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY);
if (ai_is_sprom_available(sih)) {
err = sprom_read_pci(sih, srom, SROM4_WORDS, true);
if (err == 0)
/* srom read and passed crc */
/* top word of sprom contains version and crc8 */
sromrev = srom[SROM4_CRCREV] & 0xff;
} else {
/* Use OTP if SPROM not available */
err = otp_read_pci(sih, srom, SROM4_WORDS);
if (err == 0)
/* OTP only contain SROM rev8/rev9 for now */
sromrev = srom[SROM4_CRCREV] & 0xff;
}
if (!err) {
struct si_info *sii = (struct si_info *)sih;
/* Bitmask for the sromrev */
sr = 1 << sromrev;
/*
* srom version check: Current valid versions: 8, 9
*/
if ((sr & 0x300) == 0) {
err = -EINVAL;
goto errout;
}
INIT_LIST_HEAD(&sii->var_list);
/* parse SROM into name=value pairs. */
err = _initvars_srom_pci(sromrev, srom, &sii->var_list);
if (err)
srom_free_vars(sih);
}
errout:
kfree(srom);
return err;
}
void srom_free_vars(struct si_pub *sih)
{
struct si_info *sii;
struct brcms_srom_list_head *entry, *next;
sii = (struct si_info *)sih;
list_for_each_entry_safe(entry, next, &sii->var_list, var_list) {
list_del(&entry->var_list);
kfree(entry);
}
}
/*
* Search the name=value vars for a specific one and return its value.
* Returns NULL if not found.
*/
char *getvar(struct si_pub *sih, enum brcms_srom_id id)
{
struct si_info *sii;
struct brcms_srom_list_head *entry;
sii = (struct si_info *)sih;
list_for_each_entry(entry, &sii->var_list, var_list)
if (entry->varid == id)
return &entry->buf[0];
/* nothing found */
return NULL;
}
/*
* Search the vars for a specific one and return its value as
* an integer. Returns 0 if not found.-
*/
int getintvar(struct si_pub *sih, enum brcms_srom_id id)
{
struct si_info *sii;
struct brcms_srom_list_head *entry;
unsigned long res;
sii = (struct si_info *)sih;
list_for_each_entry(entry, &sii->var_list, var_list)
if (entry->varid == id) {
if (entry->var_type == BRCMS_SROM_SNUMBER ||
entry->var_type == BRCMS_SROM_UNUMBER)
return (int)entry->sval;
else if (!kstrtoul(&entry->buf[0], 0, &res))
return (int)res;
}
return 0;
}

View file

@ -1,29 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_SROM_H_
#define _BRCM_SROM_H_
#include "types.h"
/* Prototypes */
extern int srom_var_init(struct si_pub *sih);
extern void srom_free_vars(struct si_pub *sih);
extern int srom_read(struct si_pub *sih, uint bus, void *curmap,
uint byteoff, uint nbytes, u16 *buf, bool check_crc);
#endif /* _BRCM_SROM_H_ */

View file

@ -370,9 +370,11 @@ void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc)
{
struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
/* get available rx/tx chains */
wlc->stf->hw_txchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_TXCHAIN);
wlc->stf->hw_rxchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_RXCHAIN);
wlc->stf->hw_txchain = sprom->txchain;
wlc->stf->hw_rxchain = sprom->rxchain;
/* these parameter are intended to be used for all PHY types */
if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) {

View file

@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <net/mac80211.h>
#include "iwl-dev.h"
#include "iwl-io.h"
@ -273,9 +274,20 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
return;
}
/*
* Possible situations when BT needs to take over for receive,
* at the same time where STA needs to response to AP's frame(s),
* reduce the tx power of the required response frames, by that,
* allow the concurrent BT receive & WiFi transmit
* (BT - ANT A, WiFi -ANT B), without interference to one another
*
* Reduced tx power apply to control frames only (ACK/Back/CTS)
* when indicated by the BT config command
*/
basic.kill_ack_mask = priv->kill_ack_mask;
basic.kill_cts_mask = priv->kill_cts_mask;
basic.reduce_txpower = priv->reduced_txpower;
if (priv->reduced_txpower)
basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
basic.valid = priv->bt_valid;
/*
@ -589,13 +601,31 @@ static bool iwlagn_set_kill_msk(struct iwl_priv *priv,
return need_update;
}
/*
* Upon RSSI changes, sends a bt config command with following changes
* 1. enable/disable "reduced control frames tx power
* 2. update the "kill)ack_mask" and "kill_cts_mask"
*
* If "reduced tx power" is enabled, uCode shall
* 1. ACK/Back/CTS rate shall reduced to 6Mbps
* 2. not use duplciate 20/40MHz mode
*/
static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
struct iwl_bt_uart_msg *uart_msg)
{
bool need_update = false;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
int ave_rssi;
ave_rssi = ieee80211_ave_rssi(ctx->vif);
if (!ave_rssi) {
/* no rssi data, no changes to reduce tx power */
IWL_DEBUG_COEX(priv, "no rssi data available\n");
return need_update;
}
if (!priv->reduced_txpower &&
!iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
(ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) &&
(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
BT_UART_MSG_FRAME3OBEX_MSK)) &&
!(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
@ -606,13 +636,14 @@ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
need_update = true;
} else if (priv->reduced_txpower &&
(iwl_is_associated(priv, IWL_RXON_CTX_PAN) ||
(ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) ||
(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) ||
!(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
BT_UART_MSG_FRAME3OBEX_MSK)))) {
/* disable reduced tx power */
priv->reduced_txpower = false;
priv->bt_valid &= ~IWLAGN_BT_VALID_REDUCED_TX_PWR;
priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
need_update = true;
}

View file

@ -61,6 +61,10 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
RXON_FILTER_ACCEPT_GRP_MSK;
break;
case NL80211_IFTYPE_MONITOR:
ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER;
break;
default:
IWL_ERR(priv, "Unsupported interface type %d\n",
ctx->vif->type);

View file

@ -590,11 +590,17 @@ turn_off:
spin_unlock_bh(&priv->sta_lock);
if (test_bit(txq_id, priv->agg_q_alloc)) {
/* If the transport didn't know that we wanted to start
* agreggation, don't tell it that we want to stop them
/*
* If the transport didn't know that we wanted to start
* agreggation, don't tell it that we want to stop them.
* This can happen when we don't get the addBA response on
* time, or we hadn't time to drain the AC queues.
*/
if (agg_state != IWL_AGG_STARTING)
if (agg_state == IWL_AGG_ON)
iwl_trans_tx_agg_disable(priv->trans, txq_id);
else
IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
agg_state);
iwlagn_dealloc_agg_txq(priv, txq_id);
}
@ -1300,10 +1306,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
(u8 *) &ba_resp->sta_addr_lo32,
ba_resp->sta_id);
IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, "
"scd_flow = %d, scd_ssn = %d\n",
"scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
ba_resp->tid, le16_to_cpu(ba_resp->seq_ctl),
(unsigned long long)le64_to_cpu(ba_resp->bitmap),
scd_flow, ba_resp_scd_ssn);
scd_flow, ba_resp_scd_ssn, ba_resp->txed,
ba_resp->txed_2_done);
/* Mark that the expected block-ack response arrived */
agg->wait_for_ba = false;
@ -1319,8 +1326,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
*/
ba_resp->txed = ba_resp->txed_2_done;
}
IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
ba_resp->txed, ba_resp->txed_2_done);
priv->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn;

View file

@ -603,7 +603,7 @@ void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
BIT(NL80211_IFTYPE_ADHOC);
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR);
priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
BIT(NL80211_IFTYPE_STATION);
priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;

View file

@ -1910,6 +1910,8 @@ enum iwl_bt_kill_idx {
IWLAGN_BT_VALID_REDUCED_TX_PWR | \
IWLAGN_BT_VALID_3W_LUT)
#define IWLAGN_BT_REDUCED_TX_PWR BIT(0)
#define IWLAGN_BT_DECISION_LUT_SIZE 12
struct iwl_basic_bt_cmd {
@ -1923,6 +1925,10 @@ struct iwl_basic_bt_cmd {
u8 bt3_timer_t2_value;
__le16 bt4_reaction_time; /* unused */
__le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE];
/*
* bit 0: use reduced tx power for control frame
* bit 1 - 7: reserved
*/
u8 reduce_txpower;
u8 reserved;
__le16 valid;
@ -2272,7 +2278,6 @@ struct iwl_ssid_ie {
#define IWL_GOOD_CRC_TH_DISABLED 0
#define IWL_GOOD_CRC_TH_DEFAULT cpu_to_le16(1)
#define IWL_GOOD_CRC_TH_NEVER cpu_to_le16(0xffff)
#define IWL_MAX_SCAN_SIZE 1024
#define IWL_MAX_CMD_SIZE 4096
/*

View file

@ -150,6 +150,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
IEEE80211_HW_QUEUE_CONTROL |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
IEEE80211_HW_WANT_MONITOR_VIF |
IEEE80211_HW_SCAN_WHILE_IDLE;
hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
@ -223,8 +224,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
/* we create the 802.11 header and a zero-length SSID element */
hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
/* we create the 802.11 header and a max-length SSID element */
hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 34;
/*
* We don't use all queues: 4 and 9 are unused and any

View file

@ -253,6 +253,8 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
skip, period);
/* The power level here is 0-4 (used as array index), but user expects
to see 1-5 (according to spec). */
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
}
@ -308,10 +310,12 @@ static void iwl_power_build_cmd(struct iwl_priv *priv,
priv->power_data.debug_sleep_level_override,
dtimper);
else {
/* Note that the user parameter is 1-5 (according to spec),
but we pass 0-4 because it acts as an array index. */
if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 &&
iwlwifi_mod_params.power_level <= IWL_POWER_INDEX_5)
iwlwifi_mod_params.power_level <= IWL_POWER_NUM)
iwl_static_sleep_cmd(priv, cmd,
iwlwifi_mod_params.power_level, dtimper);
iwlwifi_mod_params.power_level - 1, dtimper);
else
iwl_static_sleep_cmd(priv, cmd,
IWL_POWER_INDEX_1, dtimper);

View file

@ -52,6 +52,7 @@
#define IWL_PASSIVE_DWELL_TIME_52 (10)
#define IWL_PASSIVE_DWELL_BASE (100)
#define IWL_CHANNEL_TUNE_TIME 5
#define MAX_SCAN_CHANNEL 50
static int iwl_send_scan_abort(struct iwl_priv *priv)
{
@ -616,7 +617,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
*/
static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
const u8 *ies, int ie_len, int left)
const u8 *ies, int ie_len, const u8 *ssid,
u8 ssid_len, int left)
{
int len = 0;
u8 *pos = NULL;
@ -638,14 +640,18 @@ static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
/* ...next IE... */
pos = &frame->u.probe_req.variable[0];
/* fill in our indirect SSID IE */
left -= 2;
/* fill in our SSID IE */
left -= ssid_len + 2;
if (left < 0)
return 0;
*pos++ = WLAN_EID_SSID;
*pos++ = 0;
*pos++ = ssid_len;
if (ssid && ssid_len) {
memcpy(pos, ssid, ssid_len);
pos += ssid_len;
}
len += 2;
len += ssid_len + 2;
if (WARN_ON(left < ie_len))
return len;
@ -679,6 +685,15 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
u8 active_chains;
u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
int ret;
int scan_cmd_size = sizeof(struct iwl_scan_cmd) +
MAX_SCAN_CHANNEL * sizeof(struct iwl_scan_channel) +
priv->fw->ucode_capa.max_probe_length;
const u8 *ssid = NULL;
u8 ssid_len = 0;
if (WARN_ON_ONCE(priv->scan_request &&
priv->scan_request->n_channels > MAX_SCAN_CHANNEL))
return -EINVAL;
lockdep_assert_held(&priv->mutex);
@ -686,8 +701,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
ctx = iwl_rxon_ctx_from_vif(vif);
if (!priv->scan_cmd) {
priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
IWL_MAX_SCAN_SIZE, GFP_KERNEL);
priv->scan_cmd = kmalloc(scan_cmd_size, GFP_KERNEL);
if (!priv->scan_cmd) {
IWL_DEBUG_SCAN(priv,
"fail to allocate memory for scan\n");
@ -695,7 +709,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
}
}
scan = priv->scan_cmd;
memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
memset(scan, 0, scan_cmd_size);
scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
@ -746,10 +760,18 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (priv->scan_request->n_ssids) {
int i, p = 0;
IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
for (i = 0; i < priv->scan_request->n_ssids; i++) {
/* always does wildcard anyway */
if (!priv->scan_request->ssids[i].ssid_len)
continue;
/*
* The highest priority SSID is inserted to the
* probe request template.
*/
ssid_len = priv->scan_request->ssids[0].ssid_len;
ssid = priv->scan_request->ssids[0].ssid;
/*
* Invert the order of ssids, the firmware will invert
* it back.
*/
for (i = priv->scan_request->n_ssids - 1; i >= 1; i--) {
scan->direct_scan[p].id = WLAN_EID_SSID;
scan->direct_scan[p].len =
priv->scan_request->ssids[i].ssid_len;
@ -883,7 +905,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
vif->addr,
priv->scan_request->ie,
priv->scan_request->ie_len,
IWL_MAX_SCAN_SIZE - sizeof(*scan));
ssid, ssid_len,
scan_cmd_size - sizeof(*scan));
break;
case IWL_SCAN_RADIO_RESET:
case IWL_SCAN_ROC:
@ -891,7 +914,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
cmd_len = iwl_fill_probe_req(
(struct ieee80211_mgmt *)scan->data,
iwl_bcast_addr, NULL, 0,
IWL_MAX_SCAN_SIZE - sizeof(*scan));
NULL, 0,
scan_cmd_size - sizeof(*scan));
break;
default:
BUG();

View file

@ -746,6 +746,11 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
hwsim_check_sta_magic(txi->control.sta);
ieee80211_tx_info_clear_status(txi);
/* frame was transmitted at most favorable rate at first attempt */
txi->control.rates[0].count = 1;
txi->control.rates[1].idx = -1;
if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
txi->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status_irqsafe(hw, skb);

View file

@ -29,6 +29,8 @@ mwifiex-y += scan.o
mwifiex-y += join.o
mwifiex-y += sta_ioctl.o
mwifiex-y += sta_cmd.o
mwifiex-y += uap_cmd.o
mwifiex-y += ie.o
mwifiex-y += sta_cmdresp.o
mwifiex-y += sta_event.o
mwifiex-y += sta_tx.o

View file

@ -20,6 +20,23 @@
#include "cfg80211.h"
#include "main.h"
static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = {
{
.max = 1, .types = BIT(NL80211_IFTYPE_STATION),
},
{
.max = 1, .types = BIT(NL80211_IFTYPE_AP),
},
};
static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = {
.limits = mwifiex_ap_sta_limits,
.num_different_channels = 1,
.n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits),
.max_interfaces = MWIFIEX_MAX_BSS_NUM,
.beacon_int_infra_match = true,
};
/*
* This function maps the nl802.11 channel type into driver channel type.
*
@ -67,7 +84,7 @@ mwifiex_is_alg_wep(u32 cipher)
/*
* This function retrieves the private structure from kernel wiphy structure.
*/
static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy)
static void *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy)
{
return (void *) (*(unsigned long *) wiphy_priv(wiphy));
}
@ -80,8 +97,10 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) {
if (mwifiex_set_encode(priv, NULL, 0, key_index, peer_mac, 1)) {
wiphy_err(wiphy, "deleting the crypto keys\n");
return -EFAULT;
}
@ -98,7 +117,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
enum nl80211_tx_power_setting type,
int mbm)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct mwifiex_power_cfg power_cfg;
int dbm = MBM_TO_DBM(mbm);
@ -109,6 +129,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
power_cfg.is_power_auto = 1;
}
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
return mwifiex_set_tx_power(priv, &power_cfg);
}
@ -148,7 +170,7 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
if (!priv->sec_info.wep_enabled)
return 0;
if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) {
if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
wiphy_err(wiphy, "set default Tx key index\n");
return -EFAULT;
}
@ -165,9 +187,11 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
struct key_params *params)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, params->key, params->key_len,
key_index, 0)) {
key_index, peer_mac, 0)) {
wiphy_err(wiphy, "crypto keys added\n");
return -EFAULT;
}
@ -192,13 +216,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg;
/* Set country code */
domain_info->country_code[0] = priv->country_code[0];
domain_info->country_code[1] = priv->country_code[1];
domain_info->country_code[0] = adapter->country_code[0];
domain_info->country_code[1] = adapter->country_code[1];
domain_info->country_code[2] = ' ';
band = mwifiex_band_to_radio_type(adapter->config_bands);
@ -250,6 +274,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
domain_info->no_of_triplet = no_of_triplet;
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "11D: setting domain info in FW\n");
@ -272,12 +298,12 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
static int mwifiex_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain"
" %c%c\n", request->alpha2[0], request->alpha2[1]);
wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n",
request->alpha2[0], request->alpha2[1]);
memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2));
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_DRIVER:
@ -361,33 +387,10 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv,
if (mwifiex_bss_set_channel(priv, &cfp))
return -EFAULT;
return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
}
/*
* CFG802.11 operation handler to set channel.
*
* This function can only be used when station is not connected.
*/
static int
mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
struct mwifiex_private *priv;
if (dev)
priv = mwifiex_netdev_get_priv(dev);
if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
else
priv = mwifiex_cfg80211_get_priv(wiphy);
if (priv->media_connected) {
wiphy_err(wiphy, "This setting is valid only when station "
"is not connected\n");
return -EINVAL;
}
return mwifiex_set_rf_channel(priv, chan, channel_type);
return mwifiex_uap_set_channel(priv, cfp.channel);
}
/*
@ -399,18 +402,13 @@ mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
static int
mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
{
int ret;
if (frag_thr < MWIFIEX_FRAG_MIN_VALUE ||
frag_thr > MWIFIEX_FRAG_MAX_VALUE)
return -EINVAL;
frag_thr = MWIFIEX_FRAG_MAX_VALUE;
/* Send request to firmware */
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
&frag_thr);
return ret;
return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
&frag_thr);
}
/*
@ -439,19 +437,85 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
static int
mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
int ret = 0;
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct mwifiex_uap_bss_param *bss_cfg;
int ret, bss_started, i;
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
ret = mwifiex_set_rts(priv, wiphy->rts_threshold);
if (ret)
return ret;
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
switch (priv->bss_role) {
case MWIFIEX_BSS_ROLE_UAP:
bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param),
GFP_KERNEL);
if (!bss_cfg)
return -ENOMEM;
mwifiex_set_sys_config_invalid_data(bss_cfg);
if (changed & WIPHY_PARAM_RTS_THRESHOLD)
bss_cfg->rts_threshold = wiphy->rts_threshold;
if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
bss_cfg->frag_threshold = wiphy->frag_threshold;
if (changed & WIPHY_PARAM_RETRY_LONG)
bss_cfg->retry_limit = wiphy->retry_long;
bss_started = priv->bss_started;
ret = mwifiex_send_cmd_sync(priv,
HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0,
NULL);
if (ret) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
kfree(bss_cfg);
return ret;
}
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_UAP_SYS_CONFIG,
HostCmd_ACT_GEN_SET,
UAP_BSS_PARAMS_I, bss_cfg);
kfree(bss_cfg);
if (ret) {
wiphy_err(wiphy, "Failed to set bss config\n");
return ret;
}
if (!bss_started)
break;
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_UAP_BSS_START,
HostCmd_ACT_GEN_SET, 0,
NULL);
if (ret) {
wiphy_err(wiphy, "Failed to start BSS\n");
return ret;
}
break;
case MWIFIEX_BSS_ROLE_STA:
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
ret = mwifiex_set_rts(priv,
wiphy->rts_threshold);
if (ret)
return ret;
}
if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
ret = mwifiex_set_frag(priv,
wiphy->frag_threshold);
if (ret)
return ret;
}
break;
}
}
if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
ret = mwifiex_set_frag(priv, wiphy->frag_threshold);
return ret;
return 0;
}
/*
@ -466,31 +530,59 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
int ret;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->bss_mode == type) {
wiphy_warn(wiphy, "already set to required type\n");
return 0;
}
priv->bss_mode = type;
switch (type) {
switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_ADHOC:
dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC;
wiphy_dbg(wiphy, "info: setting interface type to adhoc\n");
switch (type) {
case NL80211_IFTYPE_STATION:
break;
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name);
case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */
return 0;
case NL80211_IFTYPE_AP:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
return -EOPNOTSUPP;
}
break;
case NL80211_IFTYPE_STATION:
dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
wiphy_dbg(wiphy, "info: setting interface type to managed\n");
switch (type) {
case NL80211_IFTYPE_ADHOC:
break;
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name);
case NL80211_IFTYPE_STATION: /* This shouldn't happen */
return 0;
case NL80211_IFTYPE_AP:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
return -EOPNOTSUPP;
}
break;
case NL80211_IFTYPE_AP:
switch (type) {
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name);
case NL80211_IFTYPE_AP: /* This shouldn't happen */
return 0;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_STATION:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
return -EOPNOTSUPP;
}
break;
case NL80211_IFTYPE_UNSPECIFIED:
dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
wiphy_dbg(wiphy, "info: setting interface type to auto\n");
return 0;
default:
wiphy_err(wiphy, "unknown interface type: %d\n", type);
return -EINVAL;
wiphy_err(wiphy, "%s: unknown iftype: %d\n",
dev->name, dev->ieee80211_ptr->iftype);
return -EOPNOTSUPP;
}
dev->ieee80211_ptr->iftype = type;
priv->bss_mode = type;
mwifiex_deauthenticate(priv, NULL);
priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
@ -804,6 +896,90 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
return 0;
}
/* cfg80211 operation handler for stop ap.
* Function stops BSS running at uAP interface.
*/
static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (mwifiex_del_mgmt_ies(priv))
wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
return -1;
}
return 0;
}
/* cfg80211 operation handler for start_ap.
* Function sets beacon period, DTIM period, SSID and security into
* AP config structure.
* AP is configured with these settings and BSS is started.
*/
static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_ap_settings *params)
{
struct mwifiex_uap_bss_param *bss_cfg;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP)
return -1;
if (mwifiex_set_mgmt_ies(priv, params))
return -1;
bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
if (!bss_cfg)
return -ENOMEM;
mwifiex_set_sys_config_invalid_data(bss_cfg);
if (params->beacon_interval)
bss_cfg->beacon_period = params->beacon_interval;
if (params->dtim_period)
bss_cfg->dtim_period = params->dtim_period;
if (params->ssid && params->ssid_len) {
memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len);
bss_cfg->ssid.ssid_len = params->ssid_len;
}
if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg);
wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");
return -1;
}
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
kfree(bss_cfg);
return -1;
}
if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
HostCmd_ACT_GEN_SET,
UAP_BSS_PARAMS_I, bss_cfg)) {
wiphy_err(wiphy, "Failed to set the SSID\n");
kfree(bss_cfg);
return -1;
}
kfree(bss_cfg);
if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "Failed to start the BSS\n");
return -1;
}
return 0;
}
/*
* CFG802.11 operation handler for disconnection request.
*
@ -923,7 +1099,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
priv->wep_key_curr_index = 0;
priv->sec_info.encryption_mode = 0;
priv->sec_info.is_authtype_auto = 0;
ret = mwifiex_set_encode(priv, NULL, 0, 0, 1);
ret = mwifiex_set_encode(priv, NULL, 0, 0, NULL, 1);
if (mode == NL80211_IFTYPE_ADHOC) {
/* "privacy" is set only for ad-hoc mode */
@ -971,7 +1147,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
" with key len %d\n", sme->key_len);
priv->wep_key_curr_index = sme->key_idx;
ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
sme->key_idx, 0);
sme->key_idx, NULL, 0);
}
}
done:
@ -1050,6 +1226,11 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
goto done;
}
if (priv->bss_mode == NL80211_IFTYPE_AP) {
wiphy_err(wiphy, "skip association request for AP interface\n");
goto done;
}
wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
(char *) sme->ssid, sme->bssid);
@ -1283,15 +1464,12 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
u32 *flags,
struct vif_params *params)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_adapter *adapter;
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct net_device *dev;
void *mdev_priv;
struct wireless_dev *wdev;
if (!priv)
return NULL;
adapter = priv->adapter;
if (!adapter)
return NULL;
@ -1299,12 +1477,21 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];
if (priv->bss_mode) {
wiphy_err(wiphy, "cannot create multiple"
" station/adhoc interfaces\n");
wiphy_err(wiphy,
"cannot create multiple sta/adhoc ifaces\n");
return NULL;
}
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!wdev)
return NULL;
wdev->wiphy = wiphy;
priv->wdev = wdev;
wdev->iftype = NL80211_IFTYPE_STATION;
if (type == NL80211_IFTYPE_UNSPECIFIED)
priv->bss_mode = NL80211_IFTYPE_STATION;
else
@ -1312,10 +1499,35 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_type = MWIFIEX_BSS_TYPE_STA;
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
priv->bss_priority = 0;
priv->bss_priority = MWIFIEX_BSS_ROLE_STA;
priv->bss_role = MWIFIEX_BSS_ROLE_STA;
priv->bss_num = 0;
break;
case NL80211_IFTYPE_AP:
priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP];
if (priv->bss_mode) {
wiphy_err(wiphy, "Can't create multiple AP interfaces");
return NULL;
}
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!wdev)
return NULL;
priv->wdev = wdev;
wdev->wiphy = wiphy;
wdev->iftype = NL80211_IFTYPE_AP;
priv->bss_type = MWIFIEX_BSS_TYPE_UAP;
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
priv->bss_priority = MWIFIEX_BSS_ROLE_UAP;
priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
priv->bss_started = 0;
priv->bss_num = 0;
priv->bss_mode = type;
break;
default:
wiphy_err(wiphy, "type not supported\n");
@ -1329,6 +1541,15 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
goto error;
}
mwifiex_init_priv_params(priv, dev);
priv->netdev = dev;
mwifiex_setup_ht_caps(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv);
if (adapter->config_bands & BAND_A)
mwifiex_setup_ht_caps(
&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv);
dev_net_set(dev, wiphy_net(wiphy));
dev->ieee80211_ptr = priv->wdev;
dev->ieee80211_ptr->iftype = priv->bss_mode;
@ -1343,9 +1564,6 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
mdev_priv = netdev_priv(dev);
*((unsigned long *) mdev_priv) = (unsigned long) priv;
priv->netdev = dev;
mwifiex_init_priv_params(priv, dev);
SET_NETDEV_DEV(dev, adapter->dev);
/* Register network device */
@ -1417,7 +1635,6 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.get_station = mwifiex_cfg80211_get_station,
.dump_station = mwifiex_cfg80211_dump_station,
.set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
.set_channel = mwifiex_cfg80211_set_channel,
.join_ibss = mwifiex_cfg80211_join_ibss,
.leave_ibss = mwifiex_cfg80211_leave_ibss,
.add_key = mwifiex_cfg80211_add_key,
@ -1426,6 +1643,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
.set_tx_power = mwifiex_cfg80211_set_tx_power,
.set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask,
.start_ap = mwifiex_cfg80211_start_ap,
.stop_ap = mwifiex_cfg80211_stop_ap,
.set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
};
@ -1436,82 +1655,67 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
* default parameters and handler function pointers, and finally
* registers the device.
*/
int mwifiex_register_cfg80211(struct mwifiex_private *priv)
int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
{
int ret;
void *wdev_priv;
struct wireless_dev *wdev;
struct ieee80211_sta_ht_cap *ht_info;
struct wiphy *wiphy;
struct mwifiex_private *priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];
u8 *country_code;
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!wdev) {
dev_err(priv->adapter->dev, "%s: allocating wireless device\n",
__func__);
/* create a new wiphy for use with cfg80211 */
wiphy = wiphy_new(&mwifiex_cfg80211_ops,
sizeof(struct mwifiex_adapter *));
if (!wiphy) {
dev_err(adapter->dev, "%s: creating new wiphy\n", __func__);
return -ENOMEM;
}
wdev->wiphy =
wiphy_new(&mwifiex_cfg80211_ops,
sizeof(struct mwifiex_private *));
if (!wdev->wiphy) {
kfree(wdev);
return -ENOMEM;
}
wdev->iftype = NL80211_IFTYPE_STATION;
wdev->wiphy->max_scan_ssids = 10;
wdev->wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
ht_info = &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap;
mwifiex_setup_ht_caps(ht_info, priv);
wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
if (adapter->config_bands & BAND_A)
wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
else
wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
if (priv->adapter->config_bands & BAND_A) {
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
ht_info = &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap;
mwifiex_setup_ht_caps(ht_info, priv);
} else {
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
}
wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta;
wiphy->n_iface_combinations = 1;
/* Initialize cipher suits */
wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
wiphy->cipher_suites = mwifiex_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_CUSTOM_REGULATORY;
/* Reserve space for mwifiex specific private data for BSS */
wdev->wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
wiphy->reg_notifier = mwifiex_reg_notifier;
/* Set struct mwifiex_private pointer in wiphy_priv */
wdev_priv = wiphy_priv(wdev->wiphy);
/* Set struct mwifiex_adapter pointer in wiphy_priv */
wdev_priv = wiphy_priv(wiphy);
*(unsigned long *)wdev_priv = (unsigned long)adapter;
*(unsigned long *) wdev_priv = (unsigned long) priv;
set_wiphy_dev(wiphy, (struct device *)priv->adapter->dev);
set_wiphy_dev(wdev->wiphy, (struct device *) priv->adapter->dev);
ret = wiphy_register(wdev->wiphy);
ret = wiphy_register(wiphy);
if (ret < 0) {
dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n",
__func__);
wiphy_free(wdev->wiphy);
kfree(wdev);
dev_err(adapter->dev,
"%s: wiphy_register failed: %d\n", __func__, ret);
wiphy_free(wiphy);
return ret;
} else {
dev_dbg(priv->adapter->dev,
"info: successfully registered wiphy device\n");
}
country_code = mwifiex_11d_code_2_region(priv->adapter->region_code);
if (country_code && regulatory_hint(wdev->wiphy, country_code))
dev_err(priv->adapter->dev,
"%s: regulatory_hint failed\n", __func__);
priv->wdev = wdev;
if (country_code && regulatory_hint(wiphy, country_code))
dev_err(adapter->dev, "regulatory_hint() failed\n");
adapter->wiphy = wiphy;
return ret;
}

View file

@ -24,6 +24,6 @@
#include "main.h"
int mwifiex_register_cfg80211(struct mwifiex_private *);
int mwifiex_register_cfg80211(struct mwifiex_adapter *);
#endif

View file

@ -440,6 +440,11 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
do_gettimeofday(&tstamp);
dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n",
tstamp.tv_sec, tstamp.tv_usec, eventcause);
} else {
/* Handle PS_SLEEP/AWAKE events on STA */
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
if (!priv)
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
}
ret = mwifiex_process_sta_event(priv);
@ -540,8 +545,20 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
/* Prepare command */
if (cmd_no) {
ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf, cmd_ptr);
switch (cmd_no) {
case HostCmd_CMD_UAP_SYS_CONFIG:
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf,
cmd_ptr);
break;
default:
ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf,
cmd_ptr);
break;
}
} else {
ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf);
cmd_node->cmd_flag |= CMD_F_HOSTCMD;

View file

@ -28,7 +28,7 @@
#include <linux/ieee80211.h>
#define MWIFIEX_MAX_BSS_NUM (1)
#define MWIFIEX_MAX_BSS_NUM (2)
#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd)
* + 4 byte alignment
@ -55,11 +55,17 @@
#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024)
#define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024)
#define MAX_BEACON_PERIOD (4000)
#define MIN_BEACON_PERIOD (50)
#define MAX_DTIM_PERIOD (100)
#define MIN_DTIM_PERIOD (1)
#define MWIFIEX_RTS_MIN_VALUE (0)
#define MWIFIEX_RTS_MAX_VALUE (2347)
#define MWIFIEX_FRAG_MIN_VALUE (256)
#define MWIFIEX_FRAG_MAX_VALUE (2346)
#define MWIFIEX_RETRY_LIMIT 14
#define MWIFIEX_SDIO_BLOCK_SIZE 256
#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
@ -92,6 +98,11 @@ struct mwifiex_fw_image {
u32 fw_len;
};
struct mwifiex_802_11_ssid {
u32 ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN];
};
struct mwifiex_wait_queue {
wait_queue_head_t wait;
int status;

View file

@ -93,6 +93,20 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF)))
#define UAP_BSS_PARAMS_I 0
#define UAP_CUSTOM_IE_I 1
#define MWIFIEX_AUTO_IDX_MASK 0xffff
#define MWIFIEX_DELETE_MASK 0x0000
#define MGMT_MASK_ASSOC_REQ 0x01
#define MGMT_MASK_REASSOC_REQ 0x04
#define MGMT_MASK_ASSOC_RESP 0x02
#define MGMT_MASK_REASSOC_RESP 0x08
#define MGMT_MASK_PROBE_REQ 0x10
#define MGMT_MASK_PROBE_RESP 0x20
#define MGMT_MASK_BEACON 0x100
#define TLV_TYPE_UAP_SSID 0x0000
#define PROPRIETARY_TLV_BASE_ID 0x0100
#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
@ -104,14 +118,26 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
#define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32)
#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44)
#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45)
#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51)
#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
#define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64)
#define TLV_TYPE_UAP_AKMP (PROPRIETARY_TLV_BASE_ID + 65)
#define TLV_TYPE_UAP_FRAG_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 70)
#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82)
#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83)
#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93)
#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104)
#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 105)
#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113)
#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114)
#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145)
#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
@ -209,6 +235,9 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_RSSI_INFO 0x00a4
#define HostCmd_CMD_FUNC_INIT 0x00a9
#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
#define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0
#define HostCmd_CMD_UAP_BSS_START 0x00b1
#define HostCmd_CMD_UAP_BSS_STOP 0x00b2
#define HostCmd_CMD_11N_CFG 0x00cd
#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
@ -223,6 +252,19 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_SET_BSS_MODE 0x00f7
#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
#define PROTOCOL_NO_SECURITY 0x01
#define PROTOCOL_STATIC_WEP 0x02
#define PROTOCOL_WPA 0x08
#define PROTOCOL_WPA2 0x20
#define PROTOCOL_WPA2_MIXED 0x28
#define PROTOCOL_EAP 0x40
#define KEY_MGMT_NONE 0x04
#define KEY_MGMT_PSK 0x02
#define KEY_MGMT_EAP 0x01
#define CIPHER_TKIP 0x04
#define CIPHER_AES_CCMP 0x08
#define VALID_CIPHER_BITMAP 0x0c
enum ENH_PS_MODES {
EN_PS = 1,
DIS_PS = 2,
@ -313,15 +355,20 @@ enum ENH_PS_MODES {
#define EVENT_DATA_SNR_HIGH 0x00000027
#define EVENT_LINK_QUALITY 0x00000028
#define EVENT_PORT_RELEASE 0x0000002b
#define EVENT_UAP_STA_DEAUTH 0x0000002c
#define EVENT_UAP_STA_ASSOC 0x0000002d
#define EVENT_UAP_BSS_START 0x0000002e
#define EVENT_PRE_BEACON_LOST 0x00000031
#define EVENT_ADDBA 0x00000033
#define EVENT_DELBA 0x00000034
#define EVENT_BA_STREAM_TIEMOUT 0x00000037
#define EVENT_AMSDU_AGGR_CTRL 0x00000042
#define EVENT_UAP_BSS_IDLE 0x00000043
#define EVENT_UAP_BSS_ACTIVE 0x00000044
#define EVENT_WEP_ICV_ERR 0x00000046
#define EVENT_HS_ACT_REQ 0x00000047
#define EVENT_BW_CHANGE 0x00000048
#define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c
#define EVENT_HOSTWAKE_STAIE 0x0000004d
#define EVENT_ID_MASK 0xffff
@ -1103,6 +1150,101 @@ struct host_cmd_ds_802_11_eeprom_access {
u8 value;
} __packed;
struct host_cmd_tlv {
__le16 type;
__le16 len;
} __packed;
struct mwifiex_assoc_event {
u8 sta_addr[ETH_ALEN];
__le16 type;
__le16 len;
__le16 frame_control;
__le16 cap_info;
__le16 listen_interval;
u8 data[0];
} __packed;
struct host_cmd_ds_sys_config {
__le16 action;
u8 tlv[0];
};
struct host_cmd_tlv_akmp {
struct host_cmd_tlv tlv;
__le16 key_mgmt;
__le16 key_mgmt_operation;
} __packed;
struct host_cmd_tlv_pwk_cipher {
struct host_cmd_tlv tlv;
__le16 proto;
u8 cipher;
u8 reserved;
} __packed;
struct host_cmd_tlv_gwk_cipher {
struct host_cmd_tlv tlv;
u8 cipher;
u8 reserved;
} __packed;
struct host_cmd_tlv_passphrase {
struct host_cmd_tlv tlv;
u8 passphrase[0];
} __packed;
struct host_cmd_tlv_auth_type {
struct host_cmd_tlv tlv;
u8 auth_type;
} __packed;
struct host_cmd_tlv_encrypt_protocol {
struct host_cmd_tlv tlv;
__le16 proto;
} __packed;
struct host_cmd_tlv_ssid {
struct host_cmd_tlv tlv;
u8 ssid[0];
} __packed;
struct host_cmd_tlv_beacon_period {
struct host_cmd_tlv tlv;
__le16 period;
} __packed;
struct host_cmd_tlv_dtim_period {
struct host_cmd_tlv tlv;
u8 period;
} __packed;
struct host_cmd_tlv_frag_threshold {
struct host_cmd_tlv tlv;
__le16 frag_thr;
} __packed;
struct host_cmd_tlv_rts_threshold {
struct host_cmd_tlv tlv;
__le16 rts_thr;
} __packed;
struct host_cmd_tlv_retry_limit {
struct host_cmd_tlv tlv;
u8 limit;
} __packed;
struct host_cmd_tlv_mac_addr {
struct host_cmd_tlv tlv;
u8 mac_addr[ETH_ALEN];
} __packed;
struct host_cmd_tlv_channel_band {
struct host_cmd_tlv tlv;
u8 band_config;
u8 channel;
} __packed;
struct host_cmd_ds_802_11_rf_channel {
__le16 action;
__le16 current_channel;
@ -1167,6 +1309,20 @@ struct host_cmd_ds_802_11_subsc_evt {
__le16 events;
} __packed;
struct mwifiex_ie {
__le16 ie_index;
__le16 mgmt_subtype_mask;
__le16 ie_length;
u8 ie_buffer[IEEE_MAX_IE_SIZE];
} __packed;
#define MAX_MGMT_IE_INDEX 16
struct mwifiex_ie_list {
__le16 type;
__le16 len;
struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX];
} __packed;
struct host_cmd_ds_command {
__le16 command;
__le16 size;
@ -1217,6 +1373,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_pcie_details pcie_host_spec;
struct host_cmd_ds_802_11_eeprom_access eeprom;
struct host_cmd_ds_802_11_subsc_evt subsc_evt;
struct host_cmd_ds_sys_config uap_sys_config;
} params;
} __packed;

View file

@ -0,0 +1,396 @@
/*
* Marvell Wireless LAN device driver: management IE handling- setting and
* deleting IE.
*
* Copyright (C) 2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#include "main.h"
/* This function checks if current IE index is used by any on other interface.
* Return: -1: yes, current IE index is used by someone else.
* 0: no, current IE index is NOT used by other interface.
*/
static int
mwifiex_ie_index_used_by_other_intf(struct mwifiex_private *priv, u16 idx)
{
int i;
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_ie *ie;
for (i = 0; i < adapter->priv_num; i++) {
if (adapter->priv[i] != priv) {
ie = &adapter->priv[i]->mgmt_ie[idx];
if (ie->mgmt_subtype_mask && ie->ie_length)
return -1;
}
}
return 0;
}
/* Get unused IE index. This index will be used for setting new IE */
static int
mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask,
struct mwifiex_ie *ie, u16 *index)
{
u16 mask, len, i;
for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) {
mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask);
len = le16_to_cpu(priv->mgmt_ie[i].ie_length) +
le16_to_cpu(ie->ie_length);
if (mask == MWIFIEX_AUTO_IDX_MASK)
continue;
if (mask == subtype_mask) {
if (len > IEEE_MAX_IE_SIZE)
continue;
*index = i;
return 0;
}
if (!priv->mgmt_ie[i].ie_length) {
if (mwifiex_ie_index_used_by_other_intf(priv, i))
continue;
*index = i;
return 0;
}
}
return -1;
}
/* This function prepares IE data buffer for command to be sent to FW */
static int
mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
struct mwifiex_ie_list *ie_list)
{
u16 travel_len, index, mask;
s16 input_len;
struct mwifiex_ie *ie;
u8 *tmp;
input_len = le16_to_cpu(ie_list->len);
travel_len = sizeof(struct host_cmd_tlv);
ie_list->len = 0;
while (input_len > 0) {
ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len);
input_len -= le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
travel_len += le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
index = le16_to_cpu(ie->ie_index);
mask = le16_to_cpu(ie->mgmt_subtype_mask);
if (index == MWIFIEX_AUTO_IDX_MASK) {
/* automatic addition */
if (mwifiex_ie_get_autoidx(priv, mask, ie, &index))
return -1;
if (index == MWIFIEX_AUTO_IDX_MASK)
return -1;
tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer;
tmp += le16_to_cpu(priv->mgmt_ie[index].ie_length);
memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length));
le16_add_cpu(&priv->mgmt_ie[index].ie_length,
le16_to_cpu(ie->ie_length));
priv->mgmt_ie[index].ie_index = cpu_to_le16(index);
priv->mgmt_ie[index].mgmt_subtype_mask =
cpu_to_le16(mask);
ie->ie_index = cpu_to_le16(index);
ie->ie_length = priv->mgmt_ie[index].ie_length;
memcpy(&ie->ie_buffer, &priv->mgmt_ie[index].ie_buffer,
le16_to_cpu(priv->mgmt_ie[index].ie_length));
} else {
if (mask != MWIFIEX_DELETE_MASK)
return -1;
/*
* Check if this index is being used on any
* other interface.
*/
if (mwifiex_ie_index_used_by_other_intf(priv, index))
return -1;
ie->ie_length = 0;
memcpy(&priv->mgmt_ie[index], ie,
sizeof(struct mwifiex_ie));
}
le16_add_cpu(&ie_list->len,
le16_to_cpu(priv->mgmt_ie[index].ie_length) +
MWIFIEX_IE_HDR_SIZE);
}
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
HostCmd_ACT_GEN_SET,
UAP_CUSTOM_IE_I, ie_list);
return 0;
}
/* Copy individual custom IEs for beacon, probe response and assoc response
* and prepare single structure for IE setting.
* This function also updates allocated IE indices from driver.
*/
static int
mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
struct mwifiex_ie *beacon_ie, u16 *beacon_idx,
struct mwifiex_ie *pr_ie, u16 *probe_idx,
struct mwifiex_ie *ar_ie, u16 *assoc_idx)
{
struct mwifiex_ie_list *ap_custom_ie;
u8 *pos;
u16 len;
int ret;
ap_custom_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!ap_custom_ie)
return -ENOMEM;
ap_custom_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
pos = (u8 *)ap_custom_ie->ie_list;
if (beacon_ie) {
len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(beacon_ie->ie_length);
memcpy(pos, beacon_ie, len);
pos += len;
le16_add_cpu(&ap_custom_ie->len, len);
}
if (pr_ie) {
len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(pr_ie->ie_length);
memcpy(pos, pr_ie, len);
pos += len;
le16_add_cpu(&ap_custom_ie->len, len);
}
if (ar_ie) {
len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(ar_ie->ie_length);
memcpy(pos, ar_ie, len);
pos += len;
le16_add_cpu(&ap_custom_ie->len, len);
}
ret = mwifiex_update_autoindex_ies(priv, ap_custom_ie);
pos = (u8 *)(&ap_custom_ie->ie_list[0].ie_index);
if (beacon_ie && *beacon_idx == MWIFIEX_AUTO_IDX_MASK) {
/* save beacon ie index after auto-indexing */
*beacon_idx = le16_to_cpu(ap_custom_ie->ie_list[0].ie_index);
len = sizeof(*beacon_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(beacon_ie->ie_length);
pos += len;
}
if (pr_ie && le16_to_cpu(pr_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK) {
/* save probe resp ie index after auto-indexing */
*probe_idx = *((u16 *)pos);
len = sizeof(*pr_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(pr_ie->ie_length);
pos += len;
}
if (ar_ie && le16_to_cpu(ar_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK)
/* save assoc resp ie index after auto-indexing */
*assoc_idx = *((u16 *)pos);
return ret;
}
/* This function parses different IEs- Tail IEs, beacon IEs, probe response IEs,
* association response IEs from cfg80211_ap_settings function and sets these IE
* to FW.
*/
int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
struct cfg80211_ap_settings *params)
{
struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
struct ieee_types_header *ie = NULL;
u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK;
u16 ar_idx = MWIFIEX_AUTO_IDX_MASK, rsn_idx = MWIFIEX_AUTO_IDX_MASK;
u16 mask;
int ret = 0;
if (params->beacon.tail && params->beacon.tail_len) {
ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, params->beacon.tail,
params->beacon.tail_len);
if (ie) {
rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!rsn_ie)
return -ENOMEM;
rsn_ie->ie_index = cpu_to_le16(rsn_idx);
mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
MGMT_MASK_ASSOC_RESP;
rsn_ie->mgmt_subtype_mask = cpu_to_le16(mask);
rsn_ie->ie_length = cpu_to_le16(ie->len + 2);
memcpy(rsn_ie->ie_buffer, ie, ie->len + 2);
if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &rsn_idx,
NULL, NULL,
NULL, NULL)) {
ret = -1;
goto done;
}
priv->rsn_idx = rsn_idx;
}
}
if (params->beacon.beacon_ies && params->beacon.beacon_ies_len) {
beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!beacon_ie) {
ret = -ENOMEM;
goto done;
}
beacon_ie->ie_index = cpu_to_le16(beacon_idx);
beacon_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON);
beacon_ie->ie_length =
cpu_to_le16(params->beacon.beacon_ies_len);
memcpy(beacon_ie->ie_buffer, params->beacon.beacon_ies,
params->beacon.beacon_ies_len);
}
if (params->beacon.proberesp_ies && params->beacon.proberesp_ies_len) {
pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!pr_ie) {
ret = -ENOMEM;
goto done;
}
pr_ie->ie_index = cpu_to_le16(pr_idx);
pr_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_PROBE_RESP);
pr_ie->ie_length =
cpu_to_le16(params->beacon.proberesp_ies_len);
memcpy(pr_ie->ie_buffer, params->beacon.proberesp_ies,
params->beacon.proberesp_ies_len);
}
if (params->beacon.assocresp_ies && params->beacon.assocresp_ies_len) {
ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!ar_ie) {
ret = -ENOMEM;
goto done;
}
ar_ie->ie_index = cpu_to_le16(ar_idx);
mask = MGMT_MASK_ASSOC_RESP | MGMT_MASK_REASSOC_RESP;
ar_ie->mgmt_subtype_mask = cpu_to_le16(mask);
ar_ie->ie_length =
cpu_to_le16(params->beacon.assocresp_ies_len);
memcpy(ar_ie->ie_buffer, params->beacon.assocresp_ies,
params->beacon.assocresp_ies_len);
}
if (beacon_ie || pr_ie || ar_ie) {
ret = mwifiex_update_uap_custom_ie(priv, beacon_ie,
&beacon_idx, pr_ie,
&pr_idx, ar_ie, &ar_idx);
if (ret)
goto done;
}
priv->beacon_idx = beacon_idx;
priv->proberesp_idx = pr_idx;
priv->assocresp_idx = ar_idx;
done:
kfree(beacon_ie);
kfree(pr_ie);
kfree(ar_ie);
kfree(rsn_ie);
return ret;
}
/* This function removes management IE set */
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv)
{
struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
int ret = 0;
if (priv->rsn_idx != MWIFIEX_AUTO_IDX_MASK) {
rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!rsn_ie)
return -ENOMEM;
rsn_ie->ie_index = cpu_to_le16(priv->rsn_idx);
rsn_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
rsn_ie->ie_length = 0;
if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &priv->rsn_idx,
NULL, &priv->proberesp_idx,
NULL, &priv->assocresp_idx)) {
ret = -1;
goto done;
}
priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
}
if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) {
beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!beacon_ie) {
ret = -ENOMEM;
goto done;
}
beacon_ie->ie_index = cpu_to_le16(priv->beacon_idx);
beacon_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
beacon_ie->ie_length = 0;
}
if (priv->proberesp_idx != MWIFIEX_AUTO_IDX_MASK) {
pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!pr_ie) {
ret = -ENOMEM;
goto done;
}
pr_ie->ie_index = cpu_to_le16(priv->proberesp_idx);
pr_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
pr_ie->ie_length = 0;
}
if (priv->assocresp_idx != MWIFIEX_AUTO_IDX_MASK) {
ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!ar_ie) {
ret = -ENOMEM;
goto done;
}
ar_ie->ie_index = cpu_to_le16(priv->assocresp_idx);
ar_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
ar_ie->ie_length = 0;
}
if (beacon_ie || pr_ie || ar_ie)
ret = mwifiex_update_uap_custom_ie(priv,
beacon_ie, &priv->beacon_idx,
pr_ie, &priv->proberesp_idx,
ar_ie, &priv->assocresp_idx);
done:
kfree(beacon_ie);
kfree(pr_ie);
kfree(ar_ie);
kfree(rsn_ie);
return ret;
}

View file

@ -279,6 +279,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0;
adapter->channel_type = NL80211_CHAN_HT20;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
}
/*

View file

@ -62,6 +62,36 @@ enum {
BAND_AN = 16,
};
#define MWIFIEX_WPA_PASSHPHRASE_LEN 64
struct wpa_param {
u8 pairwise_cipher_wpa;
u8 pairwise_cipher_wpa2;
u8 group_cipher;
u32 length;
u8 passphrase[MWIFIEX_WPA_PASSHPHRASE_LEN];
};
#define KEY_MGMT_ON_HOST 0x03
#define MWIFIEX_AUTH_MODE_AUTO 0xFF
#define BAND_CONFIG_MANUAL 0x00
struct mwifiex_uap_bss_param {
u8 channel;
u8 band_cfg;
u16 rts_threshold;
u16 frag_threshold;
u8 retry_limit;
struct mwifiex_802_11_ssid ssid;
u8 bcast_ssid_ctl;
u8 radio_ctl;
u8 dtim_period;
u16 beacon_period;
u16 auth_mode;
u16 protocol;
u16 key_mgmt;
u16 key_mgmt_operation;
struct wpa_param wpa_cfg;
};
enum {
ADHOC_IDLE,
ADHOC_STARTED,
@ -269,6 +299,8 @@ struct mwifiex_ds_read_eeprom {
#define IEEE_MAX_IE_SIZE 256
#define MWIFIEX_IE_HDR_SIZE (sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE)
struct mwifiex_ds_misc_gen_ie {
u32 type;
u32 len;

View file

@ -1374,22 +1374,28 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
*
* In case of infra made, it sends deauthentication request, and
* in case of ad-hoc mode, a stop network request is sent to the firmware.
* In AP mode, a command to stop bss is sent to firmware.
*/
int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
{
int ret = 0;
if (!priv->media_connected)
return 0;
if (priv->media_connected) {
if (priv->bss_mode == NL80211_IFTYPE_STATION) {
ret = mwifiex_deauthenticate_infra(priv, mac);
} else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
ret = mwifiex_send_cmd_sync(priv,
HostCmd_CMD_802_11_AD_HOC_STOP,
HostCmd_ACT_GEN_SET, 0, NULL);
}
switch (priv->bss_mode) {
case NL80211_IFTYPE_STATION:
return mwifiex_deauthenticate_infra(priv, mac);
case NL80211_IFTYPE_ADHOC:
return mwifiex_send_cmd_sync(priv,
HostCmd_CMD_802_11_AD_HOC_STOP,
HostCmd_ACT_GEN_SET, 0, NULL);
case NL80211_IFTYPE_AP:
return mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL);
default:
break;
}
return ret;
return 0;
}
EXPORT_SYMBOL_GPL(mwifiex_deauthenticate);

View file

@ -64,17 +64,17 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
adapter->priv_num = 0;
/* Allocate memory for private structure */
adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL);
if (!adapter->priv[0]) {
dev_err(adapter->dev,
"%s: failed to alloc priv[0]\n", __func__);
goto error;
for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) {
/* Allocate memory for private structure */
adapter->priv[i] =
kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL);
if (!adapter->priv[i])
goto error;
adapter->priv[i]->adapter = adapter;
adapter->priv[i]->bss_priority = i;
adapter->priv_num++;
}
adapter->priv_num++;
adapter->priv[0]->adapter = adapter;
mwifiex_init_lock_list(adapter);
init_timer(&adapter->cmd_timer);
@ -349,19 +349,26 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
goto done;
priv = adapter->priv[0];
if (mwifiex_register_cfg80211(priv) != 0) {
priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
if (mwifiex_register_cfg80211(adapter)) {
dev_err(adapter->dev, "cannot register with cfg80211\n");
goto err_init_fw;
}
rtnl_lock();
/* Create station interface by default */
if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
if (!mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d",
NL80211_IFTYPE_STATION, NULL, NULL)) {
dev_err(adapter->dev, "cannot create default STA interface\n");
goto err_add_intf;
}
/* Create AP interface by default */
if (!mwifiex_add_virtual_intf(adapter->wiphy, "uap%d",
NL80211_IFTYPE_AP, NULL, NULL)) {
dev_err(adapter->dev, "cannot create default AP interface\n");
goto err_add_intf;
}
rtnl_unlock();
mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
@ -369,7 +376,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
goto done;
err_add_intf:
mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev);
rtnl_unlock();
err_init_fw:
pr_debug("info: %s: unregister device\n", __func__);
@ -633,6 +640,12 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv,
priv->current_key_index = 0;
priv->media_connected = false;
memset(&priv->nick_name, 0, sizeof(priv->nick_name));
memset(priv->mgmt_ie, 0,
sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX);
priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK;
priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK;
priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK;
priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
priv->num_tx_timeout = 0;
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
}
@ -830,19 +843,21 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
rtnl_lock();
if (priv->wdev && priv->netdev)
mwifiex_del_virtual_intf(priv->wdev->wiphy,
priv->netdev);
mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev);
rtnl_unlock();
}
priv = adapter->priv[0];
if (!priv)
if (!priv || !priv->wdev)
goto exit_remove;
if (priv->wdev) {
wiphy_unregister(priv->wdev->wiphy);
wiphy_free(priv->wdev->wiphy);
kfree(priv->wdev);
wiphy_unregister(priv->wdev->wiphy);
wiphy_free(priv->wdev->wiphy);
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
if (priv)
kfree(priv->wdev);
}
mwifiex_terminate_workqueue(adapter);

View file

@ -116,6 +116,7 @@ enum {
#define MAX_FREQUENCY_BAND_BG 2484
#define MWIFIEX_EVENT_HEADER_LEN 4
#define MWIFIEX_UAP_EVENT_EXTRA_HEADER 2
#define MWIFIEX_TYPE_LEN 4
#define MWIFIEX_USB_TYPE_CMD 0xF00DFACE
@ -370,6 +371,7 @@ struct mwifiex_private {
u8 bss_role;
u8 bss_priority;
u8 bss_num;
u8 bss_started;
u8 frame_type;
u8 curr_addr[ETH_ALEN];
u8 media_connected;
@ -470,12 +472,16 @@ struct mwifiex_private {
struct cfg80211_scan_request *scan_request;
struct mwifiex_user_scan_cfg *user_scan_cfg;
u8 cfg_bssid[6];
u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
struct wps wps;
u8 scan_block;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
u8 subsc_evt_rssi_state;
struct mwifiex_ie mgmt_ie[MAX_MGMT_IE_INDEX];
u16 beacon_idx;
u16 proberesp_idx;
u16 assocresp_idx;
u16 rsn_idx;
};
enum mwifiex_ba_status {
@ -571,6 +577,7 @@ struct mwifiex_adapter {
char fw_name[32];
int winner;
struct device *dev;
struct wiphy *wiphy;
bool surprise_removed;
u32 fw_release_number;
u16 init_wait_q_woken;
@ -677,6 +684,8 @@ struct mwifiex_adapter {
struct cmd_ctrl_node *cmd_queued;
spinlock_t queue_lock; /* lock for tx queues */
struct completion fw_load;
u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
u16 max_mgmt_ie_index;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@ -760,6 +769,9 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid,
void *data_buf, void *cmd_buf);
int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid,
void *data_buf, void *cmd_buf);
int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
struct host_cmd_ds_command *resp);
int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
@ -820,6 +832,9 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
int is_command_pending(struct mwifiex_adapter *adapter);
void mwifiex_init_priv_params(struct mwifiex_private *priv,
struct net_device *dev);
int mwifiex_set_secure_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_config,
struct cfg80211_ap_settings *params);
/*
* This function checks if the queuing is RA based or not.
@ -933,7 +948,8 @@ int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel);
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
int key_len, u8 key_index, int disable);
int key_len, u8 key_index, const u8 *mac_addr,
int disable);
int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
@ -969,6 +985,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
int mwifiex_main_process(struct mwifiex_adapter *);
int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel);
int mwifiex_bss_set_channel(struct mwifiex_private *,
struct mwifiex_chan_freq_power *cfp);
int mwifiex_get_bss_info(struct mwifiex_private *,
@ -986,6 +1003,11 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
u32 *flags, struct vif_params *params);
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config);
int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
struct cfg80211_ap_settings *params);
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv);
u8 *mwifiex_11d_code_2_region(u8 code);
#ifdef CONFIG_DEBUG_FS

View file

@ -498,7 +498,8 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
{
struct host_cmd_ds_802_11_key_material *key_material =
&cmd->params.key_material;
u16 key_param_len = 0;
struct host_cmd_tlv_mac_addr *tlv_mac;
u16 key_param_len = 0, cmd_size;
int ret = 0;
const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -614,11 +615,26 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
cpu_to_le16((u16) enc_key->key_len +
KEYPARAMSET_FIXED_LEN);
key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN)
key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
+ sizeof(struct mwifiex_ie_types_header);
cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
+ key_param_len);
if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
tlv_mac = (void *)((u8 *)&key_material->key_param_set +
key_param_len);
tlv_mac->tlv.type = cpu_to_le16(TLV_TYPE_STA_MAC_ADDR);
tlv_mac->tlv.len = cpu_to_le16(ETH_ALEN);
memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN);
cmd_size = key_param_len + S_DS_GEN +
sizeof(key_material->action) +
sizeof(struct host_cmd_tlv_mac_addr);
} else {
cmd_size = key_param_len + S_DS_GEN +
sizeof(key_material->action);
}
cmd->size = cpu_to_le16(cmd_size);
}
return ret;
@ -1248,13 +1264,15 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
/* Enable IEEE PS by default */
priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_802_11_PS_MODE_ENH,
EN_AUTO_PS, BITMAP_STA_PS, NULL);
if (ret)
return -1;
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Enable IEEE PS by default */
priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
ret = mwifiex_send_cmd_async(
priv, HostCmd_CMD_802_11_PS_MODE_ENH,
EN_AUTO_PS, BITMAP_STA_PS, NULL);
if (ret)
return -1;
}
}
/* get tx rate */
@ -1270,12 +1288,14 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
/* set ibss coalescing_status */
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
HostCmd_ACT_GEN_SET, 0, &enable);
if (ret)
return -1;
if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
/* set ibss coalescing_status */
ret = mwifiex_send_cmd_async(
priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
HostCmd_ACT_GEN_SET, 0, &enable);
if (ret)
return -1;
}
memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
amsdu_aggr_ctrl.enable = true;
@ -1293,7 +1313,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
if (first_sta && (priv->adapter->iface_type != MWIFIEX_USB)) {
if (first_sta && priv->adapter->iface_type != MWIFIEX_USB &&
priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Enable auto deep sleep */
auto_ds.auto_ds = DEEP_SLEEP_ON;
auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
@ -1305,12 +1326,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
return -1;
}
/* Send cmd to FW to enable/disable 11D function */
state_11d = ENABLE_11D;
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d);
if (ret)
dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Send cmd to FW to enable/disable 11D function */
state_11d = ENABLE_11D;
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, DOT11D_I,
&state_11d);
if (ret)
dev_err(priv->adapter->dev,
"11D: failed to enable 11D\n");
}
/* Send cmd to FW to configure 11n specific configuration
* (Short GI, Channel BW, Green field support etc.) for transmit

View file

@ -944,6 +944,14 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
ret = mwifiex_ret_subsc_evt(priv, resp, data_buf);
break;
case HostCmd_CMD_UAP_SYS_CONFIG:
break;
case HostCmd_CMD_UAP_BSS_START:
priv->bss_started = 1;
break;
case HostCmd_CMD_UAP_BSS_STOP:
priv->bss_started = 0;
break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);

View file

@ -184,8 +184,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
int mwifiex_process_sta_event(struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
int ret = 0;
int len, ret = 0;
u32 eventcause = adapter->event_cause;
struct station_info sinfo;
struct mwifiex_assoc_event *event;
switch (eventcause) {
case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
@ -402,6 +404,53 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_HOSTWAKE_STAIE:
dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
break;
case EVENT_UAP_STA_ASSOC:
skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
memset(&sinfo, 0, sizeof(sinfo));
event = (struct mwifiex_assoc_event *)adapter->event_skb->data;
if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
len = -1;
if (ieee80211_is_assoc_req(event->frame_control))
len = 0;
else if (ieee80211_is_reassoc_req(event->frame_control))
/* There will be ETH_ALEN bytes of
* current_ap_addr before the re-assoc ies.
*/
len = ETH_ALEN;
if (len != -1) {
sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
sinfo.assoc_req_ies = (u8 *)&event->data[len];
len = (u8 *)sinfo.assoc_req_ies -
(u8 *)&event->frame_control;
sinfo.assoc_req_ies_len =
le16_to_cpu(event->len) - (u16)len;
}
}
cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
GFP_KERNEL);
break;
case EVENT_UAP_STA_DEAUTH:
skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
cfg80211_del_sta(priv->netdev, adapter->event_skb->data,
GFP_KERNEL);
break;
case EVENT_UAP_BSS_IDLE:
priv->media_connected = false;
break;
case EVENT_UAP_BSS_ACTIVE:
priv->media_connected = true;
break;
case EVENT_UAP_BSS_START:
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
memcpy(priv->netdev->dev_addr, adapter->event_body+2, ETH_ALEN);
break;
case EVENT_UAP_MIC_COUNTERMEASURES:
/* For future development */
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);

View file

@ -462,7 +462,7 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
info->bss_chan = bss_desc->channel;
memcpy(info->country_code, priv->country_code,
memcpy(info->country_code, adapter->country_code,
IEEE80211_COUNTRY_STRING_LEN);
info->media_connected = priv->media_connected;
@ -1219,7 +1219,8 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
* with requisite parameters and calls the IOCTL handler.
*/
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
int key_len, u8 key_index, int disable)
int key_len, u8 key_index,
const u8 *mac_addr, int disable)
{
struct mwifiex_ds_encrypt_key encrypt_key;
@ -1229,8 +1230,12 @@ int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
encrypt_key.key_index = key_index;
if (key_len)
memcpy(encrypt_key.key_material, key, key_len);
if (mac_addr)
memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
} else {
encrypt_key.key_disable = true;
if (mac_addr)
memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
}
return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);

View file

@ -0,0 +1,432 @@
/*
* Marvell Wireless LAN device driver: AP specific command handling
*
* Copyright (C) 2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#include "main.h"
/* This function parses security related parameters from cfg80211_ap_settings
* and sets into FW understandable bss_config structure.
*/
int mwifiex_set_secure_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_config,
struct cfg80211_ap_settings *params) {
int i;
switch (params->auth_type) {
case NL80211_AUTHTYPE_OPEN_SYSTEM:
bss_config->auth_mode = WLAN_AUTH_OPEN;
break;
case NL80211_AUTHTYPE_SHARED_KEY:
bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
break;
case NL80211_AUTHTYPE_NETWORK_EAP:
bss_config->auth_mode = WLAN_AUTH_LEAP;
break;
default:
bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO;
break;
}
bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
for (i = 0; i < params->crypto.n_akm_suites; i++) {
switch (params->crypto.akm_suites[i]) {
case WLAN_AKM_SUITE_8021X:
if (params->crypto.wpa_versions &
NL80211_WPA_VERSION_1) {
bss_config->protocol = PROTOCOL_WPA;
bss_config->key_mgmt = KEY_MGMT_EAP;
}
if (params->crypto.wpa_versions &
NL80211_WPA_VERSION_2) {
bss_config->protocol = PROTOCOL_WPA2;
bss_config->key_mgmt = KEY_MGMT_EAP;
}
break;
case WLAN_AKM_SUITE_PSK:
if (params->crypto.wpa_versions &
NL80211_WPA_VERSION_1) {
bss_config->protocol = PROTOCOL_WPA;
bss_config->key_mgmt = KEY_MGMT_PSK;
}
if (params->crypto.wpa_versions &
NL80211_WPA_VERSION_2) {
bss_config->protocol = PROTOCOL_WPA2;
bss_config->key_mgmt = KEY_MGMT_PSK;
}
break;
default:
break;
}
}
for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
switch (params->crypto.ciphers_pairwise[i]) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
break;
case WLAN_CIPHER_SUITE_TKIP:
bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
bss_config->wpa_cfg.pairwise_cipher_wpa2 =
CIPHER_AES_CCMP;
default:
break;
}
}
switch (params->crypto.cipher_group) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
break;
case WLAN_CIPHER_SUITE_TKIP:
bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
break;
default:
break;
}
return 0;
}
/* This function initializes some of mwifiex_uap_bss_param variables.
* This helps FW in ignoring invalid values. These values may or may not
* be get updated to valid ones at later stage.
*/
void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
{
config->bcast_ssid_ctl = 0x7F;
config->radio_ctl = 0x7F;
config->dtim_period = 0x7F;
config->beacon_period = 0x7FFF;
config->auth_mode = 0x7F;
config->rts_threshold = 0x7FFF;
config->frag_threshold = 0x7FFF;
config->retry_limit = 0x7F;
}
/* This function parses BSS related parameters from structure
* and prepares TLVs. These TLVs are appended to command buffer.
*/
static int
mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
{
struct host_cmd_tlv_dtim_period *dtim_period;
struct host_cmd_tlv_beacon_period *beacon_period;
struct host_cmd_tlv_ssid *ssid;
struct host_cmd_tlv_channel_band *chan_band;
struct host_cmd_tlv_frag_threshold *frag_threshold;
struct host_cmd_tlv_rts_threshold *rts_threshold;
struct host_cmd_tlv_retry_limit *retry_limit;
struct host_cmd_tlv_pwk_cipher *pwk_cipher;
struct host_cmd_tlv_gwk_cipher *gwk_cipher;
struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
struct host_cmd_tlv_auth_type *auth_type;
struct host_cmd_tlv_passphrase *passphrase;
struct host_cmd_tlv_akmp *tlv_akmp;
struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
u16 cmd_size = *param_size;
if (bss_cfg->ssid.ssid_len) {
ssid = (struct host_cmd_tlv_ssid *)tlv;
ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
cmd_size += sizeof(struct host_cmd_tlv) +
bss_cfg->ssid.ssid_len;
tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len;
}
if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) {
chan_band = (struct host_cmd_tlv_channel_band *)tlv;
chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
chan_band->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
sizeof(struct host_cmd_tlv));
chan_band->band_config = bss_cfg->band_cfg;
chan_band->channel = bss_cfg->channel;
cmd_size += sizeof(struct host_cmd_tlv_channel_band);
tlv += sizeof(struct host_cmd_tlv_channel_band);
}
if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD &&
bss_cfg->beacon_period <= MAX_BEACON_PERIOD) {
beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
beacon_period->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
beacon_period->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
sizeof(struct host_cmd_tlv));
beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
tlv += sizeof(struct host_cmd_tlv_beacon_period);
}
if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD &&
bss_cfg->dtim_period <= MAX_DTIM_PERIOD) {
dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
dtim_period->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
sizeof(struct host_cmd_tlv));
dtim_period->period = bss_cfg->dtim_period;
cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
tlv += sizeof(struct host_cmd_tlv_dtim_period);
}
if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) {
rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
rts_threshold->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
rts_threshold->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
sizeof(struct host_cmd_tlv));
rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
tlv += sizeof(struct host_cmd_tlv_frag_threshold);
}
if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) &&
(bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) {
frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
frag_threshold->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
frag_threshold->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) -
sizeof(struct host_cmd_tlv));
frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
tlv += sizeof(struct host_cmd_tlv_frag_threshold);
}
if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) {
retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
retry_limit->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
sizeof(struct host_cmd_tlv));
retry_limit->limit = (u8)bss_cfg->retry_limit;
cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
tlv += sizeof(struct host_cmd_tlv_retry_limit);
}
if ((bss_cfg->protocol & PROTOCOL_WPA) ||
(bss_cfg->protocol & PROTOCOL_WPA2) ||
(bss_cfg->protocol & PROTOCOL_EAP)) {
tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
tlv_akmp->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
sizeof(struct host_cmd_tlv));
tlv_akmp->key_mgmt_operation =
cpu_to_le16(bss_cfg->key_mgmt_operation);
tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
cmd_size += sizeof(struct host_cmd_tlv_akmp);
tlv += sizeof(struct host_cmd_tlv_akmp);
if (bss_cfg->wpa_cfg.pairwise_cipher_wpa &
VALID_CIPHER_BITMAP) {
pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
pwk_cipher->tlv.type =
cpu_to_le16(TLV_TYPE_PWK_CIPHER);
pwk_cipher->tlv.len = cpu_to_le16(
sizeof(struct host_cmd_tlv_pwk_cipher) -
sizeof(struct host_cmd_tlv));
pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
pwk_cipher->cipher =
bss_cfg->wpa_cfg.pairwise_cipher_wpa;
cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
}
if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 &
VALID_CIPHER_BITMAP) {
pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
pwk_cipher->tlv.len = cpu_to_le16(
sizeof(struct host_cmd_tlv_pwk_cipher) -
sizeof(struct host_cmd_tlv));
pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
pwk_cipher->cipher =
bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
}
if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
gwk_cipher->tlv.len = cpu_to_le16(
sizeof(struct host_cmd_tlv_gwk_cipher) -
sizeof(struct host_cmd_tlv));
gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
}
if (bss_cfg->wpa_cfg.length) {
passphrase = (struct host_cmd_tlv_passphrase *)tlv;
passphrase->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
passphrase->tlv.len =
cpu_to_le16(bss_cfg->wpa_cfg.length);
memcpy(passphrase->passphrase,
bss_cfg->wpa_cfg.passphrase,
bss_cfg->wpa_cfg.length);
cmd_size += sizeof(struct host_cmd_tlv) +
bss_cfg->wpa_cfg.length;
tlv += sizeof(struct host_cmd_tlv) +
bss_cfg->wpa_cfg.length;
}
}
if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
(bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
auth_type = (struct host_cmd_tlv_auth_type *)tlv;
auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
auth_type->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
sizeof(struct host_cmd_tlv));
auth_type->auth_type = (u8)bss_cfg->auth_mode;
cmd_size += sizeof(struct host_cmd_tlv_auth_type);
tlv += sizeof(struct host_cmd_tlv_auth_type);
}
if (bss_cfg->protocol) {
encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
encrypt_protocol->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
encrypt_protocol->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
- sizeof(struct host_cmd_tlv));
encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
}
*param_size = cmd_size;
return 0;
}
/* This function parses custom IEs from IE list and prepares command buffer */
static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size)
{
struct mwifiex_ie_list *ap_ie = cmd_buf;
struct host_cmd_tlv *tlv_ie = (struct host_cmd_tlv *)tlv;
if (!ap_ie || !ap_ie->len || !ap_ie->ie_list)
return -1;
*ie_size += le16_to_cpu(ap_ie->len) + sizeof(struct host_cmd_tlv);
tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
tlv_ie->len = ap_ie->len;
tlv += sizeof(struct host_cmd_tlv);
memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len));
return 0;
}
/* Parse AP config structure and prepare TLV based command structure
* to be sent to FW for uAP configuration
*/
static int
mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action,
u32 type, void *cmd_buf)
{
u8 *tlv;
u16 cmd_size, param_size, ie_size;
struct host_cmd_ds_sys_config *sys_cfg;
cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG);
cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN);
sys_cfg = (struct host_cmd_ds_sys_config *)&cmd->params.uap_sys_config;
sys_cfg->action = cpu_to_le16(cmd_action);
tlv = sys_cfg->tlv;
switch (type) {
case UAP_BSS_PARAMS_I:
param_size = cmd_size;
if (mwifiex_uap_bss_param_prepare(tlv, cmd_buf, &param_size))
return -1;
cmd->size = cpu_to_le16(param_size);
break;
case UAP_CUSTOM_IE_I:
ie_size = cmd_size;
if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size))
return -1;
cmd->size = cpu_to_le16(ie_size);
break;
default:
return -1;
}
return 0;
}
/* This function prepares the AP specific commands before sending them
* to the firmware.
* This is a generic function which calls specific command preparation
* routines based upon the command number.
*/
int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
u16 cmd_action, u32 type,
void *data_buf, void *cmd_buf)
{
struct host_cmd_ds_command *cmd = cmd_buf;
switch (cmd_no) {
case HostCmd_CMD_UAP_SYS_CONFIG:
if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, type, data_buf))
return -1;
break;
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
cmd->command = cpu_to_le16(cmd_no);
cmd->size = cpu_to_le16(S_DS_GEN);
break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd %#x\n", cmd_no);
return -1;
}
return 0;
}
/* This function sets the RF channel for AP.
*
* This function populates channel information in AP config structure
* and sends command to configure channel information in AP.
*/
int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel)
{
struct mwifiex_uap_bss_param *bss_cfg;
struct wiphy *wiphy = priv->wdev->wiphy;
bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
if (!bss_cfg)
return -ENOMEM;
bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
bss_cfg->channel = channel;
if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
HostCmd_ACT_GEN_SET,
UAP_BSS_PARAMS_I, bss_cfg)) {
wiphy_err(wiphy, "Failed to set the uAP channel\n");
kfree(bss_cfg);
return -1;
}
kfree(bss_cfg);
return 0;
}

View file

@ -885,6 +885,10 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
tid_ptr = &(priv_tmp)->wmm.
tid_tbl_ptr[tos_to_tid[i]];
/* For non-STA ra_list_curr may be NULL */
if (!tid_ptr->ra_list_curr)
continue;
spin_lock_irqsave(&tid_ptr->tid_tbl_lock,
flags);
is_list_empty =

View file

@ -505,9 +505,6 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params);
@ -549,7 +546,6 @@ static const struct cfg80211_ops rndis_config_ops = {
.disconnect = rndis_disconnect,
.join_ibss = rndis_join_ibss,
.leave_ibss = rndis_leave_ibss,
.set_channel = rndis_set_channel,
.add_key = rndis_add_key,
.del_key = rndis_del_key,
.set_default_key = rndis_set_default_key,
@ -2398,16 +2394,6 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return deauthenticate(usbdev);
}
static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
struct ieee80211_channel *chan, enum nl80211_channel_type channel_type)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
return set_channel(usbdev,
ieee80211_frequency_to_channel(chan->center_freq));
}
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)

View file

@ -1192,6 +1192,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
{ PCI_DEVICE(0x1814, 0x5390) },
{ PCI_DEVICE(0x1814, 0x5392) },
{ PCI_DEVICE(0x1814, 0x539a) },
{ PCI_DEVICE(0x1814, 0x539b) },
{ PCI_DEVICE(0x1814, 0x539f) },
#endif
{ 0, }

View file

@ -1,5 +1,6 @@
config WL12XX
tristate "TI wl12xx support"
depends on MAC80211
select WLCORE
---help---
This module adds support for wireless adapters based on TI wl1271,

View file

@ -1,6 +1,6 @@
config WLCORE
tristate "TI wlcore support"
depends on WL_TI && GENERIC_HARDIRQS
depends on WL_TI && GENERIC_HARDIRQS && MAC80211
depends on INET
select FW_LOADER
---help---

View file

@ -1714,3 +1714,83 @@ out:
return ret;
}
/* Set the global behaviour of RX filters - On/Off + default action */
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
enum rx_filter_action action)
{
struct acx_default_rx_filter *acx;
int ret;
wl1271_debug(DEBUG_ACX, "acx default rx filter en: %d act: %d",
enable, action);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx)
return -ENOMEM;
acx->enable = enable;
acx->default_action = action;
ret = wl1271_cmd_configure(wl, ACX_ENABLE_RX_DATA_FILTER, acx,
sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx default rx filter enable failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
/* Configure or disable a specific RX filter pattern */
int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable,
struct wl12xx_rx_filter *filter)
{
struct acx_rx_filter_cfg *acx;
int fields_size = 0;
int acx_size;
int ret;
WARN_ON(enable && !filter);
WARN_ON(index >= WL1271_MAX_RX_FILTERS);
wl1271_debug(DEBUG_ACX,
"acx set rx filter idx: %d enable: %d filter: %p",
index, enable, filter);
if (enable) {
fields_size = wl1271_rx_filter_get_fields_size(filter);
wl1271_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d",
filter->action, filter->num_fields, fields_size);
}
acx_size = ALIGN(sizeof(*acx) + fields_size, 4);
acx = kzalloc(acx_size, GFP_KERNEL);
if (!acx)
return -ENOMEM;
acx->enable = enable;
acx->index = index;
if (enable) {
acx->num_fields = filter->num_fields;
acx->action = filter->action;
wl1271_rx_filter_flatten_fields(filter, acx->fields);
}
wl1271_dump(DEBUG_ACX, "RX_FILTER: ", acx, acx_size);
ret = wl1271_cmd_configure(wl, ACX_SET_RX_DATA_FILTER, acx, acx_size);
if (ret < 0) {
wl1271_warning("setting rx filter failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}

View file

@ -1147,6 +1147,32 @@ struct wl12xx_acx_config_hangover {
u8 padding[2];
} __packed;
struct acx_default_rx_filter {
struct acx_header header;
u8 enable;
/* action of type FILTER_XXX */
u8 default_action;
u8 pad[2];
} __packed;
struct acx_rx_filter_cfg {
struct acx_header header;
u8 enable;
/* 0 - WL1271_MAX_RX_FILTERS-1 */
u8 index;
u8 action;
u8 num_fields;
u8 fields[0];
} __packed;
enum {
ACX_WAKE_UP_CONDITIONS = 0x0000,
ACX_MEM_CFG = 0x0001,
@ -1304,5 +1330,9 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl);
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
int wl12xx_acx_config_hangover(struct wl1271 *wl);
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
enum rx_filter_action action);
int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable,
struct wl12xx_rx_filter *filter);
#endif /* __WL1271_ACX_H__ */

View file

@ -72,7 +72,7 @@ static int wlcore_boot_fw_version(struct wl1271 *wl)
struct wl1271_static_data *static_data;
int ret;
static_data = kmalloc(sizeof(*static_data), GFP_DMA);
static_data = kmalloc(sizeof(*static_data), GFP_KERNEL | GFP_DMA);
if (!static_data) {
wl1271_error("Couldn't allocate memory for static data!");
return -ENOMEM;
@ -413,6 +413,7 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
/* unmask required mbox events */
wl->event_mask = BSS_LOSE_EVENT_ID |
REGAINED_BSS_EVENT_ID |
SCAN_COMPLETE_EVENT_ID |
ROLE_STOP_COMPLETE_EVENT_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |

View file

@ -123,7 +123,9 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
unsigned long timeout;
int ret = 0;
events_vector = kmalloc(sizeof(*events_vector), GFP_DMA);
events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA);
if (!events_vector)
return -ENOMEM;
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
@ -1034,7 +1036,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX);
tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl));
memset(tmpl, 0, sizeof(tmpl));
memset(tmpl, 0, sizeof(*tmpl));
/* llc layer */
memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header));
@ -1083,7 +1085,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
/* mac80211 header */
hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr));
memset(hdr, 0, sizeof(hdr));
memset(hdr, 0, sizeof(*hdr));
fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS;
if (wlvif->sta.qos)
fc |= IEEE80211_STYPE_QOS_DATA;

View file

@ -103,7 +103,6 @@ static int wl1271_event_process(struct wl1271 *wl)
struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
u32 vector;
bool beacon_loss = false;
bool disconnect_sta = false;
unsigned long sta_bitmap = 0;
@ -141,20 +140,23 @@ static int wl1271_event_process(struct wl1271 *wl)
mbox->soft_gemini_sense_info);
/*
* The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
* filtering) is enabled. Without PSM, the stack will receive all
* beacons and can detect beacon loss by itself.
*
* As there's possibility that the driver disables PSM before receiving
* BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
*
* We are HW_MONITOR device. On beacon loss - queue
* connection loss work. Cancel it on REGAINED event.
*/
if (vector & BSS_LOSE_EVENT_ID) {
/* TODO: check for multi-role */
int delay = wl->conf.conn.synch_fail_thold *
wl->conf.conn.bss_lose_timeout;
wl1271_info("Beacon loss detected.");
cancel_delayed_work_sync(&wl->connection_loss_work);
ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
msecs_to_jiffies(delay));
}
/* indicate to the stack, that beacons have been lost */
beacon_loss = true;
if (vector & REGAINED_BSS_EVENT_ID) {
/* TODO: check for multi-role */
wl1271_info("Beacon regained.");
cancel_delayed_work_sync(&wl->connection_loss_work);
}
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
@ -257,13 +259,6 @@ static int wl1271_event_process(struct wl1271 *wl)
rcu_read_unlock();
}
}
if (beacon_loss)
wl12xx_for_each_wlvif_sta(wl, wlvif) {
vif = wl12xx_wlvif_to_vif(wlvif);
ieee80211_connection_loss(vif);
}
return 0;
}

View file

@ -1120,6 +1120,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
cancel_work_sync(&wl->recovery_work);
cancel_delayed_work_sync(&wl->elp_work);
cancel_delayed_work_sync(&wl->tx_watchdog_work);
cancel_delayed_work_sync(&wl->connection_loss_work);
mutex_lock(&wl->mutex);
wl1271_power_off(wl);
@ -1261,8 +1262,270 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
#ifdef CONFIG_PM
static int
wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p)
{
int num_fields = 0, in_field = 0, fields_size = 0;
int i, pattern_len = 0;
if (!p->mask) {
wl1271_warning("No mask in WoWLAN pattern");
return -EINVAL;
}
/*
* The pattern is broken up into segments of bytes at different offsets
* that need to be checked by the FW filter. Each segment is called
* a field in the FW API. We verify that the total number of fields
* required for this pattern won't exceed FW limits (8)
* as well as the total fields buffer won't exceed the FW limit.
* Note that if there's a pattern which crosses Ethernet/IP header
* boundary a new field is required.
*/
for (i = 0; i < p->pattern_len; i++) {
if (test_bit(i, (unsigned long *)p->mask)) {
if (!in_field) {
in_field = 1;
pattern_len = 1;
} else {
if (i == WL1271_RX_FILTER_ETH_HEADER_SIZE) {
num_fields++;
fields_size += pattern_len +
RX_FILTER_FIELD_OVERHEAD;
pattern_len = 1;
} else
pattern_len++;
}
} else {
if (in_field) {
in_field = 0;
fields_size += pattern_len +
RX_FILTER_FIELD_OVERHEAD;
num_fields++;
}
}
}
if (in_field) {
fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD;
num_fields++;
}
if (num_fields > WL1271_RX_FILTER_MAX_FIELDS) {
wl1271_warning("RX Filter too complex. Too many segments");
return -EINVAL;
}
if (fields_size > WL1271_RX_FILTER_MAX_FIELDS_SIZE) {
wl1271_warning("RX filter pattern is too big");
return -E2BIG;
}
return 0;
}
struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void)
{
return kzalloc(sizeof(struct wl12xx_rx_filter), GFP_KERNEL);
}
void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter)
{
int i;
if (filter == NULL)
return;
for (i = 0; i < filter->num_fields; i++)
kfree(filter->fields[i].pattern);
kfree(filter);
}
int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
u16 offset, u8 flags,
u8 *pattern, u8 len)
{
struct wl12xx_rx_filter_field *field;
if (filter->num_fields == WL1271_RX_FILTER_MAX_FIELDS) {
wl1271_warning("Max fields per RX filter. can't alloc another");
return -EINVAL;
}
field = &filter->fields[filter->num_fields];
field->pattern = kzalloc(len, GFP_KERNEL);
if (!field->pattern) {
wl1271_warning("Failed to allocate RX filter pattern");
return -ENOMEM;
}
filter->num_fields++;
field->offset = cpu_to_le16(offset);
field->flags = flags;
field->len = len;
memcpy(field->pattern, pattern, len);
return 0;
}
int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter)
{
int i, fields_size = 0;
for (i = 0; i < filter->num_fields; i++)
fields_size += filter->fields[i].len +
sizeof(struct wl12xx_rx_filter_field) -
sizeof(u8 *);
return fields_size;
}
void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
u8 *buf)
{
int i;
struct wl12xx_rx_filter_field *field;
for (i = 0; i < filter->num_fields; i++) {
field = (struct wl12xx_rx_filter_field *)buf;
field->offset = filter->fields[i].offset;
field->flags = filter->fields[i].flags;
field->len = filter->fields[i].len;
memcpy(&field->pattern, filter->fields[i].pattern, field->len);
buf += sizeof(struct wl12xx_rx_filter_field) -
sizeof(u8 *) + field->len;
}
}
/*
* Allocates an RX filter returned through f
* which needs to be freed using rx_filter_free()
*/
static int wl1271_convert_wowlan_pattern_to_rx_filter(
struct cfg80211_wowlan_trig_pkt_pattern *p,
struct wl12xx_rx_filter **f)
{
int i, j, ret = 0;
struct wl12xx_rx_filter *filter;
u16 offset;
u8 flags, len;
filter = wl1271_rx_filter_alloc();
if (!filter) {
wl1271_warning("Failed to alloc rx filter");
ret = -ENOMEM;
goto err;
}
i = 0;
while (i < p->pattern_len) {
if (!test_bit(i, (unsigned long *)p->mask)) {
i++;
continue;
}
for (j = i; j < p->pattern_len; j++) {
if (!test_bit(j, (unsigned long *)p->mask))
break;
if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE &&
j >= WL1271_RX_FILTER_ETH_HEADER_SIZE)
break;
}
if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE) {
offset = i;
flags = WL1271_RX_FILTER_FLAG_ETHERNET_HEADER;
} else {
offset = i - WL1271_RX_FILTER_ETH_HEADER_SIZE;
flags = WL1271_RX_FILTER_FLAG_IP_HEADER;
}
len = j - i;
ret = wl1271_rx_filter_alloc_field(filter,
offset,
flags,
&p->pattern[i], len);
if (ret)
goto err;
i = j;
}
filter->action = FILTER_SIGNAL;
*f = filter;
return 0;
err:
wl1271_rx_filter_free(filter);
*f = NULL;
return ret;
}
static int wl1271_configure_wowlan(struct wl1271 *wl,
struct cfg80211_wowlan *wow)
{
int i, ret;
if (!wow || wow->any || !wow->n_patterns) {
wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
wl1271_rx_filter_clear_all(wl);
return 0;
}
if (WARN_ON(wow->n_patterns > WL1271_MAX_RX_FILTERS))
return -EINVAL;
/* Validate all incoming patterns before clearing current FW state */
for (i = 0; i < wow->n_patterns; i++) {
ret = wl1271_validate_wowlan_pattern(&wow->patterns[i]);
if (ret) {
wl1271_warning("Bad wowlan pattern %d", i);
return ret;
}
}
wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
wl1271_rx_filter_clear_all(wl);
/* Translate WoWLAN patterns into filters */
for (i = 0; i < wow->n_patterns; i++) {
struct cfg80211_wowlan_trig_pkt_pattern *p;
struct wl12xx_rx_filter *filter = NULL;
p = &wow->patterns[i];
ret = wl1271_convert_wowlan_pattern_to_rx_filter(p, &filter);
if (ret) {
wl1271_warning("Failed to create an RX filter from "
"wowlan pattern %d", i);
goto out;
}
ret = wl1271_rx_filter_enable(wl, i, 1, filter);
wl1271_rx_filter_free(filter);
if (ret)
goto out;
}
ret = wl1271_acx_default_rx_filter_enable(wl, 1, FILTER_DROP);
out:
return ret;
}
static int wl1271_configure_suspend_sta(struct wl1271 *wl,
struct wl12xx_vif *wlvif)
struct wl12xx_vif *wlvif,
struct cfg80211_wowlan *wow)
{
int ret = 0;
@ -1273,6 +1536,7 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0)
goto out;
wl1271_configure_wowlan(wl, wow);
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.suspend_wake_up_event,
wl->conf.conn.suspend_listen_interval);
@ -1308,10 +1572,11 @@ out:
}
static int wl1271_configure_suspend(struct wl1271 *wl,
struct wl12xx_vif *wlvif)
struct wl12xx_vif *wlvif,
struct cfg80211_wowlan *wow)
{
if (wlvif->bss_type == BSS_TYPE_STA_BSS)
return wl1271_configure_suspend_sta(wl, wlvif);
return wl1271_configure_suspend_sta(wl, wlvif, wow);
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
return wl1271_configure_suspend_ap(wl, wlvif);
return 0;
@ -1332,6 +1597,8 @@ static void wl1271_configure_resume(struct wl1271 *wl,
return;
if (is_sta) {
wl1271_configure_wowlan(wl, NULL);
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.wake_up_event,
wl->conf.conn.listen_interval);
@ -1355,15 +1622,16 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
WARN_ON(!wow || !wow->any);
WARN_ON(!wow);
wl1271_tx_flush(wl);
mutex_lock(&wl->mutex);
wl->wow_enabled = true;
wl12xx_for_each_wlvif(wl, wlvif) {
ret = wl1271_configure_suspend(wl, wlvif);
ret = wl1271_configure_suspend(wl, wlvif, wow);
if (ret < 0) {
mutex_unlock(&wl->mutex);
wl1271_warning("couldn't prepare device to suspend");
return ret;
}
@ -1487,6 +1755,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
cancel_work_sync(&wl->tx_work);
cancel_delayed_work_sync(&wl->elp_work);
cancel_delayed_work_sync(&wl->tx_watchdog_work);
cancel_delayed_work_sync(&wl->connection_loss_work);
/* let's notify MAC80211 about the remaining pending TX frames */
wl12xx_tx_reset(wl, true);
@ -3439,6 +3708,9 @@ sta_not_found:
do_join = true;
set_assoc = true;
/* Cancel connection_loss_work */
cancel_delayed_work_sync(&wl->connection_loss_work);
/*
* use basic rates from AP, and determine lowest rate
* to use with control frames.
@ -4549,6 +4821,34 @@ static struct bin_attribute fwlog_attr = {
.read = wl1271_sysfs_read_fwlog,
};
static void wl1271_connection_loss_work(struct work_struct *work)
{
struct delayed_work *dwork;
struct wl1271 *wl;
struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, connection_loss_work);
wl1271_info("Connection loss work.");
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
/* Call mac80211 connection loss */
wl12xx_for_each_wlvif_sta(wl, wlvif) {
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
goto out;
vif = wl12xx_wlvif_to_vif(wlvif);
ieee80211_connection_loss(vif);
}
out:
mutex_unlock(&wl->mutex);
}
static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
u32 oui, u32 nic, int n)
{
@ -4804,6 +5104,8 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
INIT_DELAYED_WORK(&wl->connection_loss_work,
wl1271_connection_loss_work);
wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
if (!wl->freezable_wq) {
@ -4861,7 +5163,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
goto err_dummy_packet;
}
wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_DMA);
wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_KERNEL | GFP_DMA);
if (!wl->mbox) {
ret = -ENOMEM;
goto err_fwlog;
@ -5003,9 +5305,14 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
if (!ret) {
wl->irq_wake_enabled = true;
device_init_wakeup(wl->dev, 1);
if (pdata->pwr_in_suspend)
if (pdata->pwr_in_suspend) {
wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
wl->hw->wiphy->wowlan.n_patterns =
WL1271_MAX_RX_FILTERS;
wl->hw->wiphy->wowlan.pattern_min_len = 1;
wl->hw->wiphy->wowlan.pattern_max_len =
WL1271_RX_FILTER_MAX_PATTERN_SIZE;
}
}
disable_irq(wl->irq);

View file

@ -278,3 +278,39 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
wl12xx_rearm_rx_streaming(wl, active_hlids);
}
int wl1271_rx_filter_enable(struct wl1271 *wl,
int index, bool enable,
struct wl12xx_rx_filter *filter)
{
int ret;
if (wl->rx_filter_enabled[index] == enable) {
wl1271_warning("Request to enable an already "
"enabled rx filter %d", index);
return 0;
}
ret = wl1271_acx_set_rx_filter(wl, index, enable, filter);
if (ret) {
wl1271_error("Failed to %s rx data filter %d (err=%d)",
enable ? "enable" : "disable", index, ret);
return ret;
}
wl->rx_filter_enabled[index] = enable;
return 0;
}
void wl1271_rx_filter_clear_all(struct wl1271 *wl)
{
int i;
for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) {
if (!wl->rx_filter_enabled[i])
continue;
wl1271_rx_filter_enable(wl, i, 0, NULL);
}
}

View file

@ -138,5 +138,9 @@ struct wl1271_rx_descriptor {
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
int wl1271_rx_filter_enable(struct wl1271 *wl,
int index, bool enable,
struct wl12xx_rx_filter *filter);
void wl1271_rx_filter_clear_all(struct wl1271 *wl);
#endif

View file

@ -279,6 +279,39 @@ struct wl1271_link {
u8 ba_bitmap;
};
#define WL1271_MAX_RX_FILTERS 5
#define WL1271_RX_FILTER_MAX_FIELDS 8
#define WL1271_RX_FILTER_ETH_HEADER_SIZE 14
#define WL1271_RX_FILTER_MAX_FIELDS_SIZE 95
#define RX_FILTER_FIELD_OVERHEAD \
(sizeof(struct wl12xx_rx_filter_field) - sizeof(u8 *))
#define WL1271_RX_FILTER_MAX_PATTERN_SIZE \
(WL1271_RX_FILTER_MAX_FIELDS_SIZE - RX_FILTER_FIELD_OVERHEAD)
#define WL1271_RX_FILTER_FLAG_MASK BIT(0)
#define WL1271_RX_FILTER_FLAG_IP_HEADER 0
#define WL1271_RX_FILTER_FLAG_ETHERNET_HEADER BIT(1)
enum rx_filter_action {
FILTER_DROP = 0,
FILTER_SIGNAL = 1,
FILTER_FW_HANDLE = 2
};
struct wl12xx_rx_filter_field {
__le16 offset;
u8 len;
u8 flags;
u8 *pattern;
} __packed;
struct wl12xx_rx_filter {
u8 action;
int num_fields;
struct wl12xx_rx_filter_field fields[WL1271_RX_FILTER_MAX_FIELDS];
};
struct wl1271_station {
u8 hlid;
};
@ -439,6 +472,14 @@ int wl1271_plt_stop(struct wl1271 *wl);
int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif);
void wl12xx_queue_recovery_work(struct wl1271 *wl);
size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
u16 offset, u8 flags,
u8 *pattern, u8 len);
void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter);
struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void);
int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter);
void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
u8 *buf);
#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */

View file

@ -243,6 +243,9 @@ struct wl1271 {
struct wl1271_scan scan;
struct delayed_work scan_complete_work;
/* Connection loss work */
struct delayed_work connection_loss_work;
bool sched_scanning;
/* The current band */
@ -349,6 +352,9 @@ struct wl1271 {
/* size of the private FW status data */
size_t fw_status_priv_len;
/* RX Data filter rule state - enabled/disabled */
bool rx_filter_enabled[WL1271_MAX_RX_FILTERS];
};
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);