summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/rsi
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-12-02 13:58:10 -0500
committerDavid S. Miller <davem@davemloft.net>2016-12-02 13:58:10 -0500
commitab17cb1fea82b346bdecd4f2d7f0e84e80f847af (patch)
tree35910da9eef64d5b469a7a95891e55f93558d9e2 /drivers/net/wireless/rsi
parent4f4f907a6729ae9e132810711c3a05e48311a948 (diff)
parentd5fb3a138048798ce4cc4b4ced47d07d1794c577 (diff)
Merge tag 'wireless-drivers-next-for-davem-2016-12-01' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says: ==================== wireless-drivers-next patches for 4.10 Major changes: rsi * filter rx frames * configure tx power * make it possible to select antenna * support 802.11d brcmfmac * cleanup of scheduled scan code * support for bcm43341 chipset with different chip id * support rev6 of PCIe device interface ath10k * add spectral scan support for QCA6174 and QCA9377 families * show used tx bitrate with 10.4 firmware wil6210 * add power save mode support * add abort scan functionality * add support settings retry limit for short frames bcma * add Dell Inspiron 3148 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless/rsi')
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c156
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mgmt.c129
-rw-r--r--drivers/net/wireless/rsi/rsi_main.h4
-rw-r--r--drivers/net/wireless/rsi/rsi_mgmt.h23
4 files changed, 304 insertions, 8 deletions
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index aaca25870bc1..dadaa73ab49d 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -275,6 +275,8 @@ static int rsi_mac80211_start(struct ieee80211_hw *hw)
common->iface_down = false;
mutex_unlock(&common->mutex);
+ rsi_send_rx_filter_frame(common, 0);
+
return 0;
}
@@ -388,7 +390,7 @@ static int rsi_channel_change(struct ieee80211_hw *hw)
status = rsi_band_check(common);
if (!status)
- status = rsi_set_channel(adapter->priv, channel);
+ status = rsi_set_channel(adapter->priv, curchan);
if (bss->assoc) {
if (common->hw_data_qs_blocked &&
@@ -409,6 +411,34 @@ static int rsi_channel_change(struct ieee80211_hw *hw)
}
/**
+ * rsi_config_power() - This function configures tx power to device
+ * @hw: Pointer to the ieee80211_hw structure.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int rsi_config_power(struct ieee80211_hw *hw)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+
+ if (adapter->sc_nvifs <= 0) {
+ rsi_dbg(ERR_ZONE, "%s: No virtual interface found\n", __func__);
+ return -EINVAL;
+ }
+
+ rsi_dbg(INFO_ZONE,
+ "%s: Set tx power: %d dBM\n", __func__, conf->power_level);
+
+ if (conf->power_level == common->tx_power)
+ return 0;
+
+ common->tx_power = conf->power_level;
+
+ return rsi_send_radio_params_update(common);
+}
+
+/**
* rsi_mac80211_config() - This function is a handler for configuration
* requests. The stack calls this function to
* change hardware configuration, e.g., channel.
@@ -429,6 +459,12 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw,
if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
status = rsi_channel_change(hw);
+ /* tx power */
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
+ rsi_dbg(INFO_ZONE, "%s: Configuring Power\n", __func__);
+ status = rsi_config_power(hw);
+ }
+
mutex_unlock(&common->mutex);
return status;
@@ -471,11 +507,19 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw,
{
struct rsi_hw *adapter = hw->priv;
struct rsi_common *common = adapter->priv;
+ u16 rx_filter_word = 0;
mutex_lock(&common->mutex);
if (changed & BSS_CHANGED_ASSOC) {
rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n",
__func__, bss_conf->assoc);
+ if (bss_conf->assoc) {
+ /* Send the RX filter frame */
+ rx_filter_word = (ALLOW_DATA_ASSOC_PEER |
+ ALLOW_CTRL_ASSOC_PEER |
+ ALLOW_MGMT_ASSOC_PEER);
+ rsi_send_rx_filter_frame(common, rx_filter_word);
+ }
rsi_inform_bss_status(common,
bss_conf->assoc,
bss_conf->bssid,
@@ -1013,6 +1057,7 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw,
struct rsi_common *common = adapter->priv;
mutex_lock(&common->mutex);
+
/* Resetting all the fields to default values */
common->bitrate_mask[NL80211_BAND_2GHZ] = 0;
common->bitrate_mask[NL80211_BAND_5GHZ] = 0;
@@ -1022,9 +1067,114 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw,
common->vif_info[0].seq_start = 0;
common->secinfo.ptk_cipher = 0;
common->secinfo.gtk_cipher = 0;
+
+ rsi_send_rx_filter_frame(common, 0);
+
mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+/**
+ * rsi_mac80211_set_antenna() - This function is used to configure
+ * tx and rx antennas.
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @tx_ant: Bitmap for tx antenna
+ * @rx_ant: Bitmap for rx antenna
+ *
+ * Return: 0 on success, Negative error code on failure.
+ */
+static int rsi_mac80211_set_antenna(struct ieee80211_hw *hw,
+ u32 tx_ant, u32 rx_ant)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+ u8 antenna = 0;
+ if (tx_ant > 1 || rx_ant > 1) {
+ rsi_dbg(ERR_ZONE,
+ "Invalid antenna selection (tx: %d, rx:%d)\n",
+ tx_ant, rx_ant);
+ rsi_dbg(ERR_ZONE,
+ "Use 0 for int_ant, 1 for ext_ant\n");
+ return -EINVAL;
+ }
+
+ rsi_dbg(INFO_ZONE, "%s: Antenna map Tx %x Rx %d\n",
+ __func__, tx_ant, rx_ant);
+
+ mutex_lock(&common->mutex);
+
+ antenna = tx_ant ? ANTENNA_SEL_UFL : ANTENNA_SEL_INT;
+ if (common->ant_in_use != antenna)
+ if (rsi_set_antenna(common, antenna))
+ goto fail_set_antenna;
+
+ rsi_dbg(INFO_ZONE, "(%s) Antenna path configured successfully\n",
+ tx_ant ? "UFL" : "INT");
+
+ common->ant_in_use = antenna;
+
+ mutex_unlock(&common->mutex);
+
return 0;
+
+fail_set_antenna:
+ rsi_dbg(ERR_ZONE, "%s: Failed.\n", __func__);
+ mutex_unlock(&common->mutex);
+ return -EINVAL;
+}
+
+/**
+ * rsi_mac80211_get_antenna() - This function is used to configure
+ * tx and rx antennas.
+ *
+ * @hw: Pointer to the ieee80211_hw structure.
+ * @tx_ant: Bitmap for tx antenna
+ * @rx_ant: Bitmap for rx antenna
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int rsi_mac80211_get_antenna(struct ieee80211_hw *hw,
+ u32 *tx_ant, u32 *rx_ant)
+{
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
+
+ mutex_lock(&common->mutex);
+
+ *tx_ant = (common->ant_in_use == ANTENNA_SEL_UFL) ? 1 : 0;
+ *rx_ant = 0;
+
+ mutex_unlock(&common->mutex);
+
+ return 0;
+}
+
+static void rsi_reg_notify(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct rsi_hw * adapter = hw->priv;
+ int i;
+
+ sband = wiphy->bands[NL80211_BAND_5GHZ];
+
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ if (ch->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (ch->flags & IEEE80211_CHAN_RADAR)
+ ch->flags |= IEEE80211_CHAN_NO_IR;
+ }
+
+ rsi_dbg(INFO_ZONE,
+ "country = %s dfs_region = %d\n",
+ request->alpha2, request->dfs_region);
+ adapter->dfs_region = request->dfs_region;
}
static struct ieee80211_ops mac80211_ops = {
@@ -1043,6 +1193,8 @@ static struct ieee80211_ops mac80211_ops = {
.ampdu_action = rsi_mac80211_ampdu_action,
.sta_add = rsi_mac80211_sta_add,
.sta_remove = rsi_mac80211_sta_remove,
+ .set_antenna = rsi_mac80211_set_antenna,
+ .get_antenna = rsi_mac80211_get_antenna,
};
/**
@@ -1107,6 +1259,8 @@ int rsi_mac80211_attach(struct rsi_common *common)
wiphy->bands[NL80211_BAND_5GHZ] =
&adapter->sbands[NL80211_BAND_5GHZ];
+ wiphy->reg_notifier = rsi_reg_notify;
+
status = ieee80211_register_hw(hw);
if (status)
return status;
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 30b9d44ff8f8..fac87c06357b 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -913,7 +913,8 @@ int rsi_band_check(struct rsi_common *common)
*
* Return: 0 on success, corresponding error code on failure.
*/
-int rsi_set_channel(struct rsi_common *common, u16 channel)
+int rsi_set_channel(struct rsi_common *common,
+ struct ieee80211_channel *channel)
{
struct sk_buff *skb = NULL;
struct rsi_mac_frame *mgmt_frame;
@@ -928,24 +929,76 @@ int rsi_set_channel(struct rsi_common *common, u16 channel)
return -ENOMEM;
}
+ if (!channel) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
memset(skb->data, 0, FRAME_DESC_SZ);
mgmt_frame = (struct rsi_mac_frame *)skb->data;
mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
mgmt_frame->desc_word[1] = cpu_to_le16(SCAN_REQUEST);
- mgmt_frame->desc_word[4] = cpu_to_le16(channel);
+ mgmt_frame->desc_word[4] = cpu_to_le16(channel->hw_value);
+
+ mgmt_frame->desc_word[4] |=
+ cpu_to_le16(((char)(channel->max_antenna_gain)) << 8);
+ mgmt_frame->desc_word[5] =
+ cpu_to_le16((char)(channel->max_antenna_gain));
mgmt_frame->desc_word[7] = cpu_to_le16(PUT_BBP_RESET |
BBP_REG_WRITE |
(RSI_RF_TYPE << 4));
- mgmt_frame->desc_word[5] = cpu_to_le16(0x01);
- mgmt_frame->desc_word[6] = cpu_to_le16(0x12);
+ if (!(channel->flags & IEEE80211_CHAN_NO_IR) &&
+ !(channel->flags & IEEE80211_CHAN_RADAR)) {
+ if (common->tx_power < channel->max_power)
+ mgmt_frame->desc_word[6] = cpu_to_le16(common->tx_power);
+ else
+ mgmt_frame->desc_word[6] = cpu_to_le16(channel->max_power);
+ }
+ mgmt_frame->desc_word[7] = cpu_to_le16(common->priv->dfs_region);
if (common->channel_width == BW_40MHZ)
mgmt_frame->desc_word[5] |= cpu_to_le16(0x1 << 8);
- common->channel = channel;
+ common->channel = channel->hw_value;
+
+ skb_put(skb, FRAME_DESC_SZ);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_send_radio_params_update() - This function sends the radio
+ * parameters update to device
+ * @common: Pointer to the driver private structure.
+ * @channel: Channel value to be set.
+ *
+ * Return: 0 on success, corresponding error code on failure.
+ */
+int rsi_send_radio_params_update(struct rsi_common *common)
+{
+ struct rsi_mac_frame *cmd_frame;
+ struct sk_buff *skb = NULL;
+
+ rsi_dbg(MGMT_TX_ZONE,
+ "%s: Sending Radio Params update frame\n", __func__);
+
+ skb = dev_alloc_skb(FRAME_DESC_SZ);
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ cmd_frame = (struct rsi_mac_frame *)skb->data;
+
+ cmd_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+ cmd_frame->desc_word[1] = cpu_to_le16(RADIO_PARAMS_UPDATE);
+ cmd_frame->desc_word[3] = cpu_to_le16(BIT(0));
+
+ cmd_frame->desc_word[3] |= cpu_to_le16(common->tx_power << 8);
skb_put(skb, FRAME_DESC_SZ);
@@ -1243,6 +1296,72 @@ int rsi_send_block_unblock_frame(struct rsi_common *common, bool block_event)
}
+/**
+ * rsi_send_rx_filter_frame() - Sends a frame to filter the RX packets
+ *
+ * @common: Pointer to the driver private structure.
+ * @rx_filter_word: Flags of filter packets
+ *
+ * @Return: 0 on success, -1 on failure.
+ */
+int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word)
+{
+ struct rsi_mac_frame *cmd_frame;
+ struct sk_buff *skb;
+
+ rsi_dbg(MGMT_TX_ZONE, "Sending RX filter frame\n");
+
+ skb = dev_alloc_skb(FRAME_DESC_SZ);
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ cmd_frame = (struct rsi_mac_frame *)skb->data;
+
+ cmd_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+ cmd_frame->desc_word[1] = cpu_to_le16(SET_RX_FILTER);
+ cmd_frame->desc_word[4] = cpu_to_le16(rx_filter_word);
+
+ skb_put(skb, FRAME_DESC_SZ);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * rsi_set_antenna() - This fuction send antenna configuration request
+ * to device
+ *
+ * @common: Pointer to the driver private structure.
+ * @antenna: bitmap for tx antenna selection
+ *
+ * Return: 0 on Success, negative error code on failure
+ */
+int rsi_set_antenna(struct rsi_common *common, u8 antenna)
+{
+ struct rsi_mac_frame *cmd_frame;
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(FRAME_DESC_SZ);
+ if (!skb) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ cmd_frame = (struct rsi_mac_frame *)skb->data;
+
+ cmd_frame->desc_word[1] = cpu_to_le16(ANT_SEL_FRAME);
+ cmd_frame->desc_word[3] = cpu_to_le16(antenna & 0x00ff);
+ cmd_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+
+ skb_put(skb, FRAME_DESC_SZ);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
/**
* rsi_handle_ta_confirm_type() - This function handles the confirm frames.
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index dcd095787166..1d5904bc2c74 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -204,6 +204,9 @@ struct rsi_common {
struct cqm_info cqm_info;
bool hw_data_qs_blocked;
+
+ int tx_power;
+ u8 ant_in_use;
};
struct rsi_hw {
@@ -220,6 +223,7 @@ struct rsi_hw {
struct rsi_debugfs *dfsentry;
u8 num_debugfs_entries;
#endif
+ u8 dfs_region;
void *rsi_dev;
int (*host_intf_read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len);
int (*host_intf_write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len);
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index d1553581e471..dfbf7a50269b 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -140,6 +140,19 @@
#define RSI_SUPP_FILTERS (FIF_ALLMULTI | FIF_PROBE_REQ |\
FIF_BCN_PRBRESP_PROMISC)
+
+#define ANTENNA_SEL_INT 0x02 /* RF_OUT_2 / Integerated */
+#define ANTENNA_SEL_UFL 0x03 /* RF_OUT_1 / U.FL */
+
+/* Rx filter word definitions */
+#define PROMISCOUS_MODE BIT(0)
+#define ALLOW_DATA_ASSOC_PEER BIT(1)
+#define ALLOW_MGMT_ASSOC_PEER BIT(2)
+#define ALLOW_CTRL_ASSOC_PEER BIT(3)
+#define DISALLOW_BEACONS BIT(4)
+#define ALLOW_CONN_PEER_MGMT_WHILE_BUF_FULL BIT(5)
+#define DISALLOW_BROADCAST_DATA BIT(6)
+
enum opmode {
STA_OPMODE = 1,
AP_OPMODE = 2
@@ -190,7 +203,9 @@ enum cmd_frame_type {
BG_SCAN_PARAMS,
BG_SCAN_PROBE_REQ,
CW_MODE_REQ,
- PER_CMD_PKT
+ PER_CMD_PKT,
+ ANT_SEL_FRAME = 0x20,
+ RADIO_PARAMS_UPDATE = 0x29
};
struct rsi_mac_frame {
@@ -299,7 +314,8 @@ int rsi_send_aggregation_params_frame(struct rsi_common *common, u16 tid,
u16 ssn, u8 buf_size, u8 event);
int rsi_hal_load_key(struct rsi_common *common, u8 *data, u16 key_len,
u8 key_type, u8 key_id, u32 cipher);
-int rsi_set_channel(struct rsi_common *common, u16 chno);
+int rsi_set_channel(struct rsi_common *common,
+ struct ieee80211_channel *channel);
int rsi_send_block_unblock_frame(struct rsi_common *common, bool event);
void rsi_inform_bss_status(struct rsi_common *common, u8 status,
const u8 *bssid, u8 qos_enable, u16 aid);
@@ -313,4 +329,7 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb);
int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb);
int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb);
int rsi_band_check(struct rsi_common *common);
+int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word);
+int rsi_send_radio_params_update(struct rsi_common *common);
+int rsi_set_antenna(struct rsi_common *common, u8 antenna);
#endif