提交 40d1ae57 编写于 作者: D David S. Miller

Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next

John W. Linville says:

====================
This probably is the last big pull request for wireless bits
for 3.9.  Of course, I'm sure there will be a few stragglers here
and there...surely a few bug fixes as well... :-) (In fact, I see
that Johannes has already queued-up a few more for me while I was
preparing this...)

Included are a number of pulls...

For mac80211-next, Johannes says:

"The biggest change I have is undoubtedly Marco's mesh powersave
implementation. Beyond that, I have a patch from Emmanuel to modify the
DTIM period API in mac80211, scan improvements and a removal of some
previous workaround code from Stanislaw, dynamic short slot time from
Thomas and 64-bit station byte counters from Vladimir. I also made a
number of changes myself, some related to WoWLAN, some auth/deauth
improvements and most of them BSS list cleanups."

"This time, I have relatively large number of fixes in various areas of
the code (a memory leak in regulatory, an RX race in mac80211, the new
radar checking caused a P2P device problem, some mesh issues with
stations, an older bug in tracing and for kernel-doc) as well as a
number of small new features. The biggest (in the diffstat) is my work
on hidden SSID tracking."

"Please pull to get
 * radar detection work from Simon
 * mesh improvements from Thomas
 * a connection monitoring/powersave fix from Wojciech
 * TDLS-related station management work from Jouni
 * VLAN crypto fixes from Michael Braun
 * CCK support in minstrel_ht from Felix
 * an SMPS (not SMSP, oops) related improvement in mac80211 (Emmanuel)
 * some WoWLAN work from Amitkumar Karwar: pattern match offset and a
   documentation fix
 * some WoWLAN work from myself (TCP connection wakeup feature API)
 * and a lot of VHT (and some HT) work (also from myself)

And a number of more random cleanups/fixes. I merged mac80211/master to
avoid a merge problem there."

And regarding iwlwifi-next, Johannes says:

"We continue work on our new driver, but I also have a WoWLAN and AP mode
improvement for the previous driver and a change to use threaded
interrupts to prepare us for working with non-PCIe devices."

Regarding wl12xx, Luca says:

"A few more patches intended for 3.9.  Mostly some clean-ups I've been
doing to make it easier to support device-tree.  Also including one bug
fix for wl12xx where the rates we advertise were wrong and an update in
the wlconf structure to support newer firmwares."

For the nfc-next bits, Samuel says:

"This is the second NFC pull request for 3.9.

We have:

- A few pn533 fixes on top of Waldemar refactorization of the driver, one of
  them fixes target mode.

- A new driver for Inside Secure microread chipset. It supports two
  physical layers: i2c and MEI. The MEI one depends on a patchset that's
  been sent to Greg Kroah-Hartman for inclusion into the 3.9 kernel [1]. The
  dependency is a KConfig one which means this code is not buildable as long
  as the MEI API is not usptream."

"This 3rd NFC pull request for 3.9 contains a fix for the microread MEI
physical layer support, as the MEI bus API changed.

From the MEI code, we now pass the MEI id back to the driver probe routine,
and we also pass a name and a MEI id table through the mei_bus_driver
structure. A few renames as well like e.g. mei_bus_driver to mei_driver or
mei_bus_client to mei_device in order to be closer to the driver model
practices."

For the ath6kl bits, Kalle says:

"There's not anything special here, most of the patches are just code
cleanup. The only functional changes are using the beacon interval from user
space and fixing a crash which happens when inserting and removing the
module in a loop."

Also, I pulled the wireless tree in order to resolve some pending
merge issues.  On top of that, there is a bunch of work on brcmfmac
that leads up to P2P support.  Also, mwifiex, rtlwifi, and a variety
of other drivers see some basic cleanups and minor enhancements.

