diff options
Diffstat (limited to 'drivers/net/wireless/marvell')
26 files changed, 492 insertions, 224 deletions
diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 3f97acb57e66..a0463fef79b0 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -1657,7 +1657,7 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, */ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, - enum nl80211_iftype type, u32 *flags, + enum nl80211_iftype type, struct vif_params *params) { struct lbs_private *priv = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index c3a53cd6988e..7b4955cc38db 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -1181,6 +1181,10 @@ static int if_spi_probe(struct spi_device *spi) /* Initialize interrupt handling stuff. */ card->workqueue = alloc_workqueue("libertas_spi", WQ_MEM_RECLAIM, 0); + if (!card->workqueue) { + err = -ENOMEM; + goto remove_card; + } INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); INIT_WORK(&card->resume_work, if_spi_resume_worker); @@ -1209,6 +1213,7 @@ release_irq: free_irq(spi->irq, card); terminate_workqueue: destroy_workqueue(card->workqueue); +remove_card: lbs_remove_card(priv); /* will call free_netdev */ free_card: free_if_spi_card(card); diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 54e426c1e405..d80333117989 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -641,6 +641,8 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) BIT(NL80211_IFTYPE_ADHOC); skb_queue_head_init(&priv->bc_ps_buf); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + SET_IEEE80211_DEV(hw, dmdev); INIT_WORK(&priv->cmd_work, lbtf_cmd_work); diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index 43dccd5b0291..366eb4991a7d 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -153,7 +153,8 @@ int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST); cmd->size = cpu_to_le16(S_DS_GEN); - le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_chan_rpt_req)); + le16_unaligned_add_cpu(&cmd->size, + sizeof(struct host_cmd_ds_chan_rpt_req)); cr_req->chan_desc.start_freq = cpu_to_le16(MWIFIEX_A_BAND_START_FREQ); cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value; diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 1e3bd435a694..7ec06bf13413 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -594,6 +594,24 @@ int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) return 0; } +static void mwifiex_reg_apply_radar_flags(struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + unsigned int i; + + if (!wiphy->bands[NL80211_BAND_5GHZ]) + return; + sband = wiphy->bands[NL80211_BAND_5GHZ]; + + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + if ((!(chan->flags & IEEE80211_CHAN_DISABLED)) && + (chan->flags & IEEE80211_CHAN_RADAR)) + chan->flags |= IEEE80211_CHAN_NO_IR; + } +} + /* * CFG802.11 regulatory domain callback function. * @@ -613,6 +631,7 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy, mwifiex_dbg(adapter, INFO, "info: cfg80211 regulatory domain callback for %c%c\n", request->alpha2[0], request->alpha2[1]); + mwifiex_reg_apply_radar_flags(wiphy); switch (request->initiator) { case NL80211_REGDOM_SET_BY_DRIVER: @@ -916,7 +935,7 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, static int mwifiex_change_vif_to_p2p(struct net_device *dev, enum nl80211_iftype curr_iftype, - enum nl80211_iftype type, u32 *flags, + enum nl80211_iftype type, struct vif_params *params) { struct mwifiex_private *priv; @@ -988,7 +1007,7 @@ mwifiex_change_vif_to_p2p(struct net_device *dev, static int mwifiex_change_vif_to_sta_adhoc(struct net_device *dev, enum nl80211_iftype curr_iftype, - enum nl80211_iftype type, u32 *flags, + enum nl80211_iftype type, struct vif_params *params) { struct mwifiex_private *priv; @@ -1047,7 +1066,7 @@ mwifiex_change_vif_to_sta_adhoc(struct net_device *dev, static int mwifiex_change_vif_to_ap(struct net_device *dev, enum nl80211_iftype curr_iftype, - enum nl80211_iftype type, u32 *flags, + enum nl80211_iftype type, struct vif_params *params) { struct mwifiex_private *priv; @@ -1103,7 +1122,7 @@ mwifiex_change_vif_to_ap(struct net_device *dev, static int mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, - enum nl80211_iftype type, u32 *flags, + enum nl80211_iftype type, struct vif_params *params) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); @@ -1124,10 +1143,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return mwifiex_change_vif_to_p2p(dev, curr_iftype, - type, flags, params); + type, params); case NL80211_IFTYPE_AP: return mwifiex_change_vif_to_ap(dev, curr_iftype, type, - flags, params); + params); case NL80211_IFTYPE_UNSPECIFIED: mwifiex_dbg(priv->adapter, INFO, "%s: kept type as IBSS\n", dev->name); @@ -1154,10 +1173,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return mwifiex_change_vif_to_p2p(dev, curr_iftype, - type, flags, params); + type, params); case NL80211_IFTYPE_AP: return mwifiex_change_vif_to_ap(dev, curr_iftype, type, - flags, params); + params); case NL80211_IFTYPE_UNSPECIFIED: mwifiex_dbg(priv->adapter, INFO, "%s: kept type as STA\n", dev->name); @@ -1175,13 +1194,12 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, - type, flags, - params); + type, params); break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return mwifiex_change_vif_to_p2p(dev, curr_iftype, - type, flags, params); + type, params); case NL80211_IFTYPE_UNSPECIFIED: mwifiex_dbg(priv->adapter, INFO, "%s: kept type as AP\n", dev->name); @@ -1214,14 +1232,13 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, if (mwifiex_cfg80211_deinit_p2p(priv)) return -EFAULT; return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, - type, flags, - params); + type, params); break; case NL80211_IFTYPE_AP: if (mwifiex_cfg80211_deinit_p2p(priv)) return -EFAULT; return mwifiex_change_vif_to_ap(dev, curr_iftype, type, - flags, params); + params); case NL80211_IFTYPE_UNSPECIFIED: mwifiex_dbg(priv->adapter, INFO, "%s: kept type as P2P\n", dev->name); @@ -2036,7 +2053,7 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (!mwifiex_stop_bg_scan(priv)) - cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy); + cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy, 0); if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; @@ -2304,7 +2321,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, (int)sme->ssid_len, (char *)sme->ssid, sme->bssid); if (!mwifiex_stop_bg_scan(priv)) - cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy); + cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy, 0); ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, priv->bss_mode, sme->channel, sme, 0); @@ -2513,7 +2530,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, priv->scan_block = false; if (!mwifiex_stop_bg_scan(priv)) - cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy); + cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy, 0); user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); if (!user_scan_cfg) @@ -2528,9 +2545,11 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, priv->random_mac[i] |= get_random_int() & ~(request->mac_addr_mask[i]); } + ether_addr_copy(user_scan_cfg->random_mac, priv->random_mac); + } else { + eth_zero_addr(priv->random_mac); } - ether_addr_copy(user_scan_cfg->random_mac, priv->random_mac); user_scan_cfg->num_ssids = request->n_ssids; user_scan_cfg->ssid_list = request->ssids; @@ -2701,7 +2720,7 @@ mwifiex_cfg80211_sched_scan_start(struct wiphy *wiphy, * previous bgscan configuration in the firmware */ static int mwifiex_cfg80211_sched_scan_stop(struct wiphy *wiphy, - struct net_device *dev) + struct net_device *dev, u64 reqid) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); @@ -2822,7 +2841,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, const char *name, unsigned char name_assign_type, enum nl80211_iftype type, - u32 *flags, struct vif_params *params) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); @@ -3997,8 +4015,8 @@ static int mwifiex_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, if (!priv) return -EINVAL; - err = nla_parse(tb, MWIFIEX_TM_ATTR_MAX, data, len, - mwifiex_tm_policy); + err = nla_parse(tb, MWIFIEX_TM_ATTR_MAX, data, len, mwifiex_tm_policy, + NULL); if (err) return err; @@ -4279,7 +4297,6 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | - WIPHY_FLAG_SUPPORTS_SCHED_SCAN | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAS_CHANNEL_SWITCH | WIPHY_FLAG_PS_ON_BY_DEFAULT; @@ -4298,6 +4315,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; + wiphy->max_sched_scan_reqs = 1; wiphy->max_sched_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH; wiphy->max_sched_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; wiphy->max_match_sets = MWIFIEX_MAX_SSID_LIST_LENGTH; diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 25a7475702f7..0c3b217247b1 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -242,7 +242,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, mwifiex_dbg(adapter, CMD, "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n", cmd_code, - le16_to_cpu(*(__le16 *)((u8 *)host_cmd + S_DS_GEN)), + get_unaligned_le16((u8 *)host_cmd + S_DS_GEN), cmd_size, le16_to_cpu(host_cmd->seq_num)); mwifiex_dbg_dump(adapter, CMD_D, "cmd buffer:", host_cmd, cmd_size); @@ -286,7 +286,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM; adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code; adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] = - le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)); + get_unaligned_le16((u8 *)host_cmd + S_DS_GEN); /* Clear BSS_NO_BITS from HostCmd */ cmd_code &= HostCmd_CMD_ID_MASK; diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index cb6a1a81d44e..6cf9ab9133ea 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -31,17 +31,35 @@ struct rfc_1042_hdr { u8 llc_ctrl; u8 snap_oui[3]; __be16 snap_type; -}; +} __packed; struct rx_packet_hdr { struct ethhdr eth803_hdr; struct rfc_1042_hdr rfc1042_hdr; -}; +} __packed; struct tx_packet_hdr { struct ethhdr eth803_hdr; struct rfc_1042_hdr rfc1042_hdr; -}; +} __packed; + +struct mwifiex_fw_header { + __le32 dnld_cmd; + __le32 base_addr; + __le32 data_length; + __le32 crc; +} __packed; + +struct mwifiex_fw_data { + struct mwifiex_fw_header header; + __le32 seq_num; + u8 data[1]; +} __packed; + +#define MWIFIEX_FW_DNLD_CMD_1 0x1 +#define MWIFIEX_FW_DNLD_CMD_5 0x5 +#define MWIFIEX_FW_DNLD_CMD_6 0x6 +#define MWIFIEX_FW_DNLD_CMD_7 0x7 #define B_SUPPORTED_RATES 5 #define G_SUPPORTED_RATES 9 @@ -707,7 +725,7 @@ struct uap_txpd { u8 reserved1[2]; u8 tx_token_id; u8 reserved[2]; -}; +} __packed; struct uap_rxpd { u8 bss_type; @@ -723,7 +741,7 @@ struct uap_rxpd { u8 ht_info; u8 reserved[3]; u8 flags; -}; +} __packed; struct mwifiex_fw_chan_stats { u8 chan_num; @@ -987,7 +1005,7 @@ struct mwifiex_ps_param { __le16 adhoc_wake_period; __le16 mode; __le16 delay_to_ps; -}; +} __packed; #define HS_DEF_WAKE_INTERVAL 100 #define HS_DEF_INACTIVITY_TIMEOUT 50 @@ -996,7 +1014,7 @@ struct mwifiex_ps_param_in_hs { struct mwifiex_ie_types_header header; __le32 hs_wake_int; __le32 hs_inact_timeout; -}; +} __packed; #define BITMAP_AUTO_DS 0x01 #define BITMAP_STA_PS 0x10 @@ -1062,7 +1080,7 @@ struct host_cmd_ds_802_11_rssi_info { __le16 nbcn; __le16 reserved[9]; long long reserved_1; -}; +} __packed; struct host_cmd_ds_802_11_rssi_info_rsp { __le16 action; @@ -1077,12 +1095,12 @@ struct host_cmd_ds_802_11_rssi_info_rsp { __le16 bcn_rssi_avg; __le16 bcn_nf_avg; long long tsf_bcn; -}; +} __packed; struct host_cmd_ds_802_11_mac_address { __le16 action; u8 mac_addr[ETH_ALEN]; -}; +} __packed; struct host_cmd_ds_mac_control { __le32 action; @@ -1230,7 +1248,7 @@ struct host_cmd_ds_802_11_get_log { __le32 wep_icv_err_cnt[4]; __le32 bcn_rcv_cnt; __le32 bcn_miss_cnt; -}; +} __packed; /* Enumeration for rate format */ enum _mwifiex_rate_format { @@ -1368,12 +1386,12 @@ struct host_cmd_ds_rf_ant_mimo { __le16 tx_ant_mode; __le16 action_rx; __le16 rx_ant_mode; -}; +} __packed; struct host_cmd_ds_rf_ant_siso { __le16 action; __le16 ant_mode; -}; +} __packed; struct host_cmd_ds_tdls_oper { __le16 tdls_action; @@ -1383,13 +1401,13 @@ struct host_cmd_ds_tdls_oper { struct mwifiex_tdls_config { __le16 enable; -}; +} __packed; struct mwifiex_tdls_config_cs_params { u8 unit_time; u8 thr_otherlink; u8 thr_directlink; -}; +} __packed; struct mwifiex_tdls_init_cs_params { u8 peer_mac[ETH_ALEN]; @@ -1404,7 +1422,7 @@ struct mwifiex_tdls_init_cs_params { struct mwifiex_tdls_stop_cs_params { u8 peer_mac[ETH_ALEN]; -}; +} __packed; struct host_cmd_ds_tdls_config { __le16 tdls_action; @@ -1709,7 +1727,7 @@ struct mwifiex_ie_types_local_pwr_constraint { struct mwifiex_ie_types_wmm_param_set { struct mwifiex_ie_types_header header; u8 wmm_ie[1]; -}; +} __packed; struct mwifiex_ie_types_mgmt_frame { struct mwifiex_ie_types_header header; @@ -1834,7 +1852,7 @@ struct host_cmd_ds_mem_access { __le16 reserved; __le32 addr; __le32 value; -}; +} __packed; struct mwifiex_ie_types_qos_info { struct mwifiex_ie_types_header header; diff --git a/drivers/net/wireless/marvell/mwifiex/ie.c b/drivers/net/wireless/marvell/mwifiex/ie.c index c488c3068abc..922e3d69fd84 100644 --- a/drivers/net/wireless/marvell/mwifiex/ie.c +++ b/drivers/net/wireless/marvell/mwifiex/ie.c @@ -131,9 +131,10 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv, sizeof(struct mwifiex_ie)); } - le16_add_cpu(&ie_list->len, - le16_to_cpu(priv->mgmt_ie[index].ie_length) + - MWIFIEX_IE_HDR_SIZE); + le16_unaligned_add_cpu(&ie_list->len, + le16_to_cpu( + priv->mgmt_ie[index].ie_length) + + MWIFIEX_IE_HDR_SIZE); input_len -= tlv_len + MWIFIEX_IE_HDR_SIZE; } @@ -172,21 +173,21 @@ mwifiex_update_uap_custom_ie(struct mwifiex_private *priv, le16_to_cpu(beacon_ie->ie_length); memcpy(pos, beacon_ie, len); pos += len; - le16_add_cpu(&ap_custom_ie->len, len); + le16_unaligned_add_cpu(&ap_custom_ie->len, len); } if (pr_ie) { len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE + le16_to_cpu(pr_ie->ie_length); memcpy(pos, pr_ie, len); pos += len; - le16_add_cpu(&ap_custom_ie->len, len); + le16_unaligned_add_cpu(&ap_custom_ie->len, len); } if (ar_ie) { len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE + le16_to_cpu(ar_ie->ie_length); memcpy(pos, ar_ie, len); pos += len; - le16_add_cpu(&ap_custom_ie->len, len); + le16_unaligned_add_cpu(&ap_custom_ie->len, len); } ret = mwifiex_update_autoindex_ies(priv, ap_custom_ie); @@ -242,7 +243,7 @@ static int mwifiex_update_vs_ie(const u8 *ies, int ies_len, vs_ie = (struct ieee_types_header *)vendor_ie; memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length), vs_ie, vs_ie->len + 2); - le16_add_cpu(&ie->ie_length, vs_ie->len + 2); + le16_unaligned_add_cpu(&ie->ie_length, vs_ie->len + 2); ie->mgmt_subtype_mask = cpu_to_le16(mask); ie->ie_index = cpu_to_le16(MWIFIEX_AUTO_IDX_MASK); } diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h index 536ab834b126..48e154e1865d 100644 --- a/drivers/net/wireless/marvell/mwifiex/ioctl.h +++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h @@ -91,6 +91,8 @@ struct wep_key { #define MWIFIEX_TDLS_DEF_QOS_CAPAB 0xf #define MWIFIEX_PRIO_BK 2 #define MWIFIEX_PRIO_VI 5 +#define MWIFIEX_SUPPORTED_CHANNELS 2 +#define MWIFIEX_OPERATING_CLASSES 16 struct mwifiex_uap_bss_param { u8 channel; diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index b62e03d11c2e..dd87b9ff64c3 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -17,6 +17,8 @@ * this warranty disclaimer. */ +#include <linux/suspend.h> + #include "main.h" #include "wmm.h" #include "cfg80211.h" @@ -147,7 +149,6 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) kfree(adapter->regd); - vfree(adapter->chan_stats); kfree(adapter); return 0; } @@ -511,7 +512,7 @@ static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) * - Download the correct firmware to card * - Issue the init commands to firmware */ -static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) +static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) { int ret; char fmt[64]; @@ -594,7 +595,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) rtnl_lock(); /* Create station interface by default */ wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM, - NL80211_IFTYPE_STATION, NULL, NULL); + NL80211_IFTYPE_STATION, NULL); if (IS_ERR(wdev)) { mwifiex_dbg(adapter, ERROR, "cannot create default STA interface\n"); @@ -604,7 +605,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) { wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM, - NL80211_IFTYPE_AP, NULL, NULL); + NL80211_IFTYPE_AP, NULL); if (IS_ERR(wdev)) { mwifiex_dbg(adapter, ERROR, "cannot create AP interface\n"); @@ -615,8 +616,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) { wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", NET_NAME_ENUM, - NL80211_IFTYPE_P2P_CLIENT, NULL, - NULL); + NL80211_IFTYPE_P2P_CLIENT, NULL); if (IS_ERR(wdev)) { mwifiex_dbg(adapter, ERROR, "cannot create p2p client interface\n"); @@ -631,6 +631,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: + vfree(adapter->chan_stats); wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); err_init_fw: @@ -664,11 +665,18 @@ done: mwifiex_free_adapter(adapter); /* Tell all current and future waiters we're finished */ complete_all(fw_done); - return; + + return init_failed ? -EIO : 0; +} + +static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) +{ + _mwifiex_fw_dpc(firmware, context); } /* - * This function initializes the hardware and gets firmware. + * This function gets the firmware and (if called asynchronously) kicks off the + * HW init when done. */ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter, bool req_fw_nowait) @@ -691,20 +699,15 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter, ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name, adapter->dev, GFP_KERNEL, adapter, mwifiex_fw_dpc); - if (ret < 0) - mwifiex_dbg(adapter, ERROR, - "request_firmware_nowait error %d\n", ret); } else { ret = request_firmware(&adapter->firmware, adapter->fw_name, adapter->dev); - if (ret < 0) - mwifiex_dbg(adapter, ERROR, - "request_firmware error %d\n", ret); - else - mwifiex_fw_dpc(adapter->firmware, (void *)adapter); } + if (ret < 0) + mwifiex_dbg(adapter, ERROR, "request_firmware%s error %d\n", + req_fw_nowait ? "_nowait" : "", ret); return ret; } @@ -745,7 +748,7 @@ mwifiex_close(struct net_device *dev) mwifiex_dbg(priv->adapter, INFO, "aborting bgscan on ndo_stop\n"); mwifiex_stop_bg_scan(priv); - cfg80211_sched_scan_stopped(priv->wdev.wiphy); + cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0); } return 0; @@ -1413,6 +1416,7 @@ mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); rtnl_unlock(); } + vfree(adapter->chan_stats); mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); exit_return: @@ -1426,6 +1430,8 @@ EXPORT_SYMBOL_GPL(mwifiex_shutdown_sw); int mwifiex_reinit_sw(struct mwifiex_adapter *adapter) { + int ret; + mwifiex_init_lock_list(adapter); if (adapter->if_ops.up_dev) adapter->if_ops.up_dev(adapter); @@ -1435,6 +1441,7 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter) init_waitqueue_head(&adapter->init_wait_q); adapter->is_suspended = false; adapter->hs_activated = false; + adapter->is_cmd_timedout = 0; init_waitqueue_head(&adapter->hs_activate_wait_q); init_waitqueue_head(&adapter->cmd_wait_q.wait); adapter->cmd_wait_q.status = 0; @@ -1472,9 +1479,15 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter) "%s: firmware init failed\n", __func__); goto err_init_fw; } + + /* _mwifiex_fw_dpc() does its own cleanup */ + ret = _mwifiex_fw_dpc(adapter->firmware, adapter); + if (ret) { + pr_err("Failed to bring up adapter: %d\n", ret); + return ret; + } mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); - complete_all(adapter->fw_done); return 0; err_init_fw: @@ -1502,14 +1515,13 @@ static irqreturn_t mwifiex_irq_wakeup_handler(int irq, void *priv) { struct mwifiex_adapter *adapter = priv; - if (adapter->irq_wakeup >= 0) { - dev_dbg(adapter->dev, "%s: wake by wifi", __func__); - adapter->wake_by_wifi = true; - disable_irq_nosync(irq); - } + dev_dbg(adapter->dev, "%s: wake by wifi", __func__); + adapter->wake_by_wifi = true; + disable_irq_nosync(irq); /* Notify PM core we are wakeup source */ pm_wakeup_event(adapter->dev, 0); + pm_system_wakeup(); return IRQ_HANDLED; } @@ -1714,6 +1726,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter) mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); rtnl_unlock(); } + vfree(adapter->chan_stats); wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); @@ -1742,7 +1755,7 @@ void _mwifiex_dbg(const struct mwifiex_adapter *adapter, int mask, struct va_format vaf; va_list args; - if (!adapter->dev || !(adapter->debug_mask & mask)) + if (!(adapter->debug_mask & mask)) return; va_start(args, fmt); @@ -1750,7 +1763,10 @@ void _mwifiex_dbg(const struct mwifiex_adapter *adapter, int mask, vaf.fmt = fmt; vaf.va = &args; - dev_info(adapter->dev, "%pV", &vaf); + if (adapter->dev) + dev_info(adapter->dev, "%pV", &vaf); + else + pr_info("%pV", &vaf); va_end(args); } diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 5c8297207f33..bb2a467d8b13 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -1359,7 +1359,7 @@ mwifiex_netdev_get_priv(struct net_device *dev) */ static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb) { - return (le32_to_cpu(*(__le32 *)skb->data) == PKT_TYPE_MGMT); + return (get_unaligned_le32(skb->data) == PKT_TYPE_MGMT); } /* This function retrieves channel closed for operation by Channel @@ -1529,7 +1529,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, const char *name, unsigned char name_assign_type, enum nl80211_iftype type, - u32 *flags, struct vif_params *params); int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index b8c990d10d6e..ac62bce50e96 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -119,7 +119,7 @@ static int mwifiex_read_reg_byte(struct mwifiex_adapter *adapter, */ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) { - u32 *cookie_addr; + u32 cookie_value; struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; @@ -127,11 +127,11 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) return true; if (card->sleep_cookie_vbase) { - cookie_addr = (u32 *)card->sleep_cookie_vbase; + cookie_value = get_unaligned_le32(card->sleep_cookie_vbase); mwifiex_dbg(adapter, INFO, "info: ACCESS_HW: sleep cookie=0x%x\n", - *cookie_addr); - if (*cookie_addr == FW_AWAKE_COOKIE) + cookie_value); + if (cookie_value == FW_AWAKE_COOKIE) return true; } @@ -294,8 +294,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) if (!adapter || !adapter->priv_num) return; - cancel_work_sync(&card->work); - reg = card->pcie.reg; if (reg) ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status); @@ -350,22 +348,16 @@ MODULE_DEVICE_TABLE(pci, mwifiex_ids); static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) { - struct mwifiex_adapter *adapter; - struct pcie_service_card *card; - - if (!pdev) { - pr_err("%s: PCIe device is not specified\n", __func__); - return; - } + struct pcie_service_card *card = pci_get_drvdata(pdev); + struct mwifiex_adapter *adapter = card->adapter; + int ret; - card = (struct pcie_service_card *)pci_get_drvdata(pdev); - if (!card || !card->adapter) { - pr_err("%s: Card or adapter structure is not valid (%ld)\n", - __func__, (long)card); + if (!adapter) { + dev_err(&pdev->dev, "%s: adapter structure is not valid\n", + __func__); return; } - adapter = card->adapter; mwifiex_dbg(adapter, INFO, "%s: vendor=0x%4.04x device=0x%4.04x rev=%d %s\n", __func__, pdev->vendor, pdev->device, @@ -379,13 +371,19 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) */ mwifiex_shutdown_sw(adapter); adapter->surprise_removed = true; + clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); + clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); } else { /* Kernel stores and restores PCIe function context before and * after performing FLR respectively. Reconfigure the software * and firmware including firmware redownload */ adapter->surprise_removed = false; - mwifiex_reinit_sw(adapter); + ret = mwifiex_reinit_sw(adapter); + if (ret) { + dev_err(&pdev->dev, "reinit failed: %d\n", ret); + return; + } } mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); } @@ -447,7 +445,7 @@ static void mwifiex_delay_for_sleep_cookie(struct mwifiex_adapter *adapter, sizeof(sleep_cookie), PCI_DMA_FROMDEVICE); buffer = cmdrsp->data; - sleep_cookie = READ_ONCE(*(u32 *)buffer); + sleep_cookie = get_unaligned_le32(buffer); if (sleep_cookie == MWIFIEX_DEF_SLEEP_COOKIE) { mwifiex_dbg(adapter, INFO, @@ -1039,6 +1037,7 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) if (card && card->cmd_buf) { mwifiex_unmap_pci_memory(adapter, card->cmd_buf, PCI_DMA_TODEVICE); + dev_kfree_skb_any(card->cmd_buf); } return 0; } @@ -1049,6 +1048,7 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; + u32 tmp; card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32), &card->sleep_cookie_pbase); @@ -1058,11 +1058,12 @@ static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter) return -ENOMEM; } /* Init val of Sleep Cookie */ - *(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE; + tmp = FW_AWAKE_COOKIE; + put_unaligned(tmp, card->sleep_cookie_vbase); mwifiex_dbg(adapter, INFO, "alloc_scook: sleep cookie=0x%x\n", - *((u32 *)card->sleep_cookie_vbase)); + get_unaligned(card->sleep_cookie_vbase)); return 0; } @@ -1223,7 +1224,6 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, dma_addr_t buf_pa; struct mwifiex_pcie_buf_desc *desc = NULL; struct mwifiex_pfu_buf_desc *desc2 = NULL; - __le16 *tmp; if (!(skb->data && skb->len)) { mwifiex_dbg(adapter, ERROR, @@ -1244,10 +1244,8 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb, adapter->data_sent = true; payload = skb->data; - tmp = (__le16 *)&payload[0]; - *tmp = cpu_to_le16((u16)skb->len); - tmp = (__le16 *)&payload[2]; - *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA); + put_unaligned_le16((u16)skb->len, payload + 0); + put_unaligned_le16(MWIFIEX_TYPE_DATA, payload + 2); if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE)) @@ -1376,7 +1374,6 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) (card->rxbd_rdptr & reg->rx_rollover_ind))) { struct sk_buff *skb_data; u16 rx_len; - __le16 pkt_len; rd_index = card->rxbd_rdptr & reg->rx_mask; skb_data = card->rx_buf_list[rd_index]; @@ -1393,8 +1390,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) /* Get data length from interface header - * first 2 bytes for len, next 2 bytes is for type */ - pkt_len = *((__le16 *)skb_data->data); - rx_len = le16_to_cpu(pkt_len); + rx_len = get_unaligned_le16(skb_data->data); if (WARN_ON(rx_len <= INTF_HEADER_LEN || rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) { mwifiex_dbg(adapter, ERROR, @@ -1601,13 +1597,18 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) adapter->cmd_sent = true; - *(__le16 *)&payload[0] = cpu_to_le16((u16)skb->len); - *(__le16 *)&payload[2] = cpu_to_le16(MWIFIEX_TYPE_CMD); + put_unaligned_le16((u16)skb->len, &payload[0]); + put_unaligned_le16(MWIFIEX_TYPE_CMD, &payload[2]); if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE)) return -1; card->cmd_buf = skb; + /* + * Need to keep a reference, since core driver might free up this + * buffer before we've unmapped it. + */ + skb_get(skb); /* To send a command, the driver will: 1. Write the 64bit physical address of the data buffer to @@ -1694,7 +1695,6 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) struct sk_buff *skb = card->cmdrsp_buf; int count = 0; u16 rx_len; - __le16 pkt_len; mwifiex_dbg(adapter, CMD, "info: Rx CMD Response\n"); @@ -1711,11 +1711,11 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) if (card->cmd_buf) { mwifiex_unmap_pci_memory(adapter, card->cmd_buf, PCI_DMA_TODEVICE); + dev_kfree_skb_any(card->cmd_buf); card->cmd_buf = NULL; } - pkt_len = *((__le16 *)skb->data); - rx_len = le16_to_cpu(pkt_len); + rx_len = get_unaligned_le16(skb->data); skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len); skb_trim(skb, rx_len); @@ -1856,7 +1856,7 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) desc = card->evtbd_ring[rdptr]; memset(desc, 0, sizeof(*desc)); - event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN]; + event = get_unaligned_le32(&skb_cmd->data[INTF_HEADER_LEN]); adapter->event_cause = event; /* The first 4bytes will be the event transfer header len is 2 bytes followed by type which is 2 bytes */ @@ -1965,6 +1965,94 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, return ret; } +/* Combo firmware image is a combination of + * (1) combo crc heaer, start with CMD5 + * (2) bluetooth image, start with CMD7, end with CMD6, data wrapped in CMD1. + * (3) wifi image. + * + * This function bypass the header and bluetooth part, return + * the offset of tail wifi-only part. + */ + +static int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter, + const void *firmware, u32 firmware_len) { + const struct mwifiex_fw_data *fwdata; + u32 offset = 0, data_len, dnld_cmd; + int ret = 0; + bool cmd7_before = false; + + while (1) { + /* Check for integer and buffer overflow */ + if (offset + sizeof(fwdata->header) < sizeof(fwdata->header) || + offset + sizeof(fwdata->header) >= firmware_len) { + mwifiex_dbg(adapter, ERROR, + "extract wifi-only fw failure!\n"); + ret = -1; + goto done; + } + + fwdata = firmware + offset; + dnld_cmd = le32_to_cpu(fwdata->header.dnld_cmd); + data_len = le32_to_cpu(fwdata->header.data_length); + + /* Skip past header */ + offset += sizeof(fwdata->header); + + switch (dnld_cmd) { + case MWIFIEX_FW_DNLD_CMD_1: + if (!cmd7_before) { + mwifiex_dbg(adapter, ERROR, + "no cmd7 before cmd1!\n"); + ret = -1; + goto done; + } + if (offset + data_len < data_len) { + mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); + ret = -1; + goto done; + } + offset += data_len; + break; + case MWIFIEX_FW_DNLD_CMD_5: + /* Check for integer overflow */ + if (offset + data_len < data_len) { + mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); + ret = -1; + goto done; + } + offset += data_len; + break; + case MWIFIEX_FW_DNLD_CMD_6: + /* Check for integer overflow */ + if (offset + data_len < data_len) { + mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); + ret = -1; + goto done; + } + offset += data_len; + if (offset >= firmware_len) { + mwifiex_dbg(adapter, ERROR, + "extract wifi-only fw failure!\n"); + ret = -1; + } else { + ret = offset; + } + goto done; + case MWIFIEX_FW_DNLD_CMD_7: + cmd7_before = true; + break; + default: + mwifiex_dbg(adapter, ERROR, "unknown dnld_cmd %d\n", + dnld_cmd); + ret = -1; + goto done; + } + } + +done: + return ret; +} + /* * This function downloads the firmware to the card. * @@ -1980,7 +2068,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, u32 firmware_len = fw->fw_len; u32 offset = 0; struct sk_buff *skb; - u32 txlen, tx_blocks = 0, tries, len; + u32 txlen, tx_blocks = 0, tries, len, val; u32 block_retry_cnt = 0; struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; @@ -2007,6 +2095,24 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, goto done; } + ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_13_REG, &val); + if (ret) { + mwifiex_dbg(adapter, FATAL, "Failed to read scratch register 13\n"); + goto done; + } + + /* PCIE FLR case: extract wifi part from combo firmware*/ + if (val == MWIFIEX_PCIE_FLR_HAPPENS) { + ret = mwifiex_extract_wifi_fw(adapter, firmware, firmware_len); + if (ret < 0) { + mwifiex_dbg(adapter, ERROR, "Failed to extract wifi fw\n"); + goto done; + } + offset = ret; + mwifiex_dbg(adapter, MSG, + "info: dnld wifi firmware from %d bytes\n", offset); + } + /* Perform firmware data transfer */ do { u32 ireg_intr = 0; @@ -2503,8 +2609,8 @@ mwifiex_pcie_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf) struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; int pcie_scratch_reg[] = {PCIE_SCRATCH_12_REG, - PCIE_SCRATCH_13_REG, - PCIE_SCRATCH_14_REG}; + PCIE_SCRATCH_14_REG, + PCIE_SCRATCH_15_REG}; if (!p) return 0; @@ -2874,6 +2980,8 @@ static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter) int ret; u32 fw_status; + cancel_work_sync(&card->work); + ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status); if (fw_status == FIRMWARE_READY_PCIE) { mwifiex_dbg(adapter, INFO, @@ -3077,12 +3185,6 @@ static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter) struct pci_dev *pdev = card->dev; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - /* Bluetooth is not on pcie interface. Download Wifi only firmware - * during pcie FLR, so that bluetooth part of firmware which is - * already running doesn't get affected. - */ - strcpy(adapter->fw_name, PCIE8997_DEFAULT_WIFIFW_NAME); - /* tx_buf_size might be changed to 3584 by firmware during * data transfer, we should reset it to default size. */ diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 00e8ee5ad4a8..f7ce9b6db6b4 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -35,7 +35,6 @@ #define PCIE8897_B0_FW_NAME "mrvl/pcie8897_uapsta.bin" #define PCIEUART8997_FW_NAME_V4 "mrvl/pcieuart8997_combo_v4.bin" #define PCIEUSB8997_FW_NAME_V4 "mrvl/pcieusb8997_combo_v4.bin" -#define PCIE8997_DEFAULT_WIFIFW_NAME "mrvl/pcie8997_wlan_v4.bin" #define PCIE_VENDOR_ID_MARVELL (0x11ab) #define PCIE_VENDOR_ID_V2_MARVELL (0x1b4b) @@ -77,8 +76,9 @@ #define PCIE_SCRATCH_10_REG 0xCE8 #define PCIE_SCRATCH_11_REG 0xCEC #define PCIE_SCRATCH_12_REG 0xCF0 -#define PCIE_SCRATCH_13_REG 0xCF8 -#define PCIE_SCRATCH_14_REG 0xCFC +#define PCIE_SCRATCH_13_REG 0xCF4 +#define PCIE_SCRATCH_14_REG 0xCF8 +#define PCIE_SCRATCH_15_REG 0xCFC #define PCIE_RD_DATA_PTR_Q0_Q1 0xC08C #define PCIE_WR_DATA_PTR_Q0_Q1 0xC05C @@ -119,6 +119,8 @@ #define MWIFIEX_SLEEP_COOKIE_SIZE 4 #define MWIFIEX_MAX_DELAY_COUNT 100 +#define MWIFIEX_PCIE_FLR_HAPPENS 0xFEDCBABA + struct mwifiex_pcie_card_reg { u16 cmd_addr_lo; u16 cmd_addr_hi; @@ -217,8 +219,8 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, .pfu_enabled = 1, .sleep_cookie = 0, - .fw_dump_ctrl = 0xcf4, - .fw_dump_start = 0xcf8, + .fw_dump_ctrl = PCIE_SCRATCH_13_REG, + .fw_dump_start = PCIE_SCRATCH_14_REG, .fw_dump_end = 0xcff, .fw_dump_host_ready = 0xee, .fw_dump_read_done = 0xfe, @@ -254,8 +256,8 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, .pfu_enabled = 1, .sleep_cookie = 0, - .fw_dump_ctrl = 0xcf4, - .fw_dump_start = 0xcf8, + .fw_dump_ctrl = PCIE_SCRATCH_13_REG, + .fw_dump_start = PCIE_SCRATCH_14_REG, .fw_dump_end = 0xcff, .fw_dump_host_ready = 0xcc, .fw_dump_read_done = 0xdd, diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 181691684a08..ce6936d0c5c0 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -691,8 +691,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, /* Increment the TLV header length by the size appended */ - le16_add_cpu(&chan_tlv_out->header.len, - sizeof(chan_tlv_out->chan_scan_param)); + le16_unaligned_add_cpu(&chan_tlv_out->header.len, + sizeof( + chan_tlv_out->chan_scan_param)); /* * The tlv buffer length is set to the number of bytes @@ -859,6 +860,7 @@ mwifiex_config_scan(struct mwifiex_private *priv, *scan_current_only = false; if (user_scan_in) { + u8 tmpaddr[ETH_ALEN]; /* Default the ssid_filter flag to TRUE, set false under certain wildcard conditions and qualified by the existence @@ -883,8 +885,10 @@ mwifiex_config_scan(struct mwifiex_private *priv, user_scan_in->specific_bssid, sizeof(scan_cfg_out->specific_bssid)); + memcpy(tmpaddr, scan_cfg_out->specific_bssid, ETH_ALEN); + if (adapter->ext_scan && - !is_zero_ether_addr(scan_cfg_out->specific_bssid)) { + !is_zero_ether_addr(tmpaddr)) { bssid_tlv = (struct mwifiex_ie_types_bssid_list *)tlv_pos; bssid_tlv->header.type = cpu_to_le16(TLV_TYPE_BSSID); @@ -947,8 +951,9 @@ mwifiex_config_scan(struct mwifiex_private *priv, * truncate scan results. That is not an issue with an SSID * or BSSID filter applied to the scan results in the firmware. */ + memcpy(tmpaddr, scan_cfg_out->specific_bssid, ETH_ALEN); if ((i && ssid_filter) || - !is_zero_ether_addr(scan_cfg_out->specific_bssid)) + !is_zero_ether_addr(tmpaddr)) *filtered_scan = true; if (user_scan_in->scan_chan_gap) { @@ -989,10 +994,15 @@ mwifiex_config_scan(struct mwifiex_private *priv, * If a specific BSSID or SSID is used, the number of channels in the * scan command will be increased to the absolute maximum. */ - if (*filtered_scan) + if (*filtered_scan) { *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; - else - *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD; + } else { + if (!priv->media_connected) + *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD; + else + *max_chan_per_scan = + MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD / 2; + } if (adapter->ext_scan) { bss_mode = (struct mwifiex_ie_types_bss_mode *)tlv_pos; @@ -1742,7 +1752,7 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, if (*bytes_left >= sizeof(beacon_size)) { /* Extract & convert beacon size from command buffer */ - beacon_size = le16_to_cpu(*(__le16 *)(*bss_info)); + beacon_size = get_unaligned_le16((*bss_info)); *bytes_left -= sizeof(beacon_size); *bss_info += sizeof(beacon_size); } @@ -2369,8 +2379,9 @@ int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, temp_chan = chan_list_tlv->chan_scan_param + chan_idx; /* Increment the TLV header length by size appended */ - le16_add_cpu(&chan_list_tlv->header.len, - sizeof(chan_list_tlv->chan_scan_param)); + le16_unaligned_add_cpu(&chan_list_tlv->header.len, + sizeof( + chan_list_tlv->chan_scan_param)); temp_chan->chan_number = bgscan_cfg_in->chan_list[chan_idx].chan_number; @@ -2407,8 +2418,8 @@ int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, mwifiex_bgscan_create_channel_list(priv, bgscan_cfg_in, chan_list_tlv-> chan_scan_param); - le16_add_cpu(&chan_list_tlv->header.len, - chan_num * + le16_unaligned_add_cpu(&chan_list_tlv->header.len, + chan_num * sizeof(chan_list_tlv->chan_scan_param[0])); } @@ -2432,7 +2443,7 @@ int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, /* Append vendor specific IE TLV */ mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_BGSCAN, &tlv_pos); - le16_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv); + le16_unaligned_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv); return 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index a4b356d267f9..0af1c6733c92 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -387,8 +387,6 @@ mwifiex_sdio_remove(struct sdio_func *func) if (!adapter || !adapter->priv_num) return; - cancel_work_sync(&card->work); - mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num); ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); @@ -943,7 +941,7 @@ static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, return -1; } - nb = le16_to_cpu(*(__le16 *) (buffer)); + nb = get_unaligned_le16((buffer)); if (nb > npayload) { mwifiex_dbg(adapter, ERROR, "%s: invalid packet, nb=%d npayload=%d\n", @@ -951,7 +949,7 @@ static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, return -1; } - *type = le16_to_cpu(*(__le16 *) (buffer + 2)); + *type = get_unaligned_le16((buffer + 2)); return ret; } @@ -1139,7 +1137,8 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, __func__, blk_num, blk_size, total_pkt_len); break; } - pkt_len = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET)); + pkt_len = get_unaligned_le16((data + + SDIO_HEADER_OFFSET)); if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) { mwifiex_dbg(adapter, ERROR, "%s: error in pkt_len,\t" @@ -1172,10 +1171,11 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb, u32 upld_typ) { u8 *cmd_buf; - __le16 *curr_ptr = (__le16 *)skb->data; - u16 pkt_len = le16_to_cpu(*curr_ptr); + u16 pkt_len; struct mwifiex_rxinfo *rx_info; + pkt_len = get_unaligned_le16(skb->data); + if (upld_typ != MWIFIEX_TYPE_AGGR_DATA) { skb_trim(skb, pkt_len); skb_pull(skb, INTF_HEADER_LEN); @@ -1235,7 +1235,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, case MWIFIEX_TYPE_EVENT: mwifiex_dbg(adapter, EVENT, "info: --- Rx: Event ---\n"); - adapter->event_cause = le32_to_cpu(*(__le32 *) skb->data); + adapter->event_cause = get_unaligned_le32(skb->data); if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) memcpy(adapter->event_body, @@ -1380,7 +1380,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, } if (card->mpa_rx.pkt_cnt == 1) - mport = adapter->ioport + port; + mport = adapter->ioport + card->mpa_rx.start_port; if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, card->mpa_rx.buf_len, mport, 1)) @@ -1392,8 +1392,8 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, u32 *len_arr = card->mpa_rx.len_arr; /* get curr PKT len & type */ - pkt_len = le16_to_cpu(*(__le16 *) &curr_ptr[0]); - pkt_type = le16_to_cpu(*(__le16 *) &curr_ptr[2]); + pkt_len = get_unaligned_le16(&curr_ptr[0]); + pkt_type = get_unaligned_le16(&curr_ptr[2]); /* copy pkt to deaggr buf */ skb_deaggr = mwifiex_alloc_dma_align_buf(len_arr[pind], @@ -1813,7 +1813,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, } if (card->mpa_tx.pkt_cnt == 1) - mport = adapter->ioport + port; + mport = adapter->ioport + card->mpa_tx.start_port; ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, card->mpa_tx.buf_len, mport); @@ -1874,8 +1874,9 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, /* Allocate buffer and copy payload */ blk_size = MWIFIEX_SDIO_BLOCK_SIZE; buf_block_len = (pkt_len + blk_size - 1) / blk_size; - *(__le16 *)&payload[0] = cpu_to_le16((u16)pkt_len); - *(__le16 *)&payload[2] = cpu_to_le16(type); + put_unaligned_le16((u16)pkt_len, payload + 0); + put_unaligned_le16((u32)type, payload + 2); + /* * This is SDIO specific header @@ -2155,6 +2156,8 @@ static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; + cancel_work_sync(&card->work); + kfree(card->mp_regs); kfree(card->mpa_rx.skb_arr); kfree(card->mpa_rx.len_arr); @@ -2193,6 +2196,7 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; struct sdio_func *func = card->func; + int ret; mwifiex_shutdown_sw(adapter); @@ -2207,7 +2211,9 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); - mwifiex_reinit_sw(adapter); + ret = mwifiex_reinit_sw(adapter); + if (ret) + dev_err(&func->dev, "reinit failed: %d\n", ret); } /* This function read/write firmware */ diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 2f1f4d190b28..83916c1439af 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -126,19 +126,19 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, if (cmd_action == HostCmd_ACT_GEN_GET) { snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET); snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE); - le16_add_cpu(&cmd->size, MAX_SNMP_BUF_SIZE); + le16_unaligned_add_cpu(&cmd->size, MAX_SNMP_BUF_SIZE); } else if (cmd_action == HostCmd_ACT_GEN_SET) { snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); - *((__le16 *) (snmp_mib->value)) = cpu_to_le16(*ul_temp); - le16_add_cpu(&cmd->size, sizeof(u16)); + put_unaligned_le16(*ul_temp, snmp_mib->value); + le16_unaligned_add_cpu(&cmd->size, sizeof(u16)); } mwifiex_dbg(priv->adapter, CMD, "cmd: SNMP_CMD: Action=0x%x, OID=0x%x,\t" "OIDSize=0x%x, Value=0x%x\n", cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size), - le16_to_cpu(*(__le16 *)snmp_mib->value)); + get_unaligned_le16(snmp_mib->value)); return 0; } @@ -1357,8 +1357,9 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv, subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq); pos += sizeof(struct mwifiex_ie_types_rssi_threshold); - le16_add_cpu(&cmd->size, - sizeof(struct mwifiex_ie_types_rssi_threshold)); + le16_unaligned_add_cpu(&cmd->size, + sizeof( + struct mwifiex_ie_types_rssi_threshold)); } if (event_bitmap & BITMASK_BCN_RSSI_HIGH) { @@ -1378,8 +1379,9 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv, subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq); pos += sizeof(struct mwifiex_ie_types_rssi_threshold); - le16_add_cpu(&cmd->size, - sizeof(struct mwifiex_ie_types_rssi_threshold)); + le16_unaligned_add_cpu(&cmd->size, + sizeof( + struct mwifiex_ie_types_rssi_threshold)); } return 0; @@ -1398,7 +1400,7 @@ mwifiex_cmd_append_rpn_expression(struct mwifiex_private *priv, filter = &mef_entry->filter[i]; if (!filter->filt_type) break; - *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->repeat); + put_unaligned_le32((u32)filter->repeat, stack_ptr); stack_ptr += 4; *stack_ptr = TYPE_DNUM; stack_ptr += 1; @@ -1410,8 +1412,7 @@ mwifiex_cmd_append_rpn_expression(struct mwifiex_private *priv, stack_ptr += 1; *stack_ptr = TYPE_BYTESEQ; stack_ptr += 1; - - *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->offset); + put_unaligned_le32((u32)filter->offset, stack_ptr); stack_ptr += 4; *stack_ptr = TYPE_DNUM; stack_ptr += 1; @@ -1683,14 +1684,15 @@ mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv, sizeof(u8) + sizeof(u8)); /* Add the rule length to the command size*/ - le16_add_cpu(&cmd->size, le16_to_cpu(rule->header.len) + - sizeof(struct mwifiex_ie_types_header)); + le16_unaligned_add_cpu(&cmd->size, + le16_to_cpu(rule->header.len) + + sizeof(struct mwifiex_ie_types_header)); rule = (void *)((u8 *)rule->params + length); } /* Add sizeof action, num_of_rules to total command length */ - le16_add_cpu(&cmd->size, sizeof(u16) + sizeof(u16)); + le16_unaligned_add_cpu(&cmd->size, sizeof(u16) + sizeof(u16)); return 0; } @@ -1708,7 +1710,7 @@ mwifiex_cmd_tdls_config(struct mwifiex_private *priv, cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_CONFIG); cmd->size = cpu_to_le16(S_DS_GEN); tdls_config->tdls_action = cpu_to_le16(cmd_action); - le16_add_cpu(&cmd->size, sizeof(tdls_config->tdls_action)); + le16_unaligned_add_cpu(&cmd->size, sizeof(tdls_config->tdls_action)); switch (cmd_action) { case ACT_TDLS_CS_ENABLE_CONFIG: @@ -1735,7 +1737,7 @@ mwifiex_cmd_tdls_config(struct mwifiex_private *priv, return -ENOTSUPP; } - le16_add_cpu(&cmd->size, len); + le16_unaligned_add_cpu(&cmd->size, len); return 0; } @@ -1759,7 +1761,8 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_OPER); cmd->size = cpu_to_le16(S_DS_GEN); - le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_tdls_oper)); + le16_unaligned_add_cpu(&cmd->size, + sizeof(struct host_cmd_ds_tdls_oper)); tdls_oper->reason = 0; memcpy(tdls_oper->peer_mac, oper->peer_mac, ETH_ALEN); @@ -1783,7 +1786,7 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, return -ENODATA; } - *(__le16 *)pos = cpu_to_le16(params->capability); + put_unaligned_le16(params->capability, pos); config_len += sizeof(params->capability); qos_info = params->uapsd_queues | (params->max_sp << 5); @@ -1861,7 +1864,7 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, return -ENOTSUPP; } - le16_add_cpu(&cmd->size, config_len); + le16_unaligned_add_cpu(&cmd->size, config_len); return 0; } @@ -2032,7 +2035,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_VERSION_EXT: cmd_ptr->command = cpu_to_le16(cmd_no); cmd_ptr->params.verext.version_str_sel = - (u8) (*((u32 *) data_buf)); + (u8)(get_unaligned((u32 *)data_buf)); memcpy(&cmd_ptr->params, data_buf, sizeof(struct host_cmd_ds_version_ext)); cmd_ptr->size = @@ -2043,7 +2046,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_MGMT_FRAME_REG: cmd_ptr->command = cpu_to_le16(cmd_no); cmd_ptr->params.reg_mask.action = cpu_to_le16(cmd_action); - cmd_ptr->params.reg_mask.mask = cpu_to_le32(*(u32 *)data_buf); + cmd_ptr->params.reg_mask.mask = cpu_to_le32( + get_unaligned((u32 *)data_buf)); cmd_ptr->size = cpu_to_le16(sizeof(struct host_cmd_ds_mgmt_frame_reg) + S_DS_GEN); @@ -2063,7 +2067,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_P2P_MODE_CFG: cmd_ptr->command = cpu_to_le16(cmd_no); cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action); - cmd_ptr->params.mode_cfg.mode = cpu_to_le16(*(u16 *)data_buf); + cmd_ptr->params.mode_cfg.mode = cpu_to_le16( + get_unaligned((u16 *)data_buf)); cmd_ptr->size = cpu_to_le16(sizeof(struct host_cmd_ds_p2p_mode_cfg) + S_DS_GEN); @@ -2359,8 +2364,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) if (ret) return -1; - if (!disable_auto_ds && - first_sta && priv->adapter->iface_type != MWIFIEX_USB && + if (!disable_auto_ds && first_sta && priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { /* Enable auto deep sleep */ auto_ds.auto_ds = DEEP_SLEEP_ON; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index 8548027abf71..f1d1f56fc23f 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -183,7 +183,7 @@ static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, "query_type = %#x, buf size = %#x\n", oid, query_type, le16_to_cpu(smib->buf_size)); if (query_type == HostCmd_ACT_GEN_GET) { - ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); + ul_temp = get_unaligned_le16(smib->value); if (data_buf) *data_buf = ul_temp; switch (oid) { @@ -741,7 +741,7 @@ mwifiex_ret_p2p_mode_cfg(struct mwifiex_private *priv, struct host_cmd_ds_p2p_mode_cfg *mode_cfg = &resp->params.mode_cfg; if (data_buf) - *((u16 *)data_buf) = le16_to_cpu(mode_cfg->mode); + put_unaligned_le16(le16_to_cpu(mode_cfg->mode), data_buf); return 0; } @@ -1201,7 +1201,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_802_11_BG_SCAN_QUERY: ret = mwifiex_ret_802_11_scan(priv, resp); - cfg80211_sched_scan_results(priv->wdev.wiphy); + cfg80211_sched_scan_results(priv->wdev.wiphy, 0); mwifiex_dbg(adapter, CMD, "info: CMD_RESP: BG_SCAN result is ready!\n"); break; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index d63d163eb1ec..839df8a9634e 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -670,7 +670,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->dbg.num_event_deauth++; if (priv->media_connected) { reason_code = - le16_to_cpu(*(__le16 *)adapter->event_body); + get_unaligned_le16(adapter->event_body); mwifiex_reset_connect_state(priv, reason_code, true); } break; @@ -685,7 +685,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->dbg.num_event_disassoc++; if (priv->media_connected) { reason_code = - le16_to_cpu(*(__le16 *)adapter->event_body); + get_unaligned_le16(adapter->event_body); mwifiex_reset_connect_state(priv, reason_code, true); } break; @@ -695,7 +695,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->dbg.num_event_link_lost++; if (priv->media_connected) { reason_code = - le16_to_cpu(*(__le16 *)adapter->event_body); + get_unaligned_le16(adapter->event_body); mwifiex_reset_connect_state(priv, reason_code, true); } break; @@ -793,7 +793,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_BG_SCAN_STOPPED: dev_dbg(adapter->dev, "event: BGS_STOPPED\n"); - cfg80211_sched_scan_stopped(priv->wdev.wiphy); + cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0); if (priv->sched_scanning) priv->sched_scanning = false; break; @@ -923,7 +923,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->event_body); break; case EVENT_AMSDU_AGGR_CTRL: - ctrl = le16_to_cpu(*(__le16 *)adapter->event_body); + ctrl = get_unaligned_le16(adapter->event_body); mwifiex_dbg(adapter, EVENT, "event: AMSDU_AGGR_CTRL %d\n", ctrl); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 1532ac9cee0b..42997e05d90f 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -560,7 +560,7 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) #endif mwifiex_dbg(adapter, CMD, "aborting bgscan!\n"); mwifiex_stop_bg_scan(priv); - cfg80211_sched_scan_stopped(priv->wdev.wiphy); + cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0); #ifdef CONFIG_PM } #endif diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index df9704de0715..7d0d3ff3dd4c 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -349,7 +349,7 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv, chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT; break; } - vht_oper->center_freq_seg1_idx = + vht_oper->center_freq_seg0_idx = mwifiex_get_center_freq_index(priv, BAND_AAC, bss_desc->channel, chan_bw); @@ -431,6 +431,41 @@ mwifiex_add_wmm_info_ie(struct mwifiex_private *priv, struct sk_buff *skb, *buf++ = qosinfo; /* U-APSD no in use */ } +static void mwifiex_tdls_add_bss_co_2040(struct sk_buff *skb) +{ + struct ieee_types_bss_co_2040 *bssco; + + bssco = (void *)skb_put(skb, sizeof(struct ieee_types_bss_co_2040)); + bssco->ieee_hdr.element_id = WLAN_EID_BSS_COEX_2040; + bssco->ieee_hdr.len = sizeof(struct ieee_types_bss_co_2040) - + sizeof(struct ieee_types_header); + bssco->bss_2040co = 0x01; +} + +static void mwifiex_tdls_add_supported_chan(struct sk_buff *skb) +{ + struct ieee_types_generic *supp_chan; + u8 chan_supp[] = {1, 11}; + + supp_chan = (void *)skb_put(skb, (sizeof(struct ieee_types_header) + + sizeof(chan_supp))); + supp_chan->ieee_hdr.element_id = WLAN_EID_SUPPORTED_CHANNELS; + supp_chan->ieee_hdr.len = sizeof(chan_supp); + memcpy(supp_chan->data, chan_supp, sizeof(chan_supp)); +} + +static void mwifiex_tdls_add_oper_class(struct sk_buff *skb) +{ + struct ieee_types_generic *reg_class; + u8 rc_list[] = {1, + 1, 2, 3, 4, 12, 22, 23, 24, 25, 27, 28, 29, 30, 32, 33}; + reg_class = (void *)skb_put(skb, (sizeof(struct ieee_types_header) + + sizeof(rc_list))); + reg_class->ieee_hdr.element_id = WLAN_EID_SUPPORTED_REGULATORY_CLASSES; + reg_class->ieee_hdr.len = sizeof(rc_list); + memcpy(reg_class->data, rc_list, sizeof(rc_list)); +} + static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, const u8 *peer, u8 action_code, u8 dialog_token, @@ -484,7 +519,9 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, } mwifiex_tdls_add_ext_capab(priv, skb); - mwifiex_tdls_add_qos_capab(skb); + mwifiex_tdls_add_bss_co_2040(skb); + mwifiex_tdls_add_supported_chan(skb); + mwifiex_tdls_add_oper_class(skb); mwifiex_add_wmm_info_ie(priv, skb, 0); break; @@ -522,7 +559,9 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, } mwifiex_tdls_add_ext_capab(priv, skb); - mwifiex_tdls_add_qos_capab(skb); + mwifiex_tdls_add_bss_co_2040(skb); + mwifiex_tdls_add_supported_chan(skb); + mwifiex_tdls_add_oper_class(skb); mwifiex_add_wmm_info_ie(priv, skb, 0); break; @@ -612,6 +651,9 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, sizeof(struct ieee_types_bss_co_2040) + sizeof(struct ieee80211_ht_operation) + sizeof(struct ieee80211_tdls_lnkie) + + (2 * (sizeof(struct ieee_types_header))) + + MWIFIEX_SUPPORTED_CHANNELS + + MWIFIEX_OPERATING_CLASSES + sizeof(struct ieee80211_wmm_param_ie) + extra_ies_len; @@ -760,7 +802,10 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv, } mwifiex_tdls_add_ext_capab(priv, skb); + mwifiex_tdls_add_bss_co_2040(skb); + mwifiex_tdls_add_supported_chan(skb); mwifiex_tdls_add_qos_capab(skb); + mwifiex_tdls_add_oper_class(skb); break; default: mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS action frame type\n"); @@ -857,7 +902,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, struct mwifiex_sta_node *sta_ptr; u8 *peer, *pos, *end; u8 i, action, basic; - __le16 cap = 0; + u16 cap = 0; int ie_len = 0; if (len < (sizeof(struct ethhdr) + 3)) @@ -879,7 +924,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, pos = buf + sizeof(struct ethhdr) + 4; /* payload 1+ category 1 + action 1 + dialog 1 */ - cap = cpu_to_le16(*(u16 *)pos); + cap = get_unaligned_le16(pos); ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN; pos += 2; break; @@ -889,7 +934,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, return; /* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/ pos = buf + sizeof(struct ethhdr) + 6; - cap = cpu_to_le16(*(u16 *)pos); + cap = get_unaligned_le16(pos); ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN; pos += 2; break; @@ -909,7 +954,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, if (!sta_ptr) return; - sta_ptr->tdls_cap.capab = cap; + sta_ptr->tdls_cap.capab = cpu_to_le16(cap); for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) { if (pos + 2 + pos[1] > end) @@ -969,7 +1014,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, case WLAN_EID_AID: if (priv->adapter->is_hw_11ac_capable) sta_ptr->tdls_cap.aid = - le16_to_cpu(*(__le16 *)(pos + 2)); + get_unaligned_le16((pos + 2)); default: break; } diff --git a/drivers/net/wireless/marvell/mwifiex/uap_event.c b/drivers/net/wireless/marvell/mwifiex/uap_event.c index d24eca34ac11..e10b2a52e78f 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_event.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_event.c @@ -202,7 +202,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) "AP EVENT: event id: %#x\n", eventcause); break; case EVENT_AMSDU_AGGR_CTRL: - ctrl = le16_to_cpu(*(__le16 *)adapter->event_body); + ctrl = get_unaligned_le16(adapter->event_body); mwifiex_dbg(adapter, EVENT, "event: AMSDU_AGGR_CTRL %d\n", ctrl); diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 9cf3334adf4d..2f7705c50161 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -306,9 +306,17 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size) } } - usb_fill_bulk_urb(ctx->urb, card->udev, - usb_rcvbulkpipe(card->udev, ctx->ep), ctx->skb->data, - size, mwifiex_usb_rx_complete, (void *)ctx); + if (card->rx_cmd_ep == ctx->ep && + card->rx_cmd_ep_type == USB_ENDPOINT_XFER_INT) + usb_fill_int_urb(ctx->urb, card->udev, + usb_rcvintpipe(card->udev, ctx->ep), + ctx->skb->data, size, mwifiex_usb_rx_complete, + (void *)ctx, card->rx_cmd_interval); + else + usb_fill_bulk_urb(ctx->urb, card->udev, + usb_rcvbulkpipe(card->udev, ctx->ep), + ctx->skb->data, size, mwifiex_usb_rx_complete, + (void *)ctx); if (card->rx_cmd_ep == ctx->ep) atomic_inc(&card->rx_cmd_urb_pending); @@ -424,10 +432,13 @@ static int mwifiex_usb_probe(struct usb_interface *intf, epd = &iface_desc->endpoint[i].desc; if (usb_endpoint_dir_in(epd) && usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT && - usb_endpoint_xfer_bulk(epd)) { - pr_debug("info: bulk IN: max pkt size: %d, addr: %d\n", + (usb_endpoint_xfer_bulk(epd) || + usb_endpoint_xfer_int(epd))) { + card->rx_cmd_ep_type = usb_endpoint_type(epd); + card->rx_cmd_interval = epd->bInterval; + pr_debug("info: Rx CMD/EVT:: max pkt size: %d, addr: %d, ep_type: %d\n", le16_to_cpu(epd->wMaxPacketSize), - epd->bEndpointAddress); + epd->bEndpointAddress, card->rx_cmd_ep_type); card->rx_cmd_ep = usb_endpoint_num(epd); atomic_set(&card->rx_cmd_urb_pending, 0); } @@ -461,10 +472,16 @@ static int mwifiex_usb_probe(struct usb_interface *intf, } if (usb_endpoint_dir_out(epd) && usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT && - usb_endpoint_xfer_bulk(epd)) { + (usb_endpoint_xfer_bulk(epd) || + usb_endpoint_xfer_int(epd))) { + card->tx_cmd_ep_type = usb_endpoint_type(epd); + card->tx_cmd_interval = epd->bInterval; pr_debug("info: bulk OUT: max pkt size: %d, addr: %d\n", le16_to_cpu(epd->wMaxPacketSize), epd->bEndpointAddress); + pr_debug("info: Tx CMD:: max pkt size: %d, addr: %d, ep_type: %d\n", + le16_to_cpu(epd->wMaxPacketSize), + epd->bEndpointAddress, card->tx_cmd_ep_type); card->tx_cmd_ep = usb_endpoint_num(epd); atomic_set(&card->tx_cmd_urb_pending, 0); card->bulk_out_maxpktsize = @@ -884,9 +901,17 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, context->skb = skb; tx_urb = context->urb; - usb_fill_bulk_urb(tx_urb, card->udev, usb_sndbulkpipe(card->udev, ep), - data, skb->len, mwifiex_usb_tx_complete, - (void *)context); + if (ep == card->tx_cmd_ep && + card->tx_cmd_ep_type == USB_ENDPOINT_XFER_INT) + usb_fill_int_urb(tx_urb, card->udev, + usb_sndintpipe(card->udev, ep), data, + skb->len, mwifiex_usb_tx_complete, + (void *)context, card->tx_cmd_interval); + else + usb_fill_bulk_urb(tx_urb, card->udev, + usb_sndbulkpipe(card->udev, ep), data, + skb->len, mwifiex_usb_tx_complete, + (void *)context); tx_urb->transfer_flags |= URB_ZERO_PACKET; diff --git a/drivers/net/wireless/marvell/mwifiex/usb.h b/drivers/net/wireless/marvell/mwifiex/usb.h index e5f204ea018b..e36bd63172ff 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.h +++ b/drivers/net/wireless/marvell/mwifiex/usb.h @@ -90,6 +90,10 @@ struct usb_card_rec { struct urb_context tx_cmd; u8 mc_resync_flag; struct usb_tx_data_port port[MWIFIEX_TX_DATA_PORT]; + int rx_cmd_ep_type; + u8 rx_cmd_interval; + int tx_cmd_ep_type; + u8 tx_cmd_interval; }; struct fw_header { @@ -102,12 +106,12 @@ struct fw_header { struct fw_sync_header { __le32 cmd; __le32 seq_num; -}; +} __packed; struct fw_data { struct fw_header fw_hdr; __le32 seq_num; u8 data[1]; -}; +} __packed; #endif /*_MWIFIEX_USB_H */ diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index b1ab8da121dd..0cd68ffc2c74 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -274,13 +274,13 @@ int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf, val = *((u8 *)addr); break; case 2: - val = *((u16 *)addr); + val = get_unaligned((u16 *)addr); break; case 4: - val = *((u32 *)addr); + val = get_unaligned((u32 *)addr); break; case 8: - val = *((long long *)addr); + val = get_unaligned((long long *)addr); break; default: val = -1; diff --git a/drivers/net/wireless/marvell/mwifiex/util.h b/drivers/net/wireless/marvell/mwifiex/util.h index b541d66c01eb..c386992abcdb 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.h +++ b/drivers/net/wireless/marvell/mwifiex/util.h @@ -93,4 +93,9 @@ static inline dma_addr_t MWIFIEX_SKB_DMA_ADDR(struct sk_buff *skb) int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf, struct mwifiex_debug_info *info); +static inline void le16_unaligned_add_cpu(__le16 *var, u16 val) +{ + put_unaligned_le16(get_unaligned_le16(var) + val, var); +} + #endif /* !_MWIFIEX_UTIL_H_ */ diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index b1b400b59d86..e813b2ca740c 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -994,9 +994,9 @@ mwl8k_rxd_ap_process(void *_rxd, struct ieee80211_rx_status *status, *noise = -rxd->noise_floor; if (rxd->rate & MWL8K_AP_RATE_INFO_MCS_FORMAT) { - status->flag |= RX_FLAG_HT; + status->encoding = RX_ENC_HT; if (rxd->rate & MWL8K_AP_RATE_INFO_40MHZ) - status->flag |= RX_FLAG_40MHZ; + status->bw = RATE_INFO_BW_40; status->rate_idx = MWL8K_AP_RATE_INFO_RATEID(rxd->rate); } else { int i; @@ -1011,7 +1011,7 @@ mwl8k_rxd_ap_process(void *_rxd, struct ieee80211_rx_status *status, if (rxd->channel > 14) { status->band = NL80211_BAND_5GHZ; - if (!(status->flag & RX_FLAG_HT)) + if (!(status->encoding == RX_ENC_HT)) status->rate_idx -= 5; } else { status->band = NL80211_BAND_2GHZ; @@ -1109,17 +1109,17 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info); if (rate_info & MWL8K_STA_RATE_INFO_SHORTPRE) - status->flag |= RX_FLAG_SHORTPRE; + status->enc_flags |= RX_ENC_FLAG_SHORTPRE; if (rate_info & MWL8K_STA_RATE_INFO_40MHZ) - status->flag |= RX_FLAG_40MHZ; + status->bw = RATE_INFO_BW_40; if (rate_info & MWL8K_STA_RATE_INFO_SHORTGI) - status->flag |= RX_FLAG_SHORT_GI; + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT) - status->flag |= RX_FLAG_HT; + status->encoding = RX_ENC_HT; if (rxd->channel > 14) { status->band = NL80211_BAND_5GHZ; - if (!(status->flag & RX_FLAG_HT)) + if (!(status->encoding == RX_ENC_HT)) status->rate_idx -= 5; } else { status->band = NL80211_BAND_2GHZ; @@ -6144,6 +6144,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) if (priv->sta_macids_supported || priv->device_info->fw_image_sta) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + rc = ieee80211_register_hw(hw); if (rc) { wiphy_err(hw->wiphy, "Cannot register device\n"); |