Please let me know if there are problems!
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -309,7 +309,7 @@ static struct omap2_hsmmc_info mmc[] = { ...@@ -309,7 +309,7 @@ static struct omap2_hsmmc_info mmc[] = {
.gpio_wp = 63, .gpio_wp = 63,
.deferred = true, .deferred = true,
}, },
#ifdef CONFIG_WL12XX_PLATFORM_DATA #ifdef CONFIG_WILINK_PLATFORM_DATA
{ {
.name = "wl1271", .name = "wl1271",
.mmc = 2, .mmc = 2,
...@@ -450,7 +450,7 @@ static struct regulator_init_data omap3evm_vio = { ...@@ -450,7 +450,7 @@ static struct regulator_init_data omap3evm_vio = {
.consumer_supplies = omap3evm_vio_supply, .consumer_supplies = omap3evm_vio_supply,
}; };
#ifdef CONFIG_WL12XX_PLATFORM_DATA #ifdef CONFIG_WILINK_PLATFORM_DATA
#define OMAP3EVM_WLAN_PMENA_GPIO (150) #define OMAP3EVM_WLAN_PMENA_GPIO (150)
#define OMAP3EVM_WLAN_IRQ_GPIO (149) #define OMAP3EVM_WLAN_IRQ_GPIO (149)
...@@ -563,7 +563,7 @@ static struct omap_board_mux omap35x_board_mux[] __initdata = { ...@@ -563,7 +563,7 @@ static struct omap_board_mux omap35x_board_mux[] __initdata = {
OMAP_PIN_OFF_NONE), OMAP_PIN_OFF_NONE),
OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP |
OMAP_PIN_OFF_NONE), OMAP_PIN_OFF_NONE),
#ifdef CONFIG_WL12XX_PLATFORM_DATA #ifdef CONFIG_WILINK_PLATFORM_DATA
/* WLAN IRQ - GPIO 149 */ /* WLAN IRQ - GPIO 149 */
OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
...@@ -601,7 +601,7 @@ static struct omap_board_mux omap36x_board_mux[] __initdata = { ...@@ -601,7 +601,7 @@ static struct omap_board_mux omap36x_board_mux[] __initdata = {
OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
#ifdef CONFIG_WL12XX_PLATFORM_DATA #ifdef CONFIG_WILINK_PLATFORM_DATA
/* WLAN IRQ - GPIO 149 */ /* WLAN IRQ - GPIO 149 */
OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
...@@ -637,7 +637,7 @@ static struct gpio omap3_evm_ehci_gpios[] __initdata = { ...@@ -637,7 +637,7 @@ static struct gpio omap3_evm_ehci_gpios[] __initdata = {
static void __init omap3_evm_wl12xx_init(void) static void __init omap3_evm_wl12xx_init(void)
{ {
#ifdef CONFIG_WL12XX_PLATFORM_DATA #ifdef CONFIG_WILINK_PLATFORM_DATA
int ret; int ret;
/* WL12xx WLAN Init */ /* WL12xx WLAN Init */
......
...@@ -1613,6 +1613,10 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah) ...@@ -1613,6 +1613,10 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
ah->ah_cal_mask |= AR5K_CALIBRATION_NF; ah->ah_cal_mask |= AR5K_CALIBRATION_NF;
ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel); ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
if (WARN_ON(ee_mode < 0)) {
ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF;
return;
}
/* completed NF calibration, test threshold */ /* completed NF calibration, test threshold */
nf = ath5k_hw_read_measured_noise_floor(ah); nf = ath5k_hw_read_measured_noise_floor(ah);
......
...@@ -985,6 +985,8 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, ...@@ -985,6 +985,8 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
return; return;
ee_mode = ath5k_eeprom_mode_from_channel(channel); ee_mode = ath5k_eeprom_mode_from_channel(channel);
if (WARN_ON(ee_mode < 0))
return;
/* Adjust power delta for channel 14 */ /* Adjust power delta for channel 14 */
if (channel->center_freq == 2484) if (channel->center_freq == 2484)
......
...@@ -427,6 +427,30 @@ static bool ath6kl_is_tx_pending(struct ath6kl *ar) ...@@ -427,6 +427,30 @@ static bool ath6kl_is_tx_pending(struct ath6kl *ar)
return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
} }
static void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif,
bool enable)
{
int err;
if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
return;
if (vif->nw_type != INFRA_NETWORK)
return;
if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
vif->ar->fw_capabilities))
return;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
enable ? "enable" : "disable");
err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
vif->fw_vif_idx, enable);
if (err)
ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
enable ? "enable" : "disable", err);
}
static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme) struct cfg80211_connect_params *sme)
...@@ -616,13 +640,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -616,13 +640,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
vif->req_bssid, vif->ch_hint, vif->req_bssid, vif->ch_hint,
ar->connect_ctrl_flags, nw_subtype); ar->connect_ctrl_flags, nw_subtype);
/* disable background scan if period is 0 */ if (sme->bg_scan_period == 0) {
if (sme->bg_scan_period == 0) /* disable background scan if period is 0 */
sme->bg_scan_period = 0xffff; sme->bg_scan_period = 0xffff;
} else if (sme->bg_scan_period == -1) {
/* configure default value if not specified */ /* configure default value if not specified */
if (sme->bg_scan_period == -1)
sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
}
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0,
sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
...@@ -767,7 +791,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, ...@@ -767,7 +791,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
nw_type & ADHOC_CREATOR ? "creator" : "joiner"); nw_type & ADHOC_CREATOR ? "creator" : "joiner");
cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
cfg80211_put_bss(bss); cfg80211_put_bss(ar->wiphy, bss);
return; return;
} }
...@@ -778,7 +802,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, ...@@ -778,7 +802,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
assoc_req_ie, assoc_req_len, assoc_req_ie, assoc_req_len,
assoc_resp_ie, assoc_resp_len, assoc_resp_ie, assoc_resp_len,
WLAN_STATUS_SUCCESS, GFP_KERNEL); WLAN_STATUS_SUCCESS, GFP_KERNEL);
cfg80211_put_bss(bss); cfg80211_put_bss(ar->wiphy, bss);
} else if (vif->sme_state == SME_CONNECTED) { } else if (vif->sme_state == SME_CONNECTED) {
/* inform roam event to cfg80211 */ /* inform roam event to cfg80211 */
cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len, cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
...@@ -1454,10 +1478,10 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, ...@@ -1454,10 +1478,10 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
return -EIO; return -EIO;
if (pmgmt) { if (pmgmt) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
mode.pwr_mode = REC_POWER; mode.pwr_mode = REC_POWER;
} else { } else {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
mode.pwr_mode = MAX_PERF_POWER; mode.pwr_mode = MAX_PERF_POWER;
} }
...@@ -1509,7 +1533,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, ...@@ -1509,7 +1533,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
list_del(&vif->list); list_del(&vif->list);
spin_unlock_bh(&ar->list_lock); spin_unlock_bh(&ar->list_lock);
ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
ath6kl_cfg80211_vif_cleanup(vif); ath6kl_cfg80211_vif_cleanup(vif);
...@@ -1559,17 +1583,13 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, ...@@ -1559,17 +1583,13 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
set_iface_type: set_iface_type:
switch (type) { switch (type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
vif->next_mode = INFRA_NETWORK; vif->next_mode = INFRA_NETWORK;
break; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
vif->next_mode = ADHOC_NETWORK; vif->next_mode = ADHOC_NETWORK;
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
vif->next_mode = AP_NETWORK;
break;
case NL80211_IFTYPE_P2P_CLIENT:
vif->next_mode = INFRA_NETWORK;
break;
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
vif->next_mode = AP_NETWORK; vif->next_mode = AP_NETWORK;
break; break;
...@@ -1778,14 +1798,14 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, ...@@ -1778,14 +1798,14 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
if (vif->target_stats.rx_byte) { if (vif->target_stats.rx_byte) {
sinfo->rx_bytes = vif->target_stats.rx_byte; sinfo->rx_bytes = vif->target_stats.rx_byte;
sinfo->filled |= STATION_INFO_RX_BYTES; sinfo->filled |= STATION_INFO_RX_BYTES64;
sinfo->rx_packets = vif->target_stats.rx_pkt; sinfo->rx_packets = vif->target_stats.rx_pkt;
sinfo->filled |= STATION_INFO_RX_PACKETS; sinfo->filled |= STATION_INFO_RX_PACKETS;
} }
if (vif->target_stats.tx_byte) { if (vif->target_stats.tx_byte) {
sinfo->tx_bytes = vif->target_stats.tx_byte; sinfo->tx_bytes = vif->target_stats.tx_byte;
sinfo->filled |= STATION_INFO_TX_BYTES; sinfo->filled |= STATION_INFO_TX_BYTES64;
sinfo->tx_packets = vif->target_stats.tx_pkt; sinfo->tx_packets = vif->target_stats.tx_pkt;
sinfo->filled |= STATION_INFO_TX_PACKETS; sinfo->filled |= STATION_INFO_TX_PACKETS;
} }
...@@ -2673,30 +2693,6 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, ...@@ -2673,30 +2693,6 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
return 0; return 0;
} }
void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable)
{
int err;
if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
return;
if (vif->nw_type != INFRA_NETWORK)
return;
if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
vif->ar->fw_capabilities))
return;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
enable ? "enable" : "disable");
err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
vif->fw_vif_idx, enable);
if (err)
ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
enable ? "enable" : "disable", err);
}
static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
u8 *rsn_capab) u8 *rsn_capab)
{ {
...@@ -2776,9 +2772,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -2776,9 +2772,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
ar->ap_mode_bkey.valid = false; ar->ap_mode_bkey.valid = false;
/* TODO: ret = ath6kl_wmi_ap_set_beacon_intvl_cmd(ar->wmi, vif->fw_vif_idx,
* info->interval info->beacon_interval);
*/
if (ret)
ath6kl_warn("Failed to set beacon interval: %d\n", ret);
ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx,
info->dtim_period); info->dtim_period);
...@@ -3557,6 +3555,37 @@ static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif) ...@@ -3557,6 +3555,37 @@ static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
return 0; return 0;
} }
void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready)
{
static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
bool discon_issued;
netif_stop_queue(vif->ndev);
clear_bit(WLAN_ENABLED, &vif->flags);
if (wmi_ready) {
discon_issued = test_bit(CONNECTED, &vif->flags) ||
test_bit(CONNECT_PEND, &vif->flags);
ath6kl_disconnect(vif);
del_timer(&vif->disconnect_timer);
if (discon_issued)
ath6kl_disconnect_event(vif, DISCONNECT_CMD,
(vif->nw_type & AP_NETWORK) ?
bcast_mac : vif->bssid,
0, NULL, 0);
}
if (vif->scan_req) {
cfg80211_scan_done(vif->scan_req, true);
vif->scan_req = NULL;
}
/* need to clean up enhanced bmiss detection fw state */
ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
}
void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
{ {
struct ath6kl *ar = vif->ar; struct ath6kl *ar = vif->ar;
......
...@@ -61,7 +61,5 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar); ...@@ -61,7 +61,5 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar);
struct ath6kl *ath6kl_cfg80211_create(void); struct ath6kl *ath6kl_cfg80211_create(void);
void ath6kl_cfg80211_destroy(struct ath6kl *ar); void ath6kl_cfg80211_destroy(struct ath6kl *ar);
/* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */
void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable);
#endif /* ATH6KL_CFG80211_H */ #endif /* ATH6KL_CFG80211_H */
...@@ -940,7 +940,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, ...@@ -940,7 +940,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
bool wait_fot_compltn, bool cold_reset); bool wait_fot_compltn, bool cold_reset);
void ath6kl_init_control_info(struct ath6kl_vif *vif); void ath6kl_init_control_info(struct ath6kl_vif *vif);
struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar); struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready); void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready);
int ath6kl_init_hw_start(struct ath6kl *ar); int ath6kl_init_hw_start(struct ath6kl *ar);
int ath6kl_init_hw_stop(struct ath6kl *ar); int ath6kl_init_hw_stop(struct ath6kl *ar);
int ath6kl_init_fetch_firmwares(struct ath6kl *ar); int ath6kl_init_fetch_firmwares(struct ath6kl *ar);
......
...@@ -509,9 +509,7 @@ static void destroy_htc_txctrl_packet(struct htc_packet *packet) ...@@ -509,9 +509,7 @@ static void destroy_htc_txctrl_packet(struct htc_packet *packet)
{ {
struct sk_buff *skb; struct sk_buff *skb;
skb = packet->skb; skb = packet->skb;
if (skb != NULL) dev_kfree_skb(skb);
dev_kfree_skb(skb);
kfree(packet); kfree(packet);
} }
...@@ -969,6 +967,22 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, ...@@ -969,6 +967,22 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
u16 payload_len; u16 payload_len;
int status = 0; int status = 0;
/*
* ar->htc_target can be NULL due to a race condition that can occur
* during driver initialization(we do 'ath6kl_hif_power_on' before
* initializing 'ar->htc_target' via 'ath6kl_htc_create').
* 'ath6kl_hif_power_on' assigns 'ath6kl_recv_complete' as
* usb_complete_t/callback function for 'usb_fill_bulk_urb'.
* Thus the possibility of ar->htc_target being NULL
* via ath6kl_recv_complete -> ath6kl_usb_io_comp_work.
*/
if (WARN_ON_ONCE(!target)) {
ath6kl_err("Target not yet initialized\n");
status = -EINVAL;
goto free_skb;
}
netdata = skb->data; netdata = skb->data;
netlen = skb->len; netlen = skb->len;
...@@ -1054,6 +1068,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, ...@@ -1054,6 +1068,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
dev_kfree_skb(skb); dev_kfree_skb(skb);
skb = NULL; skb = NULL;
goto free_skb; goto free_skb;
} }
...@@ -1089,8 +1104,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, ...@@ -1089,8 +1104,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
skb = NULL; skb = NULL;
free_skb: free_skb:
if (skb != NULL) dev_kfree_skb(skb);
dev_kfree_skb(skb);
return status; return status;
...@@ -1184,7 +1198,7 @@ static void reset_endpoint_states(struct htc_target *target) ...@@ -1184,7 +1198,7 @@ static void reset_endpoint_states(struct htc_target *target)
INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue); INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue);
INIT_LIST_HEAD(&ep->rx_bufq); INIT_LIST_HEAD(&ep->rx_bufq);
ep->target = target; ep->target = target;
ep->pipe.tx_credit_flow_enabled = (bool) 1; /* FIXME */ ep->pipe.tx_credit_flow_enabled = true;
} }
} }
......
...@@ -1715,38 +1715,6 @@ void ath6kl_init_hw_restart(struct ath6kl *ar) ...@@ -1715,38 +1715,6 @@ void ath6kl_init_hw_restart(struct ath6kl *ar)
} }
} }
/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
{
static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
bool discon_issued;
netif_stop_queue(vif->ndev);
clear_bit(WLAN_ENABLED, &vif->flags);
if (wmi_ready) {
discon_issued = test_bit(CONNECTED, &vif->flags) ||
test_bit(CONNECT_PEND, &vif->flags);
ath6kl_disconnect(vif);
del_timer(&vif->disconnect_timer);
if (discon_issued)
ath6kl_disconnect_event(vif, DISCONNECT_CMD,
(vif->nw_type & AP_NETWORK) ?
bcast_mac : vif->bssid,
0, NULL, 0);
}
if (vif->scan_req) {
cfg80211_scan_done(vif->scan_req, true);
vif->scan_req = NULL;
}
/* need to clean up enhanced bmiss detection fw state */
ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
}
void ath6kl_stop_txrx(struct ath6kl *ar) void ath6kl_stop_txrx(struct ath6kl *ar)
{ {
struct ath6kl_vif *vif, *tmp_vif; struct ath6kl_vif *vif, *tmp_vif;
...@@ -1766,7 +1734,7 @@ void ath6kl_stop_txrx(struct ath6kl *ar) ...@@ -1766,7 +1734,7 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) { list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) {
list_del(&vif->list); list_del(&vif->list);
spin_unlock_bh(&ar->list_lock); spin_unlock_bh(&ar->list_lock);
ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag)); ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
rtnl_lock(); rtnl_lock();
ath6kl_cfg80211_vif_cleanup(vif); ath6kl_cfg80211_vif_cleanup(vif);
rtnl_unlock(); rtnl_unlock();
...@@ -1801,8 +1769,6 @@ void ath6kl_stop_txrx(struct ath6kl *ar) ...@@ -1801,8 +1769,6 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
"attempting to reset target on instance destroy\n"); "attempting to reset target on instance destroy\n");
ath6kl_reset_device(ar, ar->target_type, true, true); ath6kl_reset_device(ar, ar->target_type, true, true);
clear_bit(WLAN_ENABLED, &ar->flag);
up(&ar->sem); up(&ar->sem);
} }
EXPORT_SYMBOL(ath6kl_stop_txrx); EXPORT_SYMBOL(ath6kl_stop_txrx);
...@@ -159,10 +159,8 @@ static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe, ...@@ -159,10 +159,8 @@ static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe,
static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context) static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context)
{ {
if (urb_context->skb != NULL) { dev_kfree_skb(urb_context->skb);
dev_kfree_skb(urb_context->skb); urb_context->skb = NULL;
urb_context->skb = NULL;
}
ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context); ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context);
} }
......
...@@ -751,6 +751,23 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid) ...@@ -751,6 +751,23 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
NO_SYNC_WMIFLAG); NO_SYNC_WMIFLAG);
} }
int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,
u32 beacon_intvl)
{
struct sk_buff *skb;
struct set_beacon_int_cmd *cmd;
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct set_beacon_int_cmd *) skb->data;
cmd->beacon_intvl = cpu_to_le32(beacon_intvl);
return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
WMI_SET_BEACON_INT_CMDID, NO_SYNC_WMIFLAG);
}
int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period) int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1108,7 +1125,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, ...@@ -1108,7 +1125,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
kfree(mgmt); kfree(mgmt);
if (bss == NULL) if (bss == NULL)
return -ENOMEM; return -ENOMEM;
cfg80211_put_bss(bss); cfg80211_put_bss(ar->wiphy, bss);
/* /*
* Firmware doesn't return any event when scheduled scan has * Firmware doesn't return any event when scheduled scan has
...@@ -2480,16 +2497,11 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx) ...@@ -2480,16 +2497,11 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
free_cmd_skb: free_cmd_skb:
/* free up any resources left over (possibly due to an error) */ /* free up any resources left over (possibly due to an error) */
if (skb) dev_kfree_skb(skb);
dev_kfree_skb(skb);
free_data_skb: free_data_skb:
for (index = 0; index < num_pri_streams; index++) { for (index = 0; index < num_pri_streams; index++)
if (data_sync_bufs[index].skb != NULL) { dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].skb);
dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].
skb);
}
}
return ret; return ret;
} }
......
...@@ -1660,6 +1660,10 @@ struct roam_ctrl_cmd { ...@@ -1660,6 +1660,10 @@ struct roam_ctrl_cmd {
u8 roam_ctrl; u8 roam_ctrl;
} __packed; } __packed;
struct set_beacon_int_cmd {
__le32 beacon_intvl;
} __packed;
struct set_dtim_cmd { struct set_dtim_cmd {
__le32 dtim_period; __le32 dtim_period;
} __packed; } __packed;
...@@ -2649,6 +2653,8 @@ int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, ...@@ -2649,6 +2653,8 @@ int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi); int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi);
int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,
u32 beacon_interval);
int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode);
int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
......
...@@ -389,6 +389,7 @@ struct ath_beacon_config { ...@@ -389,6 +389,7 @@ struct ath_beacon_config {
u16 bmiss_timeout; u16 bmiss_timeout;
u8 dtim_count; u8 dtim_count;
bool enable_beacon; bool enable_beacon;
bool ibss_creator;
}; };
struct ath_beacon { struct ath_beacon {
......
...@@ -407,12 +407,17 @@ void ath9k_beacon_tasklet(unsigned long data) ...@@ -407,12 +407,17 @@ void ath9k_beacon_tasklet(unsigned long data)
} }
} }
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval) /*
* Both nexttbtt and intval have to be in usecs.
*/
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
u32 intval, bool reset_tsf)
{ {
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
ath9k_hw_disable_interrupts(ah); ath9k_hw_disable_interrupts(ah);
ath9k_hw_reset_tsf(ah); if (reset_tsf)
ath9k_hw_reset_tsf(ah);
ath9k_beaconq_config(sc); ath9k_beaconq_config(sc);
ath9k_hw_beaconinit(ah, nexttbtt, intval); ath9k_hw_beaconinit(ah, nexttbtt, intval);
sc->beacon.bmisscnt = 0; sc->beacon.bmisscnt = 0;
...@@ -442,10 +447,12 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, ...@@ -442,10 +447,12 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
else else
ah->imask &= ~ATH9K_INT_SWBA; ah->imask &= ~ATH9K_INT_SWBA;
ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n", ath_dbg(common, BEACON,
"AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
(conf->enable_beacon) ? "Enable" : "Disable",
nexttbtt, intval, conf->beacon_interval); nexttbtt, intval, conf->beacon_interval);
ath9k_beacon_init(sc, nexttbtt, intval); ath9k_beacon_init(sc, nexttbtt, intval, true);
} }
/* /*
...@@ -586,17 +593,45 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, ...@@ -586,17 +593,45 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
ath9k_reset_beacon_status(sc); ath9k_reset_beacon_status(sc);
intval = TU_TO_USEC(conf->beacon_interval); intval = TU_TO_USEC(conf->beacon_interval);
nexttbtt = intval;
if (conf->ibss_creator) {
nexttbtt = intval;
} else {
u32 tbtt, offset, tsftu;
u64 tsf;
/*
* Pull nexttbtt forward to reflect the current
* sync'd TSF.
*/
tsf = ath9k_hw_gettsf64(ah);
tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
offset = tsftu % conf->beacon_interval;
tbtt = tsftu - offset;
if (offset)
tbtt += conf->beacon_interval;
nexttbtt = TU_TO_USEC(tbtt);
}
if (conf->enable_beacon) if (conf->enable_beacon)
ah->imask |= ATH9K_INT_SWBA; ah->imask |= ATH9K_INT_SWBA;
else else
ah->imask &= ~ATH9K_INT_SWBA; ah->imask &= ~ATH9K_INT_SWBA;
ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n", ath_dbg(common, BEACON,
"IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
(conf->enable_beacon) ? "Enable" : "Disable",
nexttbtt, intval, conf->beacon_interval); nexttbtt, intval, conf->beacon_interval);
ath9k_beacon_init(sc, nexttbtt, intval); ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator);
/*
* Set the global 'beacon has been configured' flag for the
* joiner case in IBSS mode.
*/
if (!conf->ibss_creator && conf->enable_beacon)
set_bit(SC_OP_BEACONS, &sc->sc_flags);
} }
bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
...@@ -639,6 +674,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, ...@@ -639,6 +674,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->dtim_period = bss_conf->dtim_period;
cur_conf->listen_interval = 1; cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1; cur_conf->dtim_count = 1;
cur_conf->ibss_creator = bss_conf->ibss_creator;
cur_conf->bmiss_timeout = cur_conf->bmiss_timeout =
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
...@@ -666,34 +702,59 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, ...@@ -666,34 +702,59 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
{ {
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
unsigned long flags;
bool skip_beacon = false;
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
ath9k_cache_beacon_config(sc, bss_conf); ath9k_cache_beacon_config(sc, bss_conf);
ath9k_set_beacon(sc); ath9k_set_beacon(sc);
set_bit(SC_OP_BEACONS, &sc->sc_flags); set_bit(SC_OP_BEACONS, &sc->sc_flags);
} else { return;
/*
* Take care of multiple interfaces when }
* enabling/disabling SWBA.
*/ /*
if (changed & BSS_CHANGED_BEACON_ENABLED) { * Take care of multiple interfaces when
if (!bss_conf->enable_beacon && * enabling/disabling SWBA.
(sc->nbcnvifs <= 1)) { */
cur_conf->enable_beacon = false; if (changed & BSS_CHANGED_BEACON_ENABLED) {
} else if (bss_conf->enable_beacon) { if (!bss_conf->enable_beacon &&
cur_conf->enable_beacon = true; (sc->nbcnvifs <= 1)) {
ath9k_cache_beacon_config(sc, bss_conf); cur_conf->enable_beacon = false;
} } else if (bss_conf->enable_beacon) {
cur_conf->enable_beacon = true;
ath9k_cache_beacon_config(sc, bss_conf);
} }
}
if (cur_conf->beacon_interval) { /*
* Configure the HW beacon registers only when we have a valid
* beacon interval.
*/
if (cur_conf->beacon_interval) {
/*
* If we are joining an existing IBSS network, start beaconing
* only after a TSF-sync has taken place. Ensure that this
* happens by setting the appropriate flags.
*/
if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
bss_conf->enable_beacon) {
spin_lock_irqsave(&sc->sc_pm_lock, flags);
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
skip_beacon = true;
} else {
ath9k_set_beacon(sc); ath9k_set_beacon(sc);
if (cur_conf->enable_beacon)
set_bit(SC_OP_BEACONS, &sc->sc_flags);
else
clear_bit(SC_OP_BEACONS, &sc->sc_flags);
} }
/*
* Do not set the SC_OP_BEACONS flag for IBSS joiner mode
* here, it is done in ath9k_beacon_config_adhoc().
*/
if (cur_conf->enable_beacon && !skip_beacon)
set_bit(SC_OP_BEACONS, &sc->sc_flags);
else
clear_bit(SC_OP_BEACONS, &sc->sc_flags);
} }
} }
......
...@@ -320,28 +320,25 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, ...@@ -320,28 +320,25 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct ath_node *an; struct ath_node *an;
u8 density;
an = (struct ath_node *)sta->drv_priv; an = (struct ath_node *)sta->drv_priv;
an->sc = sc; an->sc = sc;
an->sta = sta; an->sta = sta;
an->vif = vif; an->vif = vif;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { ath_tx_node_init(sc, an);
ath_tx_node_init(sc, an);
if (sta->ht_cap.ht_supported) {
an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor); sta->ht_cap.ampdu_factor);
density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
an->mpdudensity = density;
} }
} }
static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
{ {
struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_node *an = (struct ath_node *)sta->drv_priv;
ath_tx_node_cleanup(sc, an);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
ath_tx_node_cleanup(sc, an);
} }
void ath9k_tasklet(unsigned long data) void ath9k_tasklet(unsigned long data)
......
...@@ -1204,7 +1204,7 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) ...@@ -1204,7 +1204,7 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta)
caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
else if (sta->ht_cap.mcs.rx_mask[1]) else if (sta->ht_cap.mcs.rx_mask[1])
caps |= WLAN_RC_DS_FLAG; caps |= WLAN_RC_DS_FLAG;
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
caps |= WLAN_RC_40_FLAG; caps |= WLAN_RC_40_FLAG;
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
caps |= WLAN_RC_SGI_FLAG; caps |= WLAN_RC_SGI_FLAG;
......
...@@ -533,7 +533,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) ...@@ -533,7 +533,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
if (sc->ps_flags & PS_BEACON_SYNC) { if (sc->ps_flags & PS_BEACON_SYNC) {
sc->ps_flags &= ~PS_BEACON_SYNC; sc->ps_flags &= ~PS_BEACON_SYNC;
ath_dbg(common, PS, ath_dbg(common, PS,
"Reconfigure Beacon timers based on timestamp from the AP\n"); "Reconfigure beacon timers based on synchronized timestamp\n");
ath9k_set_beacon(sc); ath9k_set_beacon(sc);
} }
......
...@@ -1233,7 +1233,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, ...@@ -1233,7 +1233,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
* in HT IBSS when a beacon with HT-info is received after the station * in HT IBSS when a beacon with HT-info is received after the station
* has already been added. * has already been added.
*/ */
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { if (sta->ht_cap.ht_supported) {
an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor); sta->ht_cap.ampdu_factor);
density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
...@@ -1904,8 +1904,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, ...@@ -1904,8 +1904,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
struct ath_buf *bf; struct ath_buf *bf;
u8 tidno; u8 tidno;
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an && if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) {
ieee80211_is_data_qos(hdr->frame_control)) {
tidno = ieee80211_get_qos_ctl(hdr)[0] & tidno = ieee80211_get_qos_ctl(hdr)[0] &
IEEE80211_QOS_CTL_TID_MASK; IEEE80211_QOS_CTL_TID_MASK;
tid = ATH_AN_2_TID(txctl->an, tidno); tid = ATH_AN_2_TID(txctl->an, tidno);
......
...@@ -1853,7 +1853,7 @@ void *carl9170_alloc(size_t priv_size) ...@@ -1853,7 +1853,7 @@ void *carl9170_alloc(size_t priv_size)
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
if (!modparam_noht) { if (!modparam_noht) {
......
...@@ -341,7 +341,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, ...@@ -341,7 +341,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
} }
out: out:
cfg80211_put_bss(bss); cfg80211_put_bss(wiphy, bss);
return rc; return rc;
} }
......
...@@ -338,7 +338,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) ...@@ -338,7 +338,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
if (bss) { if (bss) {
wil_dbg_wmi(wil, "Added BSS %pM\n", wil_dbg_wmi(wil, "Added BSS %pM\n",
rx_mgmt_frame->bssid); rx_mgmt_frame->bssid);
cfg80211_put_bss(bss); cfg80211_put_bss(wiphy, bss);
} else { } else {
wil_err(wil, "cfg80211_inform_bss() failed\n"); wil_err(wil, "cfg80211_inform_bss() failed\n");
} }
......
...@@ -26,6 +26,7 @@ brcmfmac-objs += \ ...@@ -26,6 +26,7 @@ brcmfmac-objs += \
wl_cfg80211.o \ wl_cfg80211.o \
fwil.o \ fwil.o \
fweh.o \ fweh.o \
p2p.o \
dhd_cdc.o \ dhd_cdc.o \
dhd_common.o \ dhd_common.o \
dhd_linux.o dhd_linux.o
...@@ -37,4 +38,4 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ ...@@ -37,4 +38,4 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
usb.o usb.o
brcmfmac-$(CONFIG_BRCMDBG) += \ brcmfmac-$(CONFIG_BRCMDBG) += \
dhd_dbg.o dhd_dbg.o
\ No newline at end of file
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
#define BRCMF_C_SET_WSEC 134 #define BRCMF_C_SET_WSEC 134
#define BRCMF_C_GET_PHY_NOISE 135 #define BRCMF_C_GET_PHY_NOISE 135
#define BRCMF_C_GET_BSS_INFO 136 #define BRCMF_C_GET_BSS_INFO 136
#define BRCMF_C_SET_SCB_TIMEOUT 158
#define BRCMF_C_GET_PHYLIST 180 #define BRCMF_C_GET_PHYLIST 180
#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185
#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187
...@@ -149,6 +150,7 @@ ...@@ -149,6 +150,7 @@
#define BRCMF_E_REASON_MINTXRATE 9 #define BRCMF_E_REASON_MINTXRATE 9
#define BRCMF_E_REASON_TXFAIL 10 #define BRCMF_E_REASON_TXFAIL 10
#define BRCMF_E_REASON_LINK_BSSCFG_DIS 4
#define BRCMF_E_REASON_FAST_ROAM_FAILED 5 #define BRCMF_E_REASON_FAST_ROAM_FAILED 5
#define BRCMF_E_REASON_DIRECTED_ROAM 6 #define BRCMF_E_REASON_DIRECTED_ROAM 6
#define BRCMF_E_REASON_TSPEC_REJECTED 7 #define BRCMF_E_REASON_TSPEC_REJECTED 7
...@@ -375,6 +377,28 @@ struct brcmf_join_params { ...@@ -375,6 +377,28 @@ struct brcmf_join_params {
struct brcmf_assoc_params_le params_le; struct brcmf_assoc_params_le params_le;
}; };
/* scan params for extended join */
struct brcmf_join_scan_params_le {
u8 scan_type; /* 0 use default, active or passive scan */
__le32 nprobes; /* -1 use default, nr of probes per channel */
__le32 active_time; /* -1 use default, dwell time per channel for
* active scanning
*/
__le32 passive_time; /* -1 use default, dwell time per channel
* for passive scanning
*/
__le32 home_time; /* -1 use default, dwell time for the home
* channel between channel scans
*/
};
/* extended join params */
struct brcmf_ext_join_params_le {
struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */
struct brcmf_join_scan_params_le scan_le;
struct brcmf_assoc_params_le assoc_le;
};
struct brcmf_wsec_key { struct brcmf_wsec_key {
u32 index; /* key index */ u32 index; /* key index */
u32 len; /* key length */ u32 len; /* key length */
...@@ -451,6 +475,19 @@ struct brcmf_sta_info_le { ...@@ -451,6 +475,19 @@ struct brcmf_sta_info_le {
__le32 rx_decrypt_failures; /* # of packet decrypted failed */ __le32 rx_decrypt_failures; /* # of packet decrypted failed */
}; };
/*
* WLC_E_PROBRESP_MSG
* WLC_E_P2P_PROBREQ_MSG
* WLC_E_ACTION_FRAME_RX
*/
struct brcmf_rx_mgmt_data {
__be16 version;
__be16 chanspec;
__be32 rssi;
__be32 mactime;
__be32 rate;
};
/* Bus independent dongle command */ /* Bus independent dongle command */
struct brcmf_dcmd { struct brcmf_dcmd {
uint cmd; /* common dongle cmd definition */ uint cmd; /* common dongle cmd definition */
...@@ -489,9 +526,6 @@ struct brcmf_pub { ...@@ -489,9 +526,6 @@ struct brcmf_pub {
struct mutex proto_block; struct mutex proto_block;
unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
atomic_t pend_8021x_cnt;
wait_queue_head_t pend_8021x_wait;
struct brcmf_fweh_info fweh; struct brcmf_fweh_info fweh;
#ifdef DEBUG #ifdef DEBUG
struct dentry *dbgfs_dir; struct dentry *dbgfs_dir;
...@@ -515,9 +549,11 @@ struct brcmf_cfg80211_vif; ...@@ -515,9 +549,11 @@ struct brcmf_cfg80211_vif;
* @vif: points to cfg80211 specific interface information. * @vif: points to cfg80211 specific interface information.
* @ndev: associated network device. * @ndev: associated network device.
* @stats: interface specific network statistics. * @stats: interface specific network statistics.
* @idx: interface index in device firmware. * @ifidx: interface index in device firmware.
* @bssidx: index of bss associated with this interface. * @bssidx: index of bss associated with this interface.
* @mac_addr: assigned mac address. * @mac_addr: assigned mac address.
* @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
* @pend_8021x_wait: used for signalling change in count.
*/ */
struct brcmf_if { struct brcmf_if {
struct brcmf_pub *drvr; struct brcmf_pub *drvr;
...@@ -526,9 +562,11 @@ struct brcmf_if { ...@@ -526,9 +562,11 @@ struct brcmf_if {
struct net_device_stats stats; struct net_device_stats stats;
struct work_struct setmacaddr_work; struct work_struct setmacaddr_work;
struct work_struct multicast_work; struct work_struct multicast_work;
int idx; int ifidx;
s32 bssidx; s32 bssidx;
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
atomic_t pend_8021x_cnt;
wait_queue_head_t pend_8021x_wait;
}; };
...@@ -547,9 +585,10 @@ extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, ...@@ -547,9 +585,10 @@ extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
struct sk_buff *rxp); struct sk_buff *rxp);
extern int brcmf_net_attach(struct brcmf_if *ifp); extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx,
s32 bssidx, char *name, u8 *mac_addr); s32 ifidx, char *name, u8 *mac_addr);
extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
extern u32 brcmf_get_chip_info(struct brcmf_if *ifp);
#endif /* _BRCMF_H_ */ #endif /* _BRCMF_H_ */
...@@ -24,18 +24,6 @@ enum brcmf_bus_state { ...@@ -24,18 +24,6 @@ enum brcmf_bus_state {
BRCMF_BUS_DATA /* Ready for frame transfers */ BRCMF_BUS_DATA /* Ready for frame transfers */
}; };
struct dngl_stats {
unsigned long rx_packets; /* total packets received */
unsigned long tx_packets; /* total packets transmitted */
unsigned long rx_bytes; /* total bytes received */
unsigned long tx_bytes; /* total bytes transmitted */
unsigned long rx_errors; /* bad packets received */
unsigned long tx_errors; /* packet transmit problems */
unsigned long rx_dropped; /* packets dropped by dongle */
unsigned long tx_dropped; /* packets dropped by dongle */
unsigned long multicast; /* multicast packets received */
};
struct brcmf_bus_dcmd { struct brcmf_bus_dcmd {
char *name; char *name;
char *param; char *param;
...@@ -72,11 +60,12 @@ struct brcmf_bus_ops { ...@@ -72,11 +60,12 @@ struct brcmf_bus_ops {
* @drvr: public driver information. * @drvr: public driver information.
* @state: operational state of the bus interface. * @state: operational state of the bus interface.
* @maxctl: maximum size for rxctl request message. * @maxctl: maximum size for rxctl request message.
* @drvr_up: indicates driver up/down status.
* @tx_realloc: number of tx packets realloced for headroom. * @tx_realloc: number of tx packets realloced for headroom.
* @dstats: dongle-based statistical data. * @dstats: dongle-based statistical data.
* @align: alignment requirement for the bus. * @align: alignment requirement for the bus.
* @dcmd_list: bus/device specific dongle initialization commands. * @dcmd_list: bus/device specific dongle initialization commands.
* @chip: device identifier of the dongle chip.
* @chiprev: revision of the dongle chip.
*/ */
struct brcmf_bus { struct brcmf_bus {
union { union {
...@@ -87,10 +76,10 @@ struct brcmf_bus { ...@@ -87,10 +76,10 @@ struct brcmf_bus {
struct brcmf_pub *drvr; struct brcmf_pub *drvr;
enum brcmf_bus_state state; enum brcmf_bus_state state;
uint maxctl; uint maxctl;
bool drvr_up;
unsigned long tx_realloc; unsigned long tx_realloc;
struct dngl_stats dstats;
u8 align; u8 align;
u32 chip;
u32 chiprev;
struct list_head dcmd_list; struct list_head dcmd_list;
struct brcmf_bus_ops *ops; struct brcmf_bus_ops *ops;
......
...@@ -303,6 +303,14 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, ...@@ -303,6 +303,14 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
return -EBADE; return -EBADE;
} }
/* The ifidx is the idx to map to matching netdev/ifp. When receiving
* events this is easy because it contains the bssidx which maps
* 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
* bssidx 1 is used for p2p0 and no data can be received or
* transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
*/
if (*ifidx)
(*ifidx)++;
if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
BDC_PROTO_VER) { BDC_PROTO_VER) {
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include "dhd_bus.h" #include "dhd_bus.h"
#include "dhd_proto.h" #include "dhd_proto.h"
#include "dhd_dbg.h" #include "dhd_dbg.h"
#include "fwil_types.h"
#include "p2p.h"
#include "wl_cfg80211.h" #include "wl_cfg80211.h"
#include "fwil.h" #include "fwil.h"
...@@ -40,6 +42,12 @@ MODULE_LICENSE("Dual BSD/GPL"); ...@@ -40,6 +42,12 @@ MODULE_LICENSE("Dual BSD/GPL");
int brcmf_msg_level; int brcmf_msg_level;
module_param(brcmf_msg_level, int, 0); module_param(brcmf_msg_level, int, 0);
/* P2P0 enable */
static int brcmf_p2p_enable;
#ifdef CONFIG_BRCMDBG
module_param_named(p2pon, brcmf_p2p_enable, int, 0);
MODULE_PARM_DESC(p2pon, "enable p2p management functionality");
#endif
char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
{ {
...@@ -70,9 +78,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work) ...@@ -70,9 +78,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
u32 buflen; u32 buflen;
s32 err; s32 err;
brcmf_dbg(TRACE, "enter\n");
ifp = container_of(work, struct brcmf_if, multicast_work); ifp = container_of(work, struct brcmf_if, multicast_work);
brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
ndev = ifp->ndev; ndev = ifp->ndev;
/* Determine initial value of allmulti flag */ /* Determine initial value of allmulti flag */
...@@ -129,9 +138,10 @@ _brcmf_set_mac_address(struct work_struct *work) ...@@ -129,9 +138,10 @@ _brcmf_set_mac_address(struct work_struct *work)
struct brcmf_if *ifp; struct brcmf_if *ifp;
s32 err; s32 err;
brcmf_dbg(TRACE, "enter\n");
ifp = container_of(work, struct brcmf_if, setmacaddr_work); ifp = container_of(work, struct brcmf_if, setmacaddr_work);
brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
ETH_ALEN); ETH_ALEN);
if (err < 0) { if (err < 0) {
...@@ -168,7 +178,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, ...@@ -168,7 +178,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
struct brcmf_pub *drvr = ifp->drvr; struct brcmf_pub *drvr = ifp->drvr;
struct ethhdr *eh; struct ethhdr *eh;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
/* Can the device send data? */ /* Can the device send data? */
if (drvr->bus_if->state != BRCMF_BUS_DATA) { if (drvr->bus_if->state != BRCMF_BUS_DATA) {
...@@ -179,8 +189,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, ...@@ -179,8 +189,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
goto done; goto done;
} }
if (!drvr->iflist[ifp->idx]) { if (!drvr->iflist[ifp->bssidx]) {
brcmf_err("bad ifidx %d\n", ifp->idx); brcmf_err("bad ifidx %d\n", ifp->bssidx);
netif_stop_queue(ndev); netif_stop_queue(ndev);
dev_kfree_skb(skb); dev_kfree_skb(skb);
ret = -ENODEV; ret = -ENODEV;
...@@ -192,14 +202,14 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, ...@@ -192,14 +202,14 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
struct sk_buff *skb2; struct sk_buff *skb2;
brcmf_dbg(INFO, "%s: insufficient headroom\n", brcmf_dbg(INFO, "%s: insufficient headroom\n",
brcmf_ifname(drvr, ifp->idx)); brcmf_ifname(drvr, ifp->bssidx));
drvr->bus_if->tx_realloc++; drvr->bus_if->tx_realloc++;
skb2 = skb_realloc_headroom(skb, drvr->hdrlen); skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
dev_kfree_skb(skb); dev_kfree_skb(skb);
skb = skb2; skb = skb2;
if (skb == NULL) { if (skb == NULL) {
brcmf_err("%s: skb_realloc_headroom failed\n", brcmf_err("%s: skb_realloc_headroom failed\n",
brcmf_ifname(drvr, ifp->idx)); brcmf_ifname(drvr, ifp->bssidx));
ret = -ENOMEM; ret = -ENOMEM;
goto done; goto done;
} }
...@@ -217,19 +227,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, ...@@ -217,19 +227,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
if (is_multicast_ether_addr(eh->h_dest)) if (is_multicast_ether_addr(eh->h_dest))
drvr->tx_multicast++; drvr->tx_multicast++;
if (ntohs(eh->h_proto) == ETH_P_PAE) if (ntohs(eh->h_proto) == ETH_P_PAE)
atomic_inc(&drvr->pend_8021x_cnt); atomic_inc(&ifp->pend_8021x_cnt);
/* If the protocol uses a data header, apply it */ /* If the protocol uses a data header, apply it */
brcmf_proto_hdrpush(drvr, ifp->idx, skb); brcmf_proto_hdrpush(drvr, ifp->ifidx, skb);
/* Use bus module to send data frame */ /* Use bus module to send data frame */
ret = brcmf_bus_txdata(drvr->bus_if, skb); ret = brcmf_bus_txdata(drvr->bus_if, skb);
done: done:
if (ret) if (ret) {
drvr->bus_if->dstats.tx_dropped++; ifp->stats.tx_dropped++;
else } else {
drvr->bus_if->dstats.tx_packets++; ifp->stats.tx_packets++;
ifp->stats.tx_bytes += skb->len;
}
/* Return ok: we always eat the packet */ /* Return ok: we always eat the packet */
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -270,12 +282,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) ...@@ -270,12 +282,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
skb_queue_walk_safe(skb_list, skb, pnext) { skb_queue_walk_safe(skb_list, skb, pnext) {
skb_unlink(skb, skb_list); skb_unlink(skb, skb_list);
/* process and remove protocol-specific header /* process and remove protocol-specific header */
*/
ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
if (ret < 0) { ifp = drvr->iflist[ifidx];
if (ret != -ENODATA)
bus_if->dstats.rx_errors++; if (ret || !ifp || !ifp->ndev) {
if ((ret != -ENODATA) && ifp)
ifp->stats.rx_errors++;
brcmu_pkt_buf_free_skb(skb); brcmu_pkt_buf_free_skb(skb);
continue; continue;
} }
...@@ -295,21 +308,11 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) ...@@ -295,21 +308,11 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
eth = skb->data; eth = skb->data;
len = skb->len; len = skb->len;
ifp = drvr->iflist[ifidx];
if (ifp == NULL)
ifp = drvr->iflist[0];
if (!ifp || !ifp->ndev ||
ifp->ndev->reg_state != NETREG_REGISTERED) {
brcmu_pkt_buf_free_skb(skb);
continue;
}
skb->dev = ifp->ndev; skb->dev = ifp->ndev;
skb->protocol = eth_type_trans(skb, skb->dev); skb->protocol = eth_type_trans(skb, skb->dev);
if (skb->pkt_type == PACKET_MULTICAST) if (skb->pkt_type == PACKET_MULTICAST)
bus_if->dstats.multicast++; ifp->stats.multicast++;
skb->data = eth; skb->data = eth;
skb->len = len; skb->len = len;
...@@ -325,8 +328,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) ...@@ -325,8 +328,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
ifp->ndev->last_rx = jiffies; ifp->ndev->last_rx = jiffies;
} }
bus_if->dstats.rx_bytes += skb->len; if (!(ifp->ndev->flags & IFF_UP)) {
bus_if->dstats.rx_packets++; /* Local count */ brcmu_pkt_buf_free_skb(skb);
continue;
}
ifp->stats.rx_bytes += skb->len;
ifp->stats.rx_packets++;
if (in_interrupt()) if (in_interrupt())
netif_rx(skb); netif_rx(skb);
...@@ -348,36 +356,31 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) ...@@ -348,36 +356,31 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
u16 type; u16 type;
struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_if *ifp;
brcmf_proto_hdrpull(drvr, &ifidx, txp); brcmf_proto_hdrpull(drvr, &ifidx, txp);
ifp = drvr->iflist[ifidx];
if (!ifp)
return;
eh = (struct ethhdr *)(txp->data); eh = (struct ethhdr *)(txp->data);
type = ntohs(eh->h_proto); type = ntohs(eh->h_proto);
if (type == ETH_P_PAE) { if (type == ETH_P_PAE) {
atomic_dec(&drvr->pend_8021x_cnt); atomic_dec(&ifp->pend_8021x_cnt);
if (waitqueue_active(&drvr->pend_8021x_wait)) if (waitqueue_active(&ifp->pend_8021x_wait))
wake_up(&drvr->pend_8021x_wait); wake_up(&ifp->pend_8021x_wait);
} }
if (!success)
ifp->stats.tx_errors++;
} }
static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
{ {
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_bus *bus_if = ifp->drvr->bus_if;
brcmf_dbg(TRACE, "Enter\n");
/* Copy dongle stats to net device stats */ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
ifp->stats.rx_packets = bus_if->dstats.rx_packets;
ifp->stats.tx_packets = bus_if->dstats.tx_packets;
ifp->stats.rx_bytes = bus_if->dstats.rx_bytes;
ifp->stats.tx_bytes = bus_if->dstats.tx_bytes;
ifp->stats.rx_errors = bus_if->dstats.rx_errors;
ifp->stats.tx_errors = bus_if->dstats.tx_errors;
ifp->stats.rx_dropped = bus_if->dstats.rx_dropped;
ifp->stats.tx_dropped = bus_if->dstats.tx_dropped;
ifp->stats.multicast = bus_if->dstats.multicast;
return &ifp->stats; return &ifp->stats;
} }
...@@ -431,7 +434,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) ...@@ -431,7 +434,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
u32 toe_cmpnt, csum_dir; u32 toe_cmpnt, csum_dir;
int ret; int ret;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
/* all ethtool calls start with a cmd word */ /* all ethtool calls start with a cmd word */
if (copy_from_user(&cmd, uaddr, sizeof(u32))) if (copy_from_user(&cmd, uaddr, sizeof(u32)))
...@@ -454,13 +457,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) ...@@ -454,13 +457,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
sprintf(info.driver, "dhd"); sprintf(info.driver, "dhd");
strcpy(info.version, BRCMF_VERSION_STR); strcpy(info.version, BRCMF_VERSION_STR);
} }
/* report dongle driver type */
/* otherwise, require dongle to be up */
else if (!drvr->bus_if->drvr_up) {
brcmf_err("dongle is not up\n");
return -ENODEV;
}
/* finally, report dongle driver type */
else else
sprintf(info.driver, "wl"); sprintf(info.driver, "wl");
...@@ -534,9 +531,9 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, ...@@ -534,9 +531,9 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr; struct brcmf_pub *drvr = ifp->drvr;
brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd); brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd);
if (!drvr->iflist[ifp->idx]) if (!drvr->iflist[ifp->bssidx])
return -1; return -1;
if (cmd == SIOCETHTOOL) if (cmd == SIOCETHTOOL)
...@@ -548,17 +545,12 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, ...@@ -548,17 +545,12 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
static int brcmf_netdev_stop(struct net_device *ndev) static int brcmf_netdev_stop(struct net_device *ndev)
{ {
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
brcmf_dbg(TRACE, "Enter\n");
if (drvr->bus_if->drvr_up == 0) brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
return 0;
brcmf_cfg80211_down(ndev); brcmf_cfg80211_down(ndev);
/* Set state and stop OS transmissions */ /* Set state and stop OS transmissions */
drvr->bus_if->drvr_up = false;
netif_stop_queue(ndev); netif_stop_queue(ndev);
return 0; return 0;
...@@ -572,7 +564,7 @@ static int brcmf_netdev_open(struct net_device *ndev) ...@@ -572,7 +564,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
u32 toe_ol; u32 toe_ol;
s32 ret = 0; s32 ret = 0;
brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
/* If bus is not ready, can't continue */ /* If bus is not ready, can't continue */
if (bus_if->state != BRCMF_BUS_DATA) { if (bus_if->state != BRCMF_BUS_DATA) {
...@@ -580,9 +572,7 @@ static int brcmf_netdev_open(struct net_device *ndev) ...@@ -580,9 +572,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
return -EAGAIN; return -EAGAIN;
} }
atomic_set(&drvr->pend_8021x_cnt, 0); atomic_set(&ifp->pend_8021x_cnt, 0);
memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
/* Get current TOE mode from dongle */ /* Get current TOE mode from dongle */
if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
...@@ -593,7 +583,6 @@ static int brcmf_netdev_open(struct net_device *ndev) ...@@ -593,7 +583,6 @@ static int brcmf_netdev_open(struct net_device *ndev)
/* Allow transmit calls */ /* Allow transmit calls */
netif_start_queue(ndev); netif_start_queue(ndev);
drvr->bus_if->drvr_up = true;
if (brcmf_cfg80211_up(ndev)) { if (brcmf_cfg80211_up(ndev)) {
brcmf_err("failed to bring up cfg80211\n"); brcmf_err("failed to bring up cfg80211\n");
return -1; return -1;
...@@ -612,29 +601,18 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { ...@@ -612,29 +601,18 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {
.ndo_set_rx_mode = brcmf_netdev_set_multicast_list .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
}; };
static const struct net_device_ops brcmf_netdev_ops_virt = { int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
.ndo_open = brcmf_cfg80211_up,
.ndo_stop = brcmf_cfg80211_down,
.ndo_get_stats = brcmf_netdev_get_stats,
.ndo_do_ioctl = brcmf_netdev_ioctl_entry,
.ndo_start_xmit = brcmf_netdev_start_xmit,
.ndo_set_mac_address = brcmf_netdev_set_mac_address,
.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
};
int brcmf_net_attach(struct brcmf_if *ifp)
{ {
struct brcmf_pub *drvr = ifp->drvr; struct brcmf_pub *drvr = ifp->drvr;
struct net_device *ndev; struct net_device *ndev;
s32 err;
brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr); brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
ifp->mac_addr);
ndev = ifp->ndev; ndev = ifp->ndev;
/* set appropriate operations */ /* set appropriate operations */
if (!ifp->idx) ndev->netdev_ops = &brcmf_netdev_ops_pri;
ndev->netdev_ops = &brcmf_netdev_ops_pri;
else
ndev->netdev_ops = &brcmf_netdev_ops_virt;
ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
ndev->ethtool_ops = &brcmf_ethtool_ops; ndev->ethtool_ops = &brcmf_ethtool_ops;
...@@ -645,7 +623,14 @@ int brcmf_net_attach(struct brcmf_if *ifp) ...@@ -645,7 +623,14 @@ int brcmf_net_attach(struct brcmf_if *ifp)
/* set the mac address */ /* set the mac address */
memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
if (register_netdev(ndev) != 0) { INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
if (rtnl_locked)
err = register_netdevice(ndev);
else
err = register_netdev(ndev);
if (err != 0) {
brcmf_err("couldn't register the net device\n"); brcmf_err("couldn't register the net device\n");
goto fail; goto fail;
} }
...@@ -659,16 +644,78 @@ int brcmf_net_attach(struct brcmf_if *ifp) ...@@ -659,16 +644,78 @@ int brcmf_net_attach(struct brcmf_if *ifp)
return -EBADE; return -EBADE;
} }
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, static int brcmf_net_p2p_open(struct net_device *ndev)
char *name, u8 *addr_mask) {
brcmf_dbg(TRACE, "Enter\n");
return brcmf_cfg80211_up(ndev);
}
static int brcmf_net_p2p_stop(struct net_device *ndev)
{
brcmf_dbg(TRACE, "Enter\n");
return brcmf_cfg80211_down(ndev);
}
static int brcmf_net_p2p_do_ioctl(struct net_device *ndev,
struct ifreq *ifr, int cmd)
{
brcmf_dbg(TRACE, "Enter\n");
return 0;
}
static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
if (skb)
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
static const struct net_device_ops brcmf_netdev_ops_p2p = {
.ndo_open = brcmf_net_p2p_open,
.ndo_stop = brcmf_net_p2p_stop,
.ndo_do_ioctl = brcmf_net_p2p_do_ioctl,
.ndo_start_xmit = brcmf_net_p2p_start_xmit
};
static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
{
struct net_device *ndev;
brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
ifp->mac_addr);
ndev = ifp->ndev;
ndev->netdev_ops = &brcmf_netdev_ops_p2p;
/* set the mac address */
memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
if (register_netdev(ndev) != 0) {
brcmf_err("couldn't register the p2p net device\n");
goto fail;
}
brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
return 0;
fail:
return -EBADE;
}
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
char *name, u8 *mac_addr)
{ {
struct brcmf_if *ifp; struct brcmf_if *ifp;
struct net_device *ndev; struct net_device *ndev;
int i;
brcmf_dbg(TRACE, "idx %d\n", ifidx); brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx);
ifp = drvr->iflist[ifidx]; ifp = drvr->iflist[bssidx];
/* /*
* Delete the existing interface before overwriting it * Delete the existing interface before overwriting it
* in case we missed the BRCMF_E_IF_DEL event. * in case we missed the BRCMF_E_IF_DEL event.
...@@ -680,7 +727,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, ...@@ -680,7 +727,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
netif_stop_queue(ifp->ndev); netif_stop_queue(ifp->ndev);
unregister_netdev(ifp->ndev); unregister_netdev(ifp->ndev);
free_netdev(ifp->ndev); free_netdev(ifp->ndev);
drvr->iflist[ifidx] = NULL; drvr->iflist[bssidx] = NULL;
} else { } else {
brcmf_err("ignore IF event\n"); brcmf_err("ignore IF event\n");
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -697,16 +744,15 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, ...@@ -697,16 +744,15 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
ifp = netdev_priv(ndev); ifp = netdev_priv(ndev);
ifp->ndev = ndev; ifp->ndev = ndev;
ifp->drvr = drvr; ifp->drvr = drvr;
drvr->iflist[ifidx] = ifp; drvr->iflist[bssidx] = ifp;
ifp->idx = ifidx; ifp->ifidx = ifidx;
ifp->bssidx = bssidx; ifp->bssidx = bssidx;
INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
if (addr_mask != NULL) init_waitqueue_head(&ifp->pend_8021x_wait);
for (i = 0; i < ETH_ALEN; i++)
ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i]; if (mac_addr != NULL)
memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
current->pid, ifp->ndev->name, ifp->mac_addr); current->pid, ifp->ndev->name, ifp->mac_addr);
...@@ -714,19 +760,18 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, ...@@ -714,19 +760,18 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
return ifp; return ifp;
} }
void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
{ {
struct brcmf_if *ifp; struct brcmf_if *ifp;
brcmf_dbg(TRACE, "idx %d\n", ifidx); ifp = drvr->iflist[bssidx];
ifp = drvr->iflist[ifidx];
if (!ifp) { if (!ifp) {
brcmf_err("Null interface\n"); brcmf_err("Null interface, idx=%d\n", bssidx);
return; return;
} }
brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
if (ifp->ndev) { if (ifp->ndev) {
if (ifidx == 0) { if (bssidx == 0) {
if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
rtnl_lock(); rtnl_lock();
brcmf_netdev_stop(ifp->ndev); brcmf_netdev_stop(ifp->ndev);
...@@ -736,12 +781,14 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) ...@@ -736,12 +781,14 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
netif_stop_queue(ifp->ndev); netif_stop_queue(ifp->ndev);
} }
cancel_work_sync(&ifp->setmacaddr_work); if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
cancel_work_sync(&ifp->multicast_work); cancel_work_sync(&ifp->setmacaddr_work);
cancel_work_sync(&ifp->multicast_work);
}
unregister_netdev(ifp->ndev); unregister_netdev(ifp->ndev);
drvr->iflist[ifidx] = NULL; drvr->iflist[bssidx] = NULL;
if (ifidx == 0) if (bssidx == 0)
brcmf_cfg80211_detach(drvr->config); brcmf_cfg80211_detach(drvr->config);
free_netdev(ifp->ndev); free_netdev(ifp->ndev);
} }
...@@ -781,8 +828,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) ...@@ -781,8 +828,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
init_waitqueue_head(&drvr->pend_8021x_wait);
return ret; return ret;
fail: fail:
...@@ -797,6 +842,7 @@ int brcmf_bus_start(struct device *dev) ...@@ -797,6 +842,7 @@ int brcmf_bus_start(struct device *dev)
struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_if *ifp; struct brcmf_if *ifp;
struct brcmf_if *p2p_ifp;
brcmf_dbg(TRACE, "\n"); brcmf_dbg(TRACE, "\n");
...@@ -812,6 +858,13 @@ int brcmf_bus_start(struct device *dev) ...@@ -812,6 +858,13 @@ int brcmf_bus_start(struct device *dev)
if (IS_ERR(ifp)) if (IS_ERR(ifp))
return PTR_ERR(ifp); return PTR_ERR(ifp);
if (brcmf_p2p_enable)
p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL);
else
p2p_ifp = NULL;
if (IS_ERR(p2p_ifp))
p2p_ifp = NULL;
/* signal bus ready */ /* signal bus ready */
bus_if->state = BRCMF_BUS_DATA; bus_if->state = BRCMF_BUS_DATA;
...@@ -830,16 +883,22 @@ int brcmf_bus_start(struct device *dev) ...@@ -830,16 +883,22 @@ int brcmf_bus_start(struct device *dev)
if (ret < 0) if (ret < 0)
goto fail; goto fail;
ret = brcmf_net_attach(ifp); ret = brcmf_net_attach(ifp, false);
fail: fail:
if (ret < 0) { if (ret < 0) {
brcmf_err("failed: %d\n", ret); brcmf_err("failed: %d\n", ret);
if (drvr->config) if (drvr->config)
brcmf_cfg80211_detach(drvr->config); brcmf_cfg80211_detach(drvr->config);
free_netdev(drvr->iflist[0]->ndev); free_netdev(ifp->ndev);
drvr->iflist[0] = NULL; drvr->iflist[0] = NULL;
if (p2p_ifp) {
free_netdev(p2p_ifp->ndev);
drvr->iflist[1] = NULL;
}
return ret; return ret;
} }
if ((brcmf_p2p_enable) && (p2p_ifp))
brcmf_net_p2p_attach(p2p_ifp);
return 0; return 0;
} }
...@@ -865,12 +924,13 @@ void brcmf_dev_reset(struct device *dev) ...@@ -865,12 +924,13 @@ void brcmf_dev_reset(struct device *dev)
if (drvr == NULL) if (drvr == NULL)
return; return;
brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); if (drvr->iflist[0])
brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
} }
void brcmf_detach(struct device *dev) void brcmf_detach(struct device *dev)
{ {
int i; s32 i;
struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_pub *drvr = bus_if->drvr;
...@@ -897,19 +957,18 @@ void brcmf_detach(struct device *dev) ...@@ -897,19 +957,18 @@ void brcmf_detach(struct device *dev)
kfree(drvr); kfree(drvr);
} }
static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr) static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
{ {
return atomic_read(&drvr->pend_8021x_cnt); return atomic_read(&ifp->pend_8021x_cnt);
} }
int brcmf_netdev_wait_pend8021x(struct net_device *ndev) int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
{ {
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
int err; int err;
err = wait_event_timeout(drvr->pend_8021x_wait, err = wait_event_timeout(ifp->pend_8021x_wait,
!brcmf_get_pend_8021x_cnt(drvr), !brcmf_get_pend_8021x_cnt(ifp),
msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
WARN_ON(!err); WARN_ON(!err);
...@@ -917,6 +976,16 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev) ...@@ -917,6 +976,16 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
return !err; return !err;
} }
/*
* return chip id and rev of the device encoded in u32.
*/
u32 brcmf_get_chip_info(struct brcmf_if *ifp)
{
struct brcmf_bus *bus = ifp->drvr->bus_if;
return bus->chip << 4 | bus->chiprev;
}
static void brcmf_driver_init(struct work_struct *work) static void brcmf_driver_init(struct work_struct *work)
{ {
brcmf_debugfs_init(); brcmf_debugfs_init();
......
...@@ -1096,7 +1096,6 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, ...@@ -1096,7 +1096,6 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
type != BRCMF_SDIO_FT_SUPER) { type != BRCMF_SDIO_FT_SUPER) {
brcmf_err("HW header length too long\n"); brcmf_err("HW header length too long\n");
bus->sdiodev->bus_if->dstats.rx_errors++;
bus->sdcnt.rx_toolong++; bus->sdcnt.rx_toolong++;
brcmf_sdbrcm_rxfail(bus, false, false); brcmf_sdbrcm_rxfail(bus, false, false);
rd->len = 0; rd->len = 0;
...@@ -1298,7 +1297,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) ...@@ -1298,7 +1297,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
if (errcode < 0) { if (errcode < 0) {
brcmf_err("glom read of %d bytes failed: %d\n", brcmf_err("glom read of %d bytes failed: %d\n",
dlen, errcode); dlen, errcode);
bus->sdiodev->bus_if->dstats.rx_errors++;
sdio_claim_host(bus->sdiodev->func[1]); sdio_claim_host(bus->sdiodev->func[1]);
if (bus->glomerr++ < 3) { if (bus->glomerr++ < 3) {
...@@ -1477,7 +1475,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) ...@@ -1477,7 +1475,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
brcmf_err("%d-byte control read exceeds %d-byte buffer\n", brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
rdlen, bus->sdiodev->bus_if->maxctl); rdlen, bus->sdiodev->bus_if->maxctl);
bus->sdiodev->bus_if->dstats.rx_errors++;
brcmf_sdbrcm_rxfail(bus, false, false); brcmf_sdbrcm_rxfail(bus, false, false);
goto done; goto done;
} }
...@@ -1485,7 +1482,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) ...@@ -1485,7 +1482,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
if ((len - doff) > bus->sdiodev->bus_if->maxctl) { if ((len - doff) > bus->sdiodev->bus_if->maxctl) {
brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
len, len - doff, bus->sdiodev->bus_if->maxctl); len, len - doff, bus->sdiodev->bus_if->maxctl);
bus->sdiodev->bus_if->dstats.rx_errors++;
bus->sdcnt.rx_toolong++; bus->sdcnt.rx_toolong++;
brcmf_sdbrcm_rxfail(bus, false, false); brcmf_sdbrcm_rxfail(bus, false, false);
goto done; goto done;
...@@ -1633,7 +1629,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) ...@@ -1633,7 +1629,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
if (!pkt) { if (!pkt) {
/* Give up on data, request rtx of events */ /* Give up on data, request rtx of events */
brcmf_err("brcmu_pkt_buf_get_skb failed\n"); brcmf_err("brcmu_pkt_buf_get_skb failed\n");
bus->sdiodev->bus_if->dstats.rx_dropped++;
brcmf_sdbrcm_rxfail(bus, false, brcmf_sdbrcm_rxfail(bus, false,
RETRYCHAN(rd->channel)); RETRYCHAN(rd->channel));
sdio_release_host(bus->sdiodev->func[1]); sdio_release_host(bus->sdiodev->func[1]);
...@@ -1651,7 +1646,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) ...@@ -1651,7 +1646,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
brcmf_err("read %d bytes from channel %d failed: %d\n", brcmf_err("read %d bytes from channel %d failed: %d\n",
rd->len, rd->channel, sdret); rd->len, rd->channel, sdret);
brcmu_pkt_buf_free_skb(pkt); brcmu_pkt_buf_free_skb(pkt);
bus->sdiodev->bus_if->dstats.rx_errors++;
sdio_claim_host(bus->sdiodev->func[1]); sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_rxfail(bus, true, brcmf_sdbrcm_rxfail(bus, true,
RETRYCHAN(rd->channel)); RETRYCHAN(rd->channel));
...@@ -1939,10 +1933,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) ...@@ -1939,10 +1933,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
datalen = pkt->len - SDPCM_HDRLEN; datalen = pkt->len - SDPCM_HDRLEN;
ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
if (ret)
bus->sdiodev->bus_if->dstats.tx_errors++;
else
bus->sdiodev->bus_if->dstats.tx_bytes += datalen;
/* In poll mode, need to check for other events */ /* In poll mode, need to check for other events */
if (!bus->intr && cnt) { if (!bus->intr && cnt) {
...@@ -1961,8 +1951,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) ...@@ -1961,8 +1951,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
} }
/* Deflow-control stack if needed */ /* Deflow-control stack if needed */
if (bus->sdiodev->bus_if->drvr_up && if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
(bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
bus->txoff = false; bus->txoff = false;
brcmf_txflowblock(bus->sdiodev->dev, false); brcmf_txflowblock(bus->sdiodev->dev, false);
...@@ -2709,9 +2698,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, ...@@ -2709,9 +2698,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
* address of sdpcm_shared structure * address of sdpcm_shared structure
*/ */
sdio_claim_host(bus->sdiodev->func[1]); sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
rv = brcmf_sdbrcm_membytes(bus, false, shaddr, rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
(u8 *)&addr_le, 4); (u8 *)&addr_le, 4);
sdio_claim_host(bus->sdiodev->func[1]); sdio_release_host(bus->sdiodev->func[1]);
if (rv < 0) if (rv < 0)
return rv; return rv;
...@@ -2730,10 +2720,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, ...@@ -2730,10 +2720,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
} }
/* Read hndrte_shared structure */ /* Read hndrte_shared structure */
sdio_claim_host(bus->sdiodev->func[1]);
rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
sizeof(struct sdpcm_shared_le)); sizeof(struct sdpcm_shared_le));
sdio_release_host(bus->sdiodev->func[1]);
if (rv < 0) if (rv < 0)
return rv; return rv;
...@@ -2835,14 +2823,12 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, ...@@ -2835,14 +2823,12 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
if ((sh->flags & SDPCM_SHARED_TRAP) == 0) if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
return 0; return 0;
sdio_claim_host(bus->sdiodev->func[1]);
error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
sizeof(struct brcmf_trap_info)); sizeof(struct brcmf_trap_info));
if (error < 0) if (error < 0)
return error; return error;
nbytes = brcmf_sdio_dump_console(bus, sh, data, count); nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
sdio_release_host(bus->sdiodev->func[1]);
if (nbytes < 0) if (nbytes < 0)
return nbytes; return nbytes;
...@@ -3307,9 +3293,6 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) ...@@ -3307,9 +3293,6 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
{ {
int ret; int ret;
if (bus->sdiodev->bus_if->drvr_up)
return -EISCONN;
ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
&bus->sdiodev->func[2]->dev); &bus->sdiodev->func[2]->dev);
if (ret) { if (ret) {
...@@ -3940,6 +3923,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) ...@@ -3940,6 +3923,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
/* Assign bus interface call back */ /* Assign bus interface call back */
bus->sdiodev->bus_if->dev = bus->sdiodev->dev; bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops;
bus->sdiodev->bus_if->chip = bus->ci->chip;
bus->sdiodev->bus_if->chiprev = bus->ci->chiprev;
/* Attach to the brcmf/OS/network interface */ /* Attach to the brcmf/OS/network interface */
ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);
......
...@@ -189,24 +189,24 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, ...@@ -189,24 +189,24 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
return; return;
} }
ifp = drvr->iflist[ifevent->ifidx]; ifp = drvr->iflist[ifevent->bssidx];
if (ifevent->action == BRCMF_E_IF_ADD) { if (ifevent->action == BRCMF_E_IF_ADD) {
brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
emsg->addr); emsg->addr);
ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx, ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx,
emsg->ifname, emsg->addr); emsg->ifname, emsg->addr);
if (IS_ERR(ifp)) if (IS_ERR(ifp))
return; return;
if (!drvr->fweh.evt_handler[BRCMF_E_IF]) if (!drvr->fweh.evt_handler[BRCMF_E_IF])
err = brcmf_net_attach(ifp); err = brcmf_net_attach(ifp, false);
} }
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
if (ifevent->action == BRCMF_E_IF_DEL) if (ifevent->action == BRCMF_E_IF_DEL)
brcmf_del_if(drvr, ifevent->ifidx); brcmf_del_if(drvr, ifevent->bssidx);
} }
/** /**
...@@ -250,8 +250,6 @@ static void brcmf_fweh_event_worker(struct work_struct *work) ...@@ -250,8 +250,6 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
drvr = container_of(fweh, struct brcmf_pub, fweh); drvr = container_of(fweh, struct brcmf_pub, fweh);
while ((event = brcmf_fweh_dequeue_event(fweh))) { while ((event = brcmf_fweh_dequeue_event(fweh))) {
ifp = drvr->iflist[event->ifidx];
brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n",
brcmf_fweh_event_name(event->code), event->code, brcmf_fweh_event_name(event->code), event->code,
event->emsg.ifidx, event->emsg.bsscfgidx, event->emsg.ifidx, event->emsg.bsscfgidx,
...@@ -283,6 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) ...@@ -283,6 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
goto event_free; goto event_free;
} }
ifp = drvr->iflist[emsg.bsscfgidx];
err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,
event->data); event->data);
if (err) { if (err) {
......
...@@ -83,6 +83,7 @@ struct brcmf_event; ...@@ -83,6 +83,7 @@ struct brcmf_event;
BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \
BRCMF_ENUM_DEF(TRACE, 52) \ BRCMF_ENUM_DEF(TRACE, 52) \
BRCMF_ENUM_DEF(IF, 54) \ BRCMF_ENUM_DEF(IF, 54) \
BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \
BRCMF_ENUM_DEF(RSSI, 56) \ BRCMF_ENUM_DEF(RSSI, 56) \
BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \
BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \
...@@ -96,8 +97,11 @@ struct brcmf_event; ...@@ -96,8 +97,11 @@ struct brcmf_event;
BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \
BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \
BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \
BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \
BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \
BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ BRCMF_ENUM_DEF(DCS_REQUEST, 73) \
BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75)
#define BRCMF_ENUM_DEF(id, val) \ #define BRCMF_ENUM_DEF(id, val) \
BRCMF_E_##id = (val), BRCMF_E_##id = (val),
......
...@@ -45,9 +45,10 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) ...@@ -45,9 +45,10 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
if (data != NULL) if (data != NULL)
len = min_t(uint, len, BRCMF_DCMD_MAXLEN); len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
if (set) if (set)
err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len); err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data,
len);
else else
err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data, err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data,
len); len);
if (err >= 0) if (err >= 0)
...@@ -100,6 +101,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) ...@@ -100,6 +101,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
__le32 data_le = cpu_to_le32(data); __le32 data_le = cpu_to_le32(data);
mutex_lock(&ifp->drvr->proto_block); mutex_lock(&ifp->drvr->proto_block);
brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data);
err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
mutex_unlock(&ifp->drvr->proto_block); mutex_unlock(&ifp->drvr->proto_block);
...@@ -116,6 +118,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) ...@@ -116,6 +118,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
mutex_unlock(&ifp->drvr->proto_block); mutex_unlock(&ifp->drvr->proto_block);
*data = le32_to_cpu(data_le); *data = le32_to_cpu(data_le);
brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data);
return err; return err;
} }
......
/*
* Copyright (c) 2012 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 FWIL_TYPES_H_
#define FWIL_TYPES_H_
#include <linux/if_ether.h>
#define BRCMF_FIL_ACTION_FRAME_SIZE 1800
enum brcmf_fil_p2p_if_types {
BRCMF_FIL_P2P_IF_CLIENT,
BRCMF_FIL_P2P_IF_GO,
BRCMF_FIL_P2P_IF_DYNBCN_GO,
BRCMF_FIL_P2P_IF_DEV,
};
struct brcmf_fil_p2p_if_le {
u8 addr[ETH_ALEN];
__le16 type;
__le16 chspec;
};
struct brcmf_fil_chan_info_le {
__le32 hw_channel;
__le32 target_channel;
__le32 scan_channel;
};
struct brcmf_fil_action_frame_le {
u8 da[ETH_ALEN];
__le16 len;
__le32 packet_id;
u8 data[BRCMF_FIL_ACTION_FRAME_SIZE];
};
struct brcmf_fil_af_params_le {
__le32 channel;
__le32 dwell_time;
u8 bssid[ETH_ALEN];
u8 pad[2];
struct brcmf_fil_action_frame_le action_frame;
};
struct brcmf_fil_bss_enable_le {
__le32 bsscfg_idx;
__le32 enable;
};
#endif /* FWIL_TYPES_H_ */
此差异已折叠。
/*
* Copyright (c) 2012 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 WL_CFGP2P_H_
#define WL_CFGP2P_H_
#include <net/cfg80211.h>
struct brcmf_cfg80211_info;
/**
* enum p2p_bss_type - different type of BSS configurations.
*
* @P2PAPI_BSSCFG_PRIMARY: maps to driver's primary bsscfg.
* @P2PAPI_BSSCFG_DEVICE: maps to driver's P2P device discovery bsscfg.
* @P2PAPI_BSSCFG_CONNECTION: maps to driver's P2P connection bsscfg.
* @P2PAPI_BSSCFG_MAX: used for range checking.
*/
enum p2p_bss_type {
P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */
P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */
P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */
P2PAPI_BSSCFG_MAX
};
/**
* struct p2p_bss - peer-to-peer bss related information.
*
* @vif: virtual interface of this P2P bss.
* @private_data: TBD
*/
struct p2p_bss {
struct brcmf_cfg80211_vif *vif;
void *private_data;
};
/**
* enum brcmf_p2p_status - P2P specific dongle status.
*
* @BRCMF_P2P_STATUS_IF_ADD: peer-to-peer vif add sent to dongle.
* @BRCMF_P2P_STATUS_IF_DEL: NOT-USED?
* @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle.
* @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle.
* @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle.
* @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed.
* @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked.
* @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing.
* @BRCMF_P2P_STATUS_DISCOVER_LISTEN: P2P listen, remaining on channel.
* @BRCMF_P2P_STATUS_SENDING_ACT_FRAME: In the process of sending action frame.
* @BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN: extra listen time for af tx.
* @BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME: waiting for action frame response.
* @BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL: search channel for AF active.
*/
enum brcmf_p2p_status {
BRCMF_P2P_STATUS_ENABLED,
BRCMF_P2P_STATUS_IF_ADD,
BRCMF_P2P_STATUS_IF_DEL,
BRCMF_P2P_STATUS_IF_DELETING,
BRCMF_P2P_STATUS_IF_CHANGING,
BRCMF_P2P_STATUS_IF_CHANGED,
BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
BRCMF_P2P_STATUS_ACTION_TX_NOACK,
BRCMF_P2P_STATUS_GO_NEG_PHASE,
BRCMF_P2P_STATUS_DISCOVER_LISTEN,
BRCMF_P2P_STATUS_SENDING_ACT_FRAME,
BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL
};
/**
* struct afx_hdl - action frame off channel storage.
*
* @afx_work: worker thread for searching channel
* @act_frm_scan: thread synchronizing struct.
* @is_active: channel searching active.
* @peer_chan: current channel.
* @is_listen: sets mode for afx worker.
* @my_listen_chan: this peers listen channel.
* @peer_listen_chan: remote peers listen channel.
* @tx_dst_addr: mac address where tx af should be sent to.
*/
struct afx_hdl {
struct work_struct afx_work;
struct completion act_frm_scan;
bool is_active;
s32 peer_chan;
bool is_listen;
u16 my_listen_chan;
u16 peer_listen_chan;
u8 tx_dst_addr[ETH_ALEN];
};
/**
* struct brcmf_p2p_info - p2p specific driver information.
*
* @cfg: driver private data for cfg80211 interface.
* @status: status of P2P (see enum brcmf_p2p_status).
* @dev_addr: P2P device address.
* @int_addr: P2P interface address.
* @bss_idx: informate for P2P bss types.
* @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state.
* @ssid: ssid for P2P GO.
* @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state.
* @remain_on_channel: contains copy of struct used by cfg80211.
* @remain_on_channel_cookie: cookie counter for remain on channel cmd
* @next_af_subtype: expected action frame subtype.
* @send_af_done: indication that action frame tx is complete.
* @afx_hdl: action frame search handler info.
* @af_sent_channel: channel action frame is sent.
* @af_tx_sent_jiffies: jiffies time when af tx was transmitted.
* @wait_next_af: thread synchronizing struct.
* @gon_req_action: about to send go negotiation requets frame.
* @block_gon_req_tx: drop tx go negotiation requets frame.
*/
struct brcmf_p2p_info {
struct brcmf_cfg80211_info *cfg;
unsigned long status;
u8 dev_addr[ETH_ALEN];
u8 int_addr[ETH_ALEN];
struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX];
struct timer_list listen_timer;
struct brcmf_ssid ssid;
u8 listen_channel;
struct ieee80211_channel remain_on_channel;
u32 remain_on_channel_cookie;
u8 next_af_subtype;
struct completion send_af_done;
struct afx_hdl afx_hdl;
u32 af_sent_channel;
unsigned long af_tx_sent_jiffies;
struct completion wait_next_af;
bool gon_req_action;
bool block_gon_req_tx;
};
s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params);
int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
enum brcmf_fil_p2p_if_types if_type);
int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev);
void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
int brcmf_p2p_scan_prep(struct wiphy *wiphy,
struct cfg80211_scan_request *request,
struct brcmf_cfg80211_vif *vif);
int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *channel,
unsigned int duration, u64 *cookie);
int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
const struct brcmf_event_msg *e,
void *data);
void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp);
int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
const struct brcmf_event_msg *e,
void *data);
int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
const struct brcmf_event_msg *e,
void *data);
bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
struct net_device *ndev,
struct brcmf_fil_af_params_le *af_params);
bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
struct brcmf_bss_info_le *bi);
s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
const struct brcmf_event_msg *e,
void *data);
#endif /* WL_CFGP2P_H_ */
...@@ -420,10 +420,6 @@ static void brcmf_usb_tx_complete(struct urb *urb) ...@@ -420,10 +420,6 @@ static void brcmf_usb_tx_complete(struct urb *urb)
brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
req->skb); req->skb);
brcmf_usb_del_fromq(devinfo, req); brcmf_usb_del_fromq(devinfo, req);
if (urb->status == 0)
devinfo->bus_pub.bus->dstats.tx_packets++;
else
devinfo->bus_pub.bus->dstats.tx_errors++;
brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
...@@ -450,10 +446,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) ...@@ -450,10 +446,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
req->skb = NULL; req->skb = NULL;
/* zero lenght packets indicate usb "failure". Do not refill */ /* zero lenght packets indicate usb "failure". Do not refill */
if (urb->status == 0 && urb->actual_length) { if (urb->status != 0 || !urb->actual_length) {
devinfo->bus_pub.bus->dstats.rx_packets++;
} else {
devinfo->bus_pub.bus->dstats.rx_errors++;
brcmu_pkt_buf_free_skb(skb); brcmu_pkt_buf_free_skb(skb);
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
return; return;
...@@ -1256,6 +1249,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) ...@@ -1256,6 +1249,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
bus->bus_priv.usb = bus_pub; bus->bus_priv.usb = bus_pub;
dev_set_drvdata(dev, bus); dev_set_drvdata(dev, bus);
bus->ops = &brcmf_usb_bus_ops; bus->ops = &brcmf_usb_bus_ops;
bus->chip = bus_pub->devid;
bus->chiprev = bus_pub->chiprev;
/* Attach to the common driver interface */ /* Attach to the common driver interface */
ret = brcmf_attach(0, dev); ret = brcmf_attach(0, dev);
......
...@@ -41,6 +41,38 @@ ...@@ -41,6 +41,38 @@
#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ #define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */
#define IE_MAX_LEN 512 #define IE_MAX_LEN 512
/* IE TLV processing */
#define TLV_LEN_OFF 1 /* length offset */
#define TLV_HDR_LEN 2 /* header length */
#define TLV_BODY_OFF 2 /* body offset */
#define TLV_OUI_LEN 3 /* oui id length */
/* 802.11 Mgmt Packet flags */
#define BRCMF_VNDR_IE_BEACON_FLAG 0x1
#define BRCMF_VNDR_IE_PRBRSP_FLAG 0x2
#define BRCMF_VNDR_IE_ASSOCRSP_FLAG 0x4
#define BRCMF_VNDR_IE_AUTHRSP_FLAG 0x8
#define BRCMF_VNDR_IE_PRBREQ_FLAG 0x10
#define BRCMF_VNDR_IE_ASSOCREQ_FLAG 0x20
/* vendor IE in IW advertisement protocol ID field */
#define BRCMF_VNDR_IE_IWAPID_FLAG 0x40
/* allow custom IE id */
#define BRCMF_VNDR_IE_CUSTOM_FLAG 0x100
/* P2P Action Frames flags (spec ordered) */
#define BRCMF_VNDR_IE_GONREQ_FLAG 0x001000
#define BRCMF_VNDR_IE_GONRSP_FLAG 0x002000
#define BRCMF_VNDR_IE_GONCFM_FLAG 0x004000
#define BRCMF_VNDR_IE_INVREQ_FLAG 0x008000
#define BRCMF_VNDR_IE_INVRSP_FLAG 0x010000
#define BRCMF_VNDR_IE_DISREQ_FLAG 0x020000
#define BRCMF_VNDR_IE_DISRSP_FLAG 0x040000
#define BRCMF_VNDR_IE_PRDREQ_FLAG 0x080000
#define BRCMF_VNDR_IE_PRDRSP_FLAG 0x100000
#define BRCMF_VNDR_IE_P2PAF_SHIFT 12
/** /**
* enum brcmf_scan_status - dongle scan status * enum brcmf_scan_status - dongle scan status
* *
...@@ -52,11 +84,19 @@ enum brcmf_scan_status { ...@@ -52,11 +84,19 @@ enum brcmf_scan_status {
BRCMF_SCAN_STATUS_ABORT, BRCMF_SCAN_STATUS_ABORT,
}; };
/* wi-fi mode */ /**
* enum wl_mode - driver mode of virtual interface.
*
* @WL_MODE_BSS: connects to BSS.
* @WL_MODE_IBSS: operate as ad-hoc.
* @WL_MODE_AP: operate as access-point.
* @WL_MODE_P2P: provide P2P discovery.
*/
enum wl_mode { enum wl_mode {
WL_MODE_BSS, WL_MODE_BSS,
WL_MODE_IBSS, WL_MODE_IBSS,
WL_MODE_AP WL_MODE_AP,
WL_MODE_P2P
}; };
/* dongle configuration */ /* dongle configuration */
...@@ -108,6 +148,7 @@ struct brcmf_cfg80211_profile { ...@@ -108,6 +148,7 @@ struct brcmf_cfg80211_profile {
* @BRCMF_VIF_STATUS_READY: ready for operation. * @BRCMF_VIF_STATUS_READY: ready for operation.
* @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
* @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
* @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
* @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
* @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
*/ */
...@@ -115,6 +156,7 @@ enum brcmf_vif_status { ...@@ -115,6 +156,7 @@ enum brcmf_vif_status {
BRCMF_VIF_STATUS_READY, BRCMF_VIF_STATUS_READY,
BRCMF_VIF_STATUS_CONNECTING, BRCMF_VIF_STATUS_CONNECTING,
BRCMF_VIF_STATUS_CONNECTED, BRCMF_VIF_STATUS_CONNECTED,
BRCMF_VIF_STATUS_DISCONNECTING,
BRCMF_VIF_STATUS_AP_CREATING, BRCMF_VIF_STATUS_AP_CREATING,
BRCMF_VIF_STATUS_AP_CREATED BRCMF_VIF_STATUS_AP_CREATED
}; };
...@@ -122,16 +164,22 @@ enum brcmf_vif_status { ...@@ -122,16 +164,22 @@ enum brcmf_vif_status {
/** /**
* struct vif_saved_ie - holds saved IEs for a virtual interface. * struct vif_saved_ie - holds saved IEs for a virtual interface.
* *
* @probe_req_ie: IE info for probe request.
* @probe_res_ie: IE info for probe response. * @probe_res_ie: IE info for probe response.
* @beacon_ie: IE info for beacon frame. * @beacon_ie: IE info for beacon frame.
* @probe_req_ie_len: IE info length for probe request.
* @probe_res_ie_len: IE info length for probe response. * @probe_res_ie_len: IE info length for probe response.
* @beacon_ie_len: IE info length for beacon frame. * @beacon_ie_len: IE info length for beacon frame.
*/ */
struct vif_saved_ie { struct vif_saved_ie {
u8 probe_req_ie[IE_MAX_LEN];
u8 probe_res_ie[IE_MAX_LEN]; u8 probe_res_ie[IE_MAX_LEN];
u8 beacon_ie[IE_MAX_LEN]; u8 beacon_ie[IE_MAX_LEN];
u8 assoc_req_ie[IE_MAX_LEN];
u32 probe_req_ie_len;
u32 probe_res_ie_len; u32 probe_res_ie_len;
u32 beacon_ie_len; u32 beacon_ie_len;
u32 assoc_req_ie_len;
}; };
/** /**
...@@ -145,6 +193,7 @@ struct vif_saved_ie { ...@@ -145,6 +193,7 @@ struct vif_saved_ie {
* @sme_state: SME state using enum brcmf_vif_status bits. * @sme_state: SME state using enum brcmf_vif_status bits.
* @pm_block: power-management blocked. * @pm_block: power-management blocked.
* @list: linked list. * @list: linked list.
* @mgmt_rx_reg: registered rx mgmt frame types.
*/ */
struct brcmf_cfg80211_vif { struct brcmf_cfg80211_vif {
struct brcmf_if *ifp; struct brcmf_if *ifp;
...@@ -156,6 +205,7 @@ struct brcmf_cfg80211_vif { ...@@ -156,6 +205,7 @@ struct brcmf_cfg80211_vif {
bool pm_block; bool pm_block;
struct vif_saved_ie saved_ie; struct vif_saved_ie saved_ie;
struct list_head list; struct list_head list;
u16 mgmt_rx_reg;
}; };
/* association inform */ /* association inform */
...@@ -189,6 +239,9 @@ struct escan_info { ...@@ -189,6 +239,9 @@ struct escan_info {
u8 escan_buf[WL_ESCAN_BUF_SIZE]; u8 escan_buf[WL_ESCAN_BUF_SIZE];
struct wiphy *wiphy; struct wiphy *wiphy;
struct net_device *ndev; struct net_device *ndev;
s32 (*run)(struct brcmf_cfg80211_info *cfg,
struct net_device *ndev,
struct cfg80211_scan_request *request, u16 action);
}; };
/** /**
...@@ -272,11 +325,28 @@ struct brcmf_pno_scanresults_le { ...@@ -272,11 +325,28 @@ struct brcmf_pno_scanresults_le {
__le32 count; __le32 count;
}; };
/**
* struct brcmf_cfg80211_vif_event - virtual interface event information.
*
* @vif_wq: waitqueue awaiting interface event from firmware.
* @vif_event_lock: protects other members in this structure.
* @vif_complete: completion for net attach.
* @action: either add, change, or delete.
* @vif: virtual interface object related to the event.
*/
struct brcmf_cfg80211_vif_event {
wait_queue_head_t vif_wq;
struct mutex vif_event_lock;
u8 action;
struct brcmf_cfg80211_vif *vif;
};
/** /**
* struct brcmf_cfg80211_info - dongle private data of cfg80211 interface * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
* *
* @wiphy: wiphy object for cfg80211 interface. * @wiphy: wiphy object for cfg80211 interface.
* @conf: dongle configuration. * @conf: dongle configuration.
* @p2p: peer-to-peer specific information.
* @scan_request: cfg80211 scan request object. * @scan_request: cfg80211 scan request object.
* @usr_sync: mainly for dongle up/down synchronization. * @usr_sync: mainly for dongle up/down synchronization.
* @bss_list: bss_list holding scanned ap information. * @bss_list: bss_list holding scanned ap information.
...@@ -304,10 +374,12 @@ struct brcmf_pno_scanresults_le { ...@@ -304,10 +374,12 @@ struct brcmf_pno_scanresults_le {
* @escan_ioctl_buf: dongle command buffer for escan commands. * @escan_ioctl_buf: dongle command buffer for escan commands.
* @vif_list: linked list of vif instances. * @vif_list: linked list of vif instances.
* @vif_cnt: number of vif instances. * @vif_cnt: number of vif instances.
* @vif_event: vif event signalling.
*/ */
struct brcmf_cfg80211_info { struct brcmf_cfg80211_info {
struct wiphy *wiphy; struct wiphy *wiphy;
struct brcmf_cfg80211_conf *conf; struct brcmf_cfg80211_conf *conf;
struct brcmf_p2p_info p2p;
struct cfg80211_scan_request *scan_request; struct cfg80211_scan_request *scan_request;
struct mutex usr_sync; struct mutex usr_sync;
struct brcmf_scan_results *bss_list; struct brcmf_scan_results *bss_list;
...@@ -335,6 +407,21 @@ struct brcmf_cfg80211_info { ...@@ -335,6 +407,21 @@ struct brcmf_cfg80211_info {
u8 *escan_ioctl_buf; u8 *escan_ioctl_buf;
struct list_head vif_list; struct list_head vif_list;
u8 vif_cnt; u8 vif_cnt;
struct brcmf_cfg80211_vif_event vif_event;
struct completion vif_disabled;
};
/**
* struct brcmf_tlv - tag_ID/length/value_buffer tuple.
*
* @id: tag identifier.
* @len: number of bytes in value buffer.
* @data: value buffer.
*/
struct brcmf_tlv {
u8 id;
u8 len;
u8 data[1];
}; };
static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
...@@ -389,4 +476,26 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); ...@@ -389,4 +476,26 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_up(struct net_device *ndev); s32 brcmf_cfg80211_up(struct net_device *ndev);
s32 brcmf_cfg80211_down(struct net_device *ndev); s32 brcmf_cfg80211_down(struct net_device *ndev);
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype type,
bool pm_block);
void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
const u8 *vndr_ie_buf, u32 vndr_ie_len);
s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key);
u16 channel_to_chanspec(struct ieee80211_channel *ch);
u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state);
void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif);
bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
u8 action, ulong timeout);
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
struct net_device *ndev,
bool aborted, bool fw_abort);
void brcmf_set_mpc(struct net_device *ndev, int mpc);
void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
#endif /* _wl_cfg80211_h_ */ #endif /* _wl_cfg80211_h_ */
...@@ -183,8 +183,7 @@ static bool brcms_c_country_valid(const char *ccode) ...@@ -183,8 +183,7 @@ static bool brcms_c_country_valid(const char *ccode)
* chars. * chars.
*/ */
if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A &&
(0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A && (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A))
ccode[2] == '\0'))
return false; return false;
/* /*
......
...@@ -101,8 +101,6 @@ ...@@ -101,8 +101,6 @@
#define DOT11_RTS_LEN 16 #define DOT11_RTS_LEN 16
#define DOT11_CTS_LEN 10 #define DOT11_CTS_LEN 10
#define DOT11_BA_BITMAP_LEN 128 #define DOT11_BA_BITMAP_LEN 128
#define DOT11_MIN_BEACON_PERIOD 1
#define DOT11_MAX_BEACON_PERIOD 0xFFFF
#define DOT11_MAXNUMFRAGS 16 #define DOT11_MAXNUMFRAGS 16
#define DOT11_MAX_FRAG_LEN 2346 #define DOT11_MAX_FRAG_LEN 2346
...@@ -3140,8 +3138,7 @@ void brcms_c_reset(struct brcms_c_info *wlc) ...@@ -3140,8 +3138,7 @@ void brcms_c_reset(struct brcms_c_info *wlc)
brcms_c_statsupd(wlc); brcms_c_statsupd(wlc);
/* reset our snapshot of macstat counters */ /* reset our snapshot of macstat counters */
memset((char *)wlc->core->macstat_snapshot, 0, memset(wlc->core->macstat_snapshot, 0, sizeof(struct macstat));
sizeof(struct macstat));
brcms_b_reset(wlc->hw); brcms_b_reset(wlc->hw);
} }
...@@ -4054,7 +4051,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, ...@@ -4054,7 +4051,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
return; return;
} }
memset((char *)&acp_shm, 0, sizeof(struct shm_acparams)); memset(&acp_shm, 0, sizeof(struct shm_acparams));
/* fill in shm ac params struct */ /* fill in shm ac params struct */
acp_shm.txop = params->txop; acp_shm.txop = params->txop;
/* convert from units of 32us to us for ucode */ /* convert from units of 32us to us for ucode */
...@@ -4770,7 +4767,7 @@ static void brcms_c_bss_default_init(struct brcms_c_info *wlc) ...@@ -4770,7 +4767,7 @@ static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
struct brcms_bss_info *bi = wlc->default_bss; struct brcms_bss_info *bi = wlc->default_bss;
/* init default and target BSS with some sane initial values */ /* init default and target BSS with some sane initial values */
memset((char *)(bi), 0, sizeof(struct brcms_bss_info)); memset(bi, 0, sizeof(*bi));
bi->beacon_period = BEACON_INTERVAL_DEFAULT; bi->beacon_period = BEACON_INTERVAL_DEFAULT;
/* fill the default channel as the first valid channel /* fill the default channel as the first valid channel
...@@ -5299,7 +5296,7 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) ...@@ -5299,7 +5296,7 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);
/* Clear rateset override */ /* Clear rateset override */
memset(&rs, 0, sizeof(struct brcms_c_rateset)); memset(&rs, 0, sizeof(rs));
switch (gmode) { switch (gmode) {
case GMODE_LEGACY_B: case GMODE_LEGACY_B:
...@@ -5522,7 +5519,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) ...@@ -5522,7 +5519,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
if (rs->count > BRCMS_NUMRATES) if (rs->count > BRCMS_NUMRATES)
return -ENOBUFS; return -ENOBUFS;
memset(&internal_rs, 0, sizeof(struct brcms_c_rateset)); memset(&internal_rs, 0, sizeof(internal_rs));
/* Copy only legacy rateset section */ /* Copy only legacy rateset section */
internal_rs.count = rs->count; internal_rs.count = rs->count;
...@@ -5548,8 +5545,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) ...@@ -5548,8 +5545,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
{ {
if (period < DOT11_MIN_BEACON_PERIOD || if (period == 0)
period > DOT11_MAX_BEACON_PERIOD)
return -EINVAL; return -EINVAL;
wlc->default_bss->beacon_period = period; wlc->default_bss->beacon_period = period;
...@@ -5626,7 +5622,7 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, ...@@ -5626,7 +5622,7 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
for (i = 0; i < BRCMS_MAXMODULES; i++) { for (i = 0; i < BRCMS_MAXMODULES; i++) {
if (!strcmp(wlc->modulecb[i].name, name) && if (!strcmp(wlc->modulecb[i].name, name) &&
(wlc->modulecb[i].hdl == hdl)) { (wlc->modulecb[i].hdl == hdl)) {
memset(&wlc->modulecb[i], 0, sizeof(struct modulecb)); memset(&wlc->modulecb[i], 0, sizeof(wlc->modulecb[i]));
return 0; return 0;
} }
} }
...@@ -6446,10 +6442,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, ...@@ -6446,10 +6442,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
&& (!is_mcs_rate(rspec[k]))) { && (!is_mcs_rate(rspec[k]))) {
brcms_err(wlc->hw->d11core, brcms_warn(wlc->hw->d11core,
"wl%d: %s: IEEE80211_TX_" "wl%d: %s: IEEE80211_TX_RC_MCS != is_mcs_rate(rspec)\n",
"RC_MCS != is_mcs_rate(rspec)\n", wlc->pub->unit, __func__);
wlc->pub->unit, __func__);
} }
if (is_mcs_rate(rspec[k])) { if (is_mcs_rate(rspec[k])) {
...@@ -6682,11 +6677,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, ...@@ -6682,11 +6677,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
(struct ofdm_phy_hdr *) rts_plcp) : (struct ofdm_phy_hdr *) rts_plcp) :
rts_plcp[0]) << 8; rts_plcp[0]) << 8;
} else { } else {
memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); memset(txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
memset((char *)&txh->rts_frame, 0, memset(&txh->rts_frame, 0, sizeof(struct ieee80211_rts));
sizeof(struct ieee80211_rts)); memset(txh->RTSPLCPFallback, 0, sizeof(txh->RTSPLCPFallback));
memset((char *)txh->RTSPLCPFallback, 0,
sizeof(txh->RTSPLCPFallback));
txh->RTSDurFallback = 0; txh->RTSDurFallback = 0;
} }
...@@ -6841,21 +6834,19 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, ...@@ -6841,21 +6834,19 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
wlc->fragthresh[queue] = wlc->fragthresh[queue] =
(u16) newfragthresh; (u16) newfragthresh;
} else { } else {
brcms_err(wlc->hw->d11core, brcms_warn(wlc->hw->d11core,
"wl%d: %s txop invalid " "wl%d: %s txop invalid for rate %d\n",
"for rate %d\n", wlc->pub->unit, fifo_names[queue],
wlc->pub->unit, fifo_names[queue], rspec2rate(rspec[0]));
rspec2rate(rspec[0]));
} }
if (dur > wlc->edcf_txop[ac]) if (dur > wlc->edcf_txop[ac])
brcms_err(wlc->hw->d11core, brcms_warn(wlc->hw->d11core,
"wl%d: %s: %s txop " "wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n",
"exceeded phylen %d/%d dur %d/%d\n", wlc->pub->unit, __func__,
wlc->pub->unit, __func__, fifo_names[queue],
fifo_names[queue], phylen, wlc->fragthresh[queue],
phylen, wlc->fragthresh[queue], dur, wlc->edcf_txop[ac]);
dur, wlc->edcf_txop[ac]);
} }
} }
...@@ -7330,7 +7321,7 @@ brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type, ...@@ -7330,7 +7321,7 @@ brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
*len = hdr_len + body_len; *len = hdr_len + body_len;
/* format PHY and MAC headers */ /* format PHY and MAC headers */
memset((char *)buf, 0, hdr_len); memset(buf, 0, hdr_len);
plcp = (struct cck_phy_hdr *) buf; plcp = (struct cck_phy_hdr *) buf;
...@@ -7401,9 +7392,13 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, ...@@ -7401,9 +7392,13 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
struct brcms_bss_cfg *cfg, struct brcms_bss_cfg *cfg,
bool suspend) bool suspend)
{ {
u16 prb_resp[BCN_TMPL_LEN / 2]; u16 *prb_resp;
int len = BCN_TMPL_LEN; int len = BCN_TMPL_LEN;
prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC);
if (!prb_resp)
return;
/* /*
* write the probe response to hardware, or save in * write the probe response to hardware, or save in
* the config structure * the config structure
...@@ -7437,6 +7432,8 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, ...@@ -7437,6 +7432,8 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
if (suspend) if (suspend)
brcms_c_enable_mac(wlc); brcms_c_enable_mac(wlc);
kfree(prb_resp);
} }
void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
......
...@@ -572,26 +572,11 @@ il3945_tx_skb(struct il_priv *il, ...@@ -572,26 +572,11 @@ il3945_tx_skb(struct il_priv *il,
il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id); il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id);
/* Total # bytes to be transmitted */ /* Total # bytes to be transmitted */
len = (u16) skb->len; tx_cmd->len = cpu_to_le16((u16) skb->len);
tx_cmd->len = cpu_to_le16(len);
il_update_stats(il, true, fc, len);
tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
} else {
wait_write_ptr = 1;
txq->need_update = 0;
}
D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence));
D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd));
il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr,
ieee80211_hdrlen(fc));
/* /*
* Use the first empty entry in this queue's command buffer array * Use the first empty entry in this queue's command buffer array
* to contain the Tx command and MAC header concatenated together * to contain the Tx command and MAC header concatenated together
...@@ -610,14 +595,8 @@ il3945_tx_skb(struct il_priv *il, ...@@ -610,14 +595,8 @@ il3945_tx_skb(struct il_priv *il,
* within command buffer array. */ * within command buffer array. */
txcmd_phys = txcmd_phys =
pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE); pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE);
/* we do not map meta data ... so we can safely access address to if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))
* provide to unmap command*/ goto drop_unlock;
dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
dma_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
/* Set up TFD's 2nd entry to point directly to remainder of skb, /* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */ * if any (802.11 null frames have no payload). */
...@@ -626,10 +605,34 @@ il3945_tx_skb(struct il_priv *il, ...@@ -626,10 +605,34 @@ il3945_tx_skb(struct il_priv *il,
phys_addr = phys_addr =
pci_map_single(il->pci_dev, skb->data + hdr_len, len, pci_map_single(il->pci_dev, skb->data + hdr_len, len,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))
goto drop_unlock;
}
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
dma_unmap_len_set(out_meta, len, len);
if (len)
il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0, il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
U32_PAD(len)); U32_PAD(len));
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
} else {
wait_write_ptr = 1;
txq->need_update = 0;
} }
il_update_stats(il, true, fc, skb->len);
D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence));
D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd));
il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr,
ieee80211_hdrlen(fc));
/* Tell device the write idx *just past* this latest filled TFD */ /* Tell device the write idx *just past* this latest filled TFD */
q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd);
il_txq_update_write_ptr(il, txq); il_txq_update_write_ptr(il, txq);
......
...@@ -1793,8 +1793,7 @@ il4965_tx_skb(struct il_priv *il, ...@@ -1793,8 +1793,7 @@ il4965_tx_skb(struct il_priv *il,
memcpy(tx_cmd->hdr, hdr, hdr_len); memcpy(tx_cmd->hdr, hdr, hdr_len);
/* Total # bytes to be transmitted */ /* Total # bytes to be transmitted */
len = (u16) skb->len; tx_cmd->len = cpu_to_le16((u16) skb->len);
tx_cmd->len = cpu_to_le16(len);
if (info->control.hw_key) if (info->control.hw_key)
il4965_tx_cmd_build_hwcrypto(il, info, tx_cmd, skb, sta_id); il4965_tx_cmd_build_hwcrypto(il, info, tx_cmd, skb, sta_id);
...@@ -1804,7 +1803,6 @@ il4965_tx_skb(struct il_priv *il, ...@@ -1804,7 +1803,6 @@ il4965_tx_skb(struct il_priv *il,
il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc); il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc);
il_update_stats(il, true, fc, len);
/* /*
* Use the first empty entry in this queue's command buffer array * Use the first empty entry in this queue's command buffer array
* to contain the Tx command and MAC header concatenated together * to contain the Tx command and MAC header concatenated together
...@@ -1826,18 +1824,8 @@ il4965_tx_skb(struct il_priv *il, ...@@ -1826,18 +1824,8 @@ il4965_tx_skb(struct il_priv *il,
txcmd_phys = txcmd_phys =
pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen, pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen,
PCI_DMA_BIDIRECTIONAL); PCI_DMA_BIDIRECTIONAL);
dma_unmap_addr_set(out_meta, mapping, txcmd_phys); if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))
dma_unmap_len_set(out_meta, len, firstlen); goto drop_unlock;
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
} else {
wait_write_ptr = 1;
txq->need_update = 0;
}
/* Set up TFD's 2nd entry to point directly to remainder of skb, /* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */ * if any (802.11 null frames have no payload). */
...@@ -1846,8 +1834,24 @@ il4965_tx_skb(struct il_priv *il, ...@@ -1846,8 +1834,24 @@ il4965_tx_skb(struct il_priv *il,
phys_addr = phys_addr =
pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen, pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))
goto drop_unlock;
}
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
dma_unmap_len_set(out_meta, len, firstlen);
if (secondlen)
il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen,
0, 0); 0, 0);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
} else {
wait_write_ptr = 1;
txq->need_update = 0;
} }
scratch_phys = scratch_phys =
...@@ -1860,6 +1864,8 @@ il4965_tx_skb(struct il_priv *il, ...@@ -1860,6 +1864,8 @@ il4965_tx_skb(struct il_priv *il,
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys); tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys);
il_update_stats(il, true, fc, skb->len);
D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence)); D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence));
D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd, sizeof(*tx_cmd)); il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd, sizeof(*tx_cmd));
...@@ -5733,7 +5739,7 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) ...@@ -5733,7 +5739,7 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
/* Tell mac80211 our characteristics */ /* Tell mac80211 our characteristics */
hw->flags = hw->flags =
IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS; IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
if (il->cfg->sku & IL_SKU_N) if (il->cfg->sku & IL_SKU_N)
......
...@@ -1183,8 +1183,7 @@ il4965_rs_switch_to_mimo2(struct il_priv *il, struct il_lq_sta *lq_sta, ...@@ -1183,8 +1183,7 @@ il4965_rs_switch_to_mimo2(struct il_priv *il, struct il_lq_sta *lq_sta,
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1; return -1;
if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) == if (sta->smps_mode == IEEE80211_SMPS_STATIC)
WLAN_HT_CAP_SM_PS_STATIC)
return -1; return -1;
/* Need both Tx chains/antennas to support MIMO */ /* Need both Tx chains/antennas to support MIMO */
......
...@@ -1830,32 +1830,30 @@ il_set_ht_add_station(struct il_priv *il, u8 idx, struct ieee80211_sta *sta) ...@@ -1830,32 +1830,30 @@ il_set_ht_add_station(struct il_priv *il, u8 idx, struct ieee80211_sta *sta)
{ {
struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
__le32 sta_flags; __le32 sta_flags;
u8 mimo_ps_mode;
if (!sta || !sta_ht_inf->ht_supported) if (!sta || !sta_ht_inf->ht_supported)
goto done; goto done;
mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
D_ASSOC("spatial multiplexing power save mode: %s\n", D_ASSOC("spatial multiplexing power save mode: %s\n",
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? "static" : (sta->smps_mode == IEEE80211_SMPS_STATIC) ? "static" :
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? "dynamic" : (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? "dynamic" :
"disabled"); "disabled");
sta_flags = il->stations[idx].sta.station_flags; sta_flags = il->stations[idx].sta.station_flags;
sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
switch (mimo_ps_mode) { switch (sta->smps_mode) {
case WLAN_HT_CAP_SM_PS_STATIC: case IEEE80211_SMPS_STATIC:
sta_flags |= STA_FLG_MIMO_DIS_MSK; sta_flags |= STA_FLG_MIMO_DIS_MSK;
break; break;
case WLAN_HT_CAP_SM_PS_DYNAMIC: case IEEE80211_SMPS_DYNAMIC:
sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
break; break;
case WLAN_HT_CAP_SM_PS_DISABLED: case IEEE80211_SMPS_OFF:
break; break;
default: default:
IL_WARN("Invalid MIMO PS mode %d\n", mimo_ps_mode); IL_WARN("Invalid MIMO PS mode %d\n", sta->smps_mode);
break; break;
} }
...@@ -3162,18 +3160,23 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd) ...@@ -3162,18 +3160,23 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
idx, il->cmd_queue); idx, il->cmd_queue);
} }
#endif #endif
txq->need_update = 1;
if (il->ops->txq_update_byte_cnt_tbl)
/* Set up entry in queue's byte count circular buffer */
il->ops->txq_update_byte_cnt_tbl(il, txq, 0);
phys_addr = phys_addr =
pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size, pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size,
PCI_DMA_BIDIRECTIONAL); PCI_DMA_BIDIRECTIONAL);
if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) {
idx = -ENOMEM;
goto out;
}
dma_unmap_addr_set(out_meta, mapping, phys_addr); dma_unmap_addr_set(out_meta, mapping, phys_addr);
dma_unmap_len_set(out_meta, len, fix_size); dma_unmap_len_set(out_meta, len, fix_size);
txq->need_update = 1;
if (il->ops->txq_update_byte_cnt_tbl)
/* Set up entry in queue's byte count circular buffer */
il->ops->txq_update_byte_cnt_tbl(il, txq, 0);
il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1, il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1,
U32_PAD(cmd->len)); U32_PAD(cmd->len));
...@@ -3181,6 +3184,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd) ...@@ -3181,6 +3184,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd); q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd);
il_txq_update_write_ptr(il, txq); il_txq_update_write_ptr(il, txq);
out:
spin_unlock_irqrestore(&il->hcmd_lock, flags); spin_unlock_irqrestore(&il->hcmd_lock, flags);
return idx; return idx;
} }
......
...@@ -338,7 +338,7 @@ int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx, ...@@ -338,7 +338,7 @@ int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct iwl_rxon_context *ctx, struct iwl_rxon_context *ctx,
struct ieee80211_sta_ht_cap *ht_cap); struct ieee80211_sta *sta);
static inline int iwl_sta_id(struct ieee80211_sta *sta) static inline int iwl_sta_id(struct ieee80211_sta *sta)
{ {
......
...@@ -3897,6 +3897,24 @@ struct iwlagn_wowlan_kek_kck_material_cmd { ...@@ -3897,6 +3897,24 @@ struct iwlagn_wowlan_kek_kck_material_cmd {
__le64 replay_ctr; __le64 replay_ctr;
} __packed; } __packed;
#define RF_KILL_INDICATOR_FOR_WOWLAN 0x87
/*
* REPLY_WOWLAN_GET_STATUS = 0xe5
*/
struct iwlagn_wowlan_status {
__le64 replay_ctr;
__le32 rekey_status;
__le32 wakeup_reason;
u8 pattern_number;
u8 reserved1;
__le16 qos_seq_ctr[8];
__le16 non_qos_seq_ctr;
__le16 reserved2;
union iwlagn_all_tsc_rsc tsc_rsc;
__le16 reserved3;
} __packed;
/* /*
* REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification) * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
*/ */
......
...@@ -1289,8 +1289,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, ...@@ -1289,8 +1289,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1; return -1;
if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) if (sta->smps_mode == IEEE80211_SMPS_STATIC)
== WLAN_HT_CAP_SM_PS_STATIC)
return -1; return -1;
/* Need both Tx chains/antennas to support MIMO */ /* Need both Tx chains/antennas to support MIMO */
...@@ -1305,7 +1304,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, ...@@ -1305,7 +1304,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_SEARCH; tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_mimo2_rate; rate_mask = lq_sta->active_mimo2_rate;
if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
tbl->is_ht40 = 1; tbl->is_ht40 = 1;
else else
tbl->is_ht40 = 0; tbl->is_ht40 = 0;
...@@ -1345,8 +1344,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, ...@@ -1345,8 +1344,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1; return -1;
if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) if (sta->smps_mode == IEEE80211_SMPS_STATIC)
== WLAN_HT_CAP_SM_PS_STATIC)
return -1; return -1;
/* Need both Tx chains/antennas to support MIMO */ /* Need both Tx chains/antennas to support MIMO */
...@@ -1361,7 +1359,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, ...@@ -1361,7 +1359,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
rate_mask = lq_sta->active_mimo3_rate; rate_mask = lq_sta->active_mimo3_rate;
if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
tbl->is_ht40 = 1; tbl->is_ht40 = 1;
else else
tbl->is_ht40 = 0; tbl->is_ht40 = 0;
...@@ -1410,7 +1408,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, ...@@ -1410,7 +1408,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_SEARCH; tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_siso_rate; rate_mask = lq_sta->active_siso_rate;
if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
tbl->is_ht40 = 1; tbl->is_ht40 = 1;
else else
tbl->is_ht40 = 0; tbl->is_ht40 = 0;
......
...@@ -790,7 +790,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, ...@@ -790,7 +790,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
ieee80211_rx(priv->hw, skb); ieee80211_rx_ni(priv->hw, skb);
} }
static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
......
...@@ -1545,10 +1545,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1545,10 +1545,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->bssid); bss_conf->bssid);
} }
if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC && if (changes & BSS_CHANGED_BEACON && priv->beacon_ctx == ctx) {
priv->beacon_ctx) {
if (iwlagn_update_beacon(priv, vif)) if (iwlagn_update_beacon(priv, vif))
IWL_ERR(priv, "Error sending IBSS beacon\n"); IWL_ERR(priv, "Error updating beacon\n");
} }
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
......
...@@ -113,13 +113,13 @@ struct iwl_cfg; ...@@ -113,13 +113,13 @@ struct iwl_cfg;
* May sleep * May sleep
* @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
* HCMD the this Rx responds to. * HCMD the this Rx responds to.
* Must be atomic and called with BH disabled. * This callback may sleep, it is called from a threaded IRQ handler.
* @queue_full: notifies that a HW queue is full. * @queue_full: notifies that a HW queue is full.
* Must be atomic and called with BH disabled. * Must be atomic and called with BH disabled.
* @queue_not_full: notifies that a HW queue is not full any more. * @queue_not_full: notifies that a HW queue is not full any more.
* Must be atomic and called with BH disabled. * Must be atomic and called with BH disabled.
* @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that
* the radio is killed. Must be atomic. * the radio is killed. May sleep.
* @free_skb: allows the transport layer to free skbs that haven't been * @free_skb: allows the transport layer to free skbs that haven't been
* reclaimed by the op_mode. This can happen when the driver is freed and * reclaimed by the op_mode. This can happen when the driver is freed and
* there are Tx packets pending in the transport layer. * there are Tx packets pending in the transport layer.
...@@ -130,8 +130,7 @@ struct iwl_cfg; ...@@ -130,8 +130,7 @@ struct iwl_cfg;
* called with BH disabled. * called with BH disabled.
* @nic_config: configure NIC, called before firmware is started. * @nic_config: configure NIC, called before firmware is started.
* May sleep * May sleep
* @wimax_active: invoked when WiMax becomes active. Must be atomic and called * @wimax_active: invoked when WiMax becomes active. May sleep
* with BH disabled.
*/ */
struct iwl_op_mode_ops { struct iwl_op_mode_ops {
struct iwl_op_mode *(*start)(struct iwl_trans *trans, struct iwl_op_mode *(*start)(struct iwl_trans *trans,
...@@ -178,6 +177,7 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, ...@@ -178,6 +177,7 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode,
struct iwl_rx_cmd_buffer *rxb, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd) struct iwl_device_cmd *cmd)
{ {
might_sleep();
return op_mode->ops->rx(op_mode, rxb, cmd); return op_mode->ops->rx(op_mode, rxb, cmd);
} }
...@@ -196,6 +196,7 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, ...@@ -196,6 +196,7 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode,
static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode,
bool state) bool state)
{ {
might_sleep();
op_mode->ops->hw_rf_kill(op_mode, state); op_mode->ops->hw_rf_kill(op_mode, state);
} }
...@@ -223,6 +224,7 @@ static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode) ...@@ -223,6 +224,7 @@ static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode)
static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
{ {
might_sleep();
op_mode->ops->wimax_active(op_mode); op_mode->ops->wimax_active(op_mode);
} }
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册