* Re: [PATCH 5/5] mac80211: set NETIF_F_LLTX when using intermediate tx queues
From: Toke Høiland-Jørgensen @ 2019-04-17 9:09 UTC (permalink / raw)
To: Herbert Xu
Cc: Johannes Berg, Arend Van Spriel, Felix Fietkau, linux-wireless,
Eric Dumazet, netdev
In-Reply-To: <20190417033834.ep6t7r6ttvjek5g7@gondor.apana.org.au>
Herbert Xu <herbert@gondor.apana.org.au> writes:
> On Tue, Apr 16, 2019 at 02:18:36PM +0100, Toke Høiland-Jørgensen wrote:
>>
>> > The congestion control happens at two levels. You are right that the
>> > socket buffer acts as one limit. However, other applications may also
>> > rely on the TX queue being full as the throttle (by setting a
>> > sufficiently large socket buffer size).
>>
>> Do you happen to have an example of an application that does this that
>> could be used for testing? :)
>
> Have a look at
>
> commit 6ce9e7b5fe3195d1ae6e3a0753d4ddcac5cd699e
> Author: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Wed Sep 2 18:05:33 2009 -0700
>
> ip: Report qdisc packet drops
>
> You should be able to do a UDP flood while setting IP_RECVERR to
> detect the packet drop due to a full queue which AFAICS will never
> happen with the current mac80211 setup.
Yup, got that part. Was just wondering if you know of any applications
that already do this, that I could test without having to write my
own... :)
-Toke
^ permalink raw reply
* Re: [PATCH 5/5] mac80211: set NETIF_F_LLTX when using intermediate tx queues
From: Arend Van Spriel @ 2019-04-17 9:16 UTC (permalink / raw)
To: Toke Høiland-Jørgensen, Herbert Xu
Cc: Johannes Berg, Felix Fietkau, linux-wireless, Eric Dumazet,
netdev, Bob McMahon
In-Reply-To: <87wojtroar.fsf@toke.dk>
+ Bob
On 4/17/2019 11:09 AM, Toke Høiland-Jørgensen wrote:
> Herbert Xu <herbert@gondor.apana.org.au> writes:
>
>> On Tue, Apr 16, 2019 at 02:18:36PM +0100, Toke Høiland-Jørgensen wrote:
>>>
>>>> The congestion control happens at two levels. You are right that the
>>>> socket buffer acts as one limit. However, other applications may also
>>>> rely on the TX queue being full as the throttle (by setting a
>>>> sufficiently large socket buffer size).
>>>
>>> Do you happen to have an example of an application that does this that
>>> could be used for testing? :)
>>
>> Have a look at
>>
>> commit 6ce9e7b5fe3195d1ae6e3a0753d4ddcac5cd699e
>> Author: Eric Dumazet <eric.dumazet@gmail.com>
>> Date: Wed Sep 2 18:05:33 2009 -0700
>>
>> ip: Report qdisc packet drops
>>
>> You should be able to do a UDP flood while setting IP_RECVERR to
>> detect the packet drop due to a full queue which AFAICS will never
>> happen with the current mac80211 setup.
>
> Yup, got that part. Was just wondering if you know of any applications
> that already do this, that I could test without having to write my
> own... :)
Hi Bob,
Is this something that could be easily implemented in iperf?
Regards,
Arend
^ permalink raw reply
* [PATCHv4 0/2] cfg80211/mac80211: Add support to configure and monitor station's rssi threshold
From: Tamizh chelvam @ 2019-04-17 9:21 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Tamizh chelvam
This patchsets introduced new NL command and api to support
configuring rssi for the connected stations and api to notify
userspace application upon crossing the configured threshold.
This will be useful for the application which requires
station's current signal strength change information.
Monitoring station's signal strength through station dump command
will unnecessarily increase the system overhead. This event based
mechanism will reduce the system overhead and helps application to
take a decision for the station for which event received.
Tamizh chelvam (2):
cfg80211: Add support to configure station specific RSSI threshold
for AP mode
mac80211: Implement API to configure station specific rssi threshold
v4:
* Fixed sparse warning
v3:
* Address Johannes comments
v2:
* Combined patchset 2 and 3 as single patch and addressed Johannes comments.
include/net/cfg80211.h | 39 +++++++++
include/net/mac80211.h | 7 ++
include/uapi/linux/nl80211.h | 21 +++++
net/mac80211/cfg.c | 108 +++++++++++++++++++++++++
net/mac80211/rx.c | 56 ++++++++++++-
net/mac80211/sta_info.c | 1 +
net/mac80211/sta_info.h | 31 ++++++++
net/wireless/nl80211.c | 179 ++++++++++++++++++++++++++++++++++++------
net/wireless/rdev-ops.h | 13 +++
net/wireless/trace.h | 21 +++++
10 files changed, 449 insertions(+), 27 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCHv4 2/2] mac80211: Implement API to configure station specific rssi threshold
From: Tamizh chelvam @ 2019-04-17 9:21 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1555492880-26457-1-git-send-email-tamizhr@codeaurora.org>
Implement set_sta_mon_rssi_config API to configure station
specific rssi threshold value to monitor change in connected
station's signal strength. RSSI low and high threshold values
will be calculated as per the station's current signal strength,
if the configuration needs to be a fixed threshold then the user
given value will be chosen as low and high threshold.
And this patch triggers cfg80211_sta_mon_rssi_notify with the
corresponding event when station signal goes out of configured threshold.
It uses rx data signal to check against rssi threshold configured by the user.
And update the lower and upper RSSI threshold for the station if it is not
configured as a fixed threshold.
This event will be useful for the application like steering to take
decision on any station depends on its current link quality.
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
include/net/mac80211.h | 7 +++
net/mac80211/cfg.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/rx.c | 56 +++++++++++++++++++++++-
net/mac80211/sta_info.c | 1 +
net/mac80211/sta_info.h | 31 ++++++++++++++
5 files changed, 202 insertions(+), 1 deletion(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d66fbfe..6893cb9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -873,6 +873,13 @@ enum mac80211_rate_control_flags {
};
+/*
+ * How many frames need to have been used in average station's
+ * signal strength before checking against the threshold
+ */
+#define IEEE80211_STA_SIGNAL_AVE_MIN_COUNT 4
+
+
/* there are 40 bytes if you don't need the rateset to be kept */
#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index ba6e408..b460051 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3938,6 +3938,113 @@ static int ieee80211_get_txq_stats(struct wiphy *wiphy,
return drv_abort_pmsr(local, sdata, request);
}
+void sta_mon_rssi_config_free(struct sta_info *sta)
+{
+ struct sta_mon_rssi_config *old_rssi_config;
+
+ if (sta->rssi_config) {
+ old_rssi_config = sta->rssi_config;
+ RCU_INIT_POINTER(sta->rssi_config, NULL);
+ kfree_rcu(old_rssi_config, rcu_head);
+ }
+}
+
+void ieee80211_update_rssi_config(struct sta_info *sta)
+{
+ s32 last;
+ u32 hyst;
+ int i, n;
+
+ if (!sta->rssi_config || sta->rssi_config->fixed_thold)
+ return;
+
+ if (!sta->rssi_config->last_value)
+ sta->rssi_config->last_value =
+ -ewma_signal_read(&sta->rx_stats_avg.signal);
+
+ last = sta->rssi_config->last_value;
+ hyst = sta->rssi_config->hyst;
+ n = sta->rssi_config->n_thresholds;
+
+ for (i = 0; i < n; i++)
+ if (last < sta->rssi_config->thresholds[i])
+ break;
+
+ sta->rssi_config->low =
+ i > 0 ? (sta->rssi_config->thresholds[i - 1] - hyst) : S32_MIN;
+ sta->rssi_config->high =
+ i < n ? (sta->rssi_config->thresholds[i] + hyst - 1) : S32_MAX;
+}
+
+static int
+ieee80211_set_sta_mon_rssi_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *mac_addr,
+ const struct cfg80211_sta_mon *sta_mon_cfg)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ struct sta_mon_rssi_config *rssi_config;
+ struct sta_info *sta;
+ int ret = 0;
+
+ mutex_lock(&local->sta_mtx);
+ rcu_read_lock();
+
+ if (mac_addr) {
+ sta = sta_info_get_bss(sdata, mac_addr);
+ if (!sta) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (sta_mon_cfg->fixed_thold &&
+ sta_mon_cfg->n_tholds > 2) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rssi_config = kzalloc(sizeof(*rssi_config) +
+ sta_mon_cfg->n_tholds * sizeof(s32),
+ GFP_KERNEL);
+ if (!rssi_config) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rssi_config->hyst = sta_mon_cfg->rssi_hyst;
+ if (sta_mon_cfg->fixed_thold) {
+ sta_mon_rssi_config_free(sta);
+ if (sta_mon_cfg->n_tholds == 1) {
+ rssi_config->low = sta_mon_cfg->rssi_tholds[0];
+ rssi_config->high = sta_mon_cfg->rssi_tholds[0];
+ } else {
+ rssi_config->low = sta_mon_cfg->rssi_tholds[0];
+ rssi_config->high = sta_mon_cfg->rssi_tholds[1];
+ }
+ rssi_config->fixed_thold = sta_mon_cfg->fixed_thold;
+ rssi_config->hyst = sta_mon_cfg->rssi_hyst;
+ rssi_config->n_thresholds = sta_mon_cfg->n_tholds;
+ sta->rssi_config = rssi_config;
+ } else {
+ sta_mon_rssi_config_free(sta);
+ rssi_config->n_thresholds = sta_mon_cfg->n_tholds;
+ memcpy(rssi_config->thresholds,
+ sta_mon_cfg->rssi_tholds,
+ rssi_config->n_thresholds * sizeof(s32));
+ rssi_config->hyst = sta_mon_cfg->rssi_hyst;
+ sta->rssi_config = rssi_config;
+ /* Calculate low and high RSSI thresholds */
+ ieee80211_update_rssi_config(sta);
+ }
+ }
+
+out:
+ rcu_read_unlock();
+ mutex_unlock(&local->sta_mtx);
+ return ret;
+}
+
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -4035,4 +4142,5 @@ static int ieee80211_get_txq_stats(struct wiphy *wiphy,
.get_ftm_responder_stats = ieee80211_get_ftm_responder_stats,
.start_pmsr = ieee80211_start_pmsr,
.abort_pmsr = ieee80211_abort_pmsr,
+ .set_sta_mon_rssi_config = ieee80211_set_sta_mon_rssi_config,
};
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4a03c18..de27a6f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1732,6 +1732,57 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
return RX_CONTINUE;
}
+static void ieee80211_sta_rx_signal_thold_check(struct ieee80211_rx_data *rx)
+{
+ struct sta_info *sta = rx->sta;
+ struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf;
+ bool rssi_cross = false;
+
+ if (!wiphy_ext_feature_isset(rx->local->hw.wiphy,
+ NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG))
+ return;
+
+ if (!sta->rssi_config)
+ return;
+
+ rcu_read_lock();
+ sta->rssi_config->count_rx_signal++;
+ if (sta->rssi_config->count_rx_signal <
+ IEEE80211_STA_SIGNAL_AVE_MIN_COUNT)
+ return;
+
+ if (sta->rssi_config->low && bss_conf->enable_beacon) {
+ int last_event = sta->rssi_config->last_value;
+ int sig = -ewma_signal_read(&sta->rx_stats_avg.signal);
+ int low = sta->rssi_config->low;
+ int high = sta->rssi_config->high;
+
+ if (sig < low &&
+ (last_event == 0 || last_event >= low)) {
+ sta->rssi_config->last_value = sig;
+ cfg80211_sta_mon_rssi_notify(
+ rx->sdata->dev, sta->addr,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+ sig, GFP_ATOMIC);
+ rssi_cross = true;
+ } else if (sig > high &&
+ (last_event == 0 || last_event <= high)) {
+ sta->rssi_config->last_value = sig;
+ cfg80211_sta_mon_rssi_notify(
+ rx->sdata->dev, sta->addr,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+ sig, GFP_ATOMIC);
+ rssi_cross = true;
+ }
+ }
+
+ if (rssi_cross) {
+ ieee80211_update_rssi_config(sta);
+ rssi_cross = false;
+ }
+ rcu_read_unlock();
+}
+
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
{
@@ -1787,6 +1838,7 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
sta->rx_stats.last_signal = status->signal;
ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal);
+ ieee80211_sta_rx_signal_thold_check(rx);
}
if (status->chains) {
@@ -4219,9 +4271,11 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
/* statistics part of ieee80211_rx_h_sta_process() */
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
stats->last_signal = status->signal;
- if (!fast_rx->uses_rss)
+ if (!fast_rx->uses_rss) {
ewma_signal_add(&sta->rx_stats_avg.signal,
-status->signal);
+ ieee80211_sta_rx_signal_thold_check(rx);
+ }
}
if (status->chains) {
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a4932ee..ea22c2d 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1029,6 +1029,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
rate_control_remove_sta_debugfs(sta);
ieee80211_sta_debugfs_remove(sta);
+ sta_mon_rssi_config_free(sta);
cleanup_single_sta(sta);
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 71f7e49..17b3726 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -427,6 +427,33 @@ struct ieee80211_sta_rx_stats {
u64 msdu[IEEE80211_NUM_TIDS + 1];
};
+/**
+ * struct sta_mon_rssi_config - Monitor station's signal strength
+ * @rcu_head: rcu head for freeing structure
+ * @n_rssi_tholds: Number of thresholds passed by user
+ * @low: RSSI lower threshold for this station, a zero value implies
+ * disabled
+ * @high: RSSI upper threshold for this station
+ * @hyst: RSSI hysteresis for this station
+ * @last_value: Last RSSI value for this station triggered the
+ * RSSI cross event
+ * @fixed_thold - Indicate whether to use fixed thresholds limit or not
+ * @threholds: RSSI threshold limit passed by the user
+ * @count_rx_signal: Number of data frames used in averaging station signal.
+ * This can be used to avoid generating less reliable station rssi cross
+ * events that would be based only on couple of received frames
+ */
+struct sta_mon_rssi_config {
+ struct rcu_head rcu_head;
+ int n_thresholds;
+ s32 low, high;
+ u32 hyst;
+ s32 last_value;
+ u8 fixed_thold;
+ unsigned int count_rx_signal;
+ s32 thresholds[0];
+};
+
/*
* The bandwidth threshold below which the per-station CoDel parameters will be
* scaled to be more lenient (to prevent starvation of slow stations). This
@@ -496,6 +523,7 @@ struct ieee80211_sta_rx_stats {
* @fast_rx: RX fastpath information
* @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to
* the BSS one.
+ * @rssi_config: RSSI threshold config parameters for this station
* @tx_stats: TX statistics
* @tx_stats.packets: # of packets transmitted
* @tx_stats.bytes: # of bytes in all packets transmitted
@@ -623,6 +651,7 @@ struct sta_info {
struct cfg80211_chan_def tdls_chandef;
+ struct sta_mon_rssi_config __rcu *rssi_config;
/* keep last! */
struct ieee80211_sta sta;
};
@@ -760,6 +789,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
+void sta_mon_rssi_config_free(struct sta_info *sta);
void sta_info_recalc_tim(struct sta_info *sta);
@@ -792,6 +822,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
unsigned long exp_time);
u8 sta_info_tx_streams(struct sta_info *sta);
+void ieee80211_update_rssi_config(struct sta_info *sta);
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
--
1.7.9.5
^ permalink raw reply related
* [PATCHv4 1/2] cfg80211: Add support to configure station specific RSSI threshold for AP mode
From: Tamizh chelvam @ 2019-04-17 9:21 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Tamizh chelvam
In-Reply-To: <1555492880-26457-1-git-send-email-tamizhr@codeaurora.org>
Add infrastructure to configure station specific RSSI threshold
configuration to monitor station's signal strength variation.
This configuration will be useful for the application like
steering which requires change in the station's current signal
strength.
New NL80211_CMD_STA_MON introduced to configure the RSSI threshold
using NL80211_ATTR_CQM nested attributes. The MAC address of
a station is passed in NL80211_ATTR_MAC. And NL80211_ATTR_STA_MON_FIXED_THOLD
introduced to have this RSSI threshold as a fixed(not modifying the
low and high threshold upon crossing the threshold) or moving(modifying
low and high threshold upon crossing the threshold) thresholds.
Depends on the application's use case user can have either fixed or
moving RSSI range thresholds.
cfg80211_sta_mon_rssi_notify introduced to notify change in the
station's signal stregnth cross event using NL80211_CMD_NOTIFY_STA_MON.
Driver supporting this feature should advertise
NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG feature flag.
Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
include/net/cfg80211.h | 39 +++++++++
include/uapi/linux/nl80211.h | 21 +++++
net/wireless/nl80211.c | 179 ++++++++++++++++++++++++++++++++++++------
net/wireless/rdev-ops.h | 13 +++
net/wireless/trace.h | 21 +++++
5 files changed, 247 insertions(+), 26 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2ea04e9..cb8ba5a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3161,6 +3161,20 @@ struct cfg80211_update_owe_info {
};
/**
+ * struct cfg80211_sta_mon - Configure station monitor parameters
+ * @rssi_tholds - array of RSSI thresholds for the station
+ * @rssi_hyst - RSSI hysterisis
+ * @n_tholds - Number of configuration thresholds
+ * @fixed_thold - Fixed thresholds limit used for the station
+ */
+struct cfg80211_sta_mon {
+ s32 *rssi_tholds;
+ u32 rssi_hyst;
+ int n_tholds;
+ u8 fixed_thold;
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -3501,6 +3515,12 @@ struct cfg80211_update_owe_info {
* @update_owe_info: Provide updated OWE info to driver. Driver implementing SME
* but offloading OWE processing to the user space will get the updated
* DH IE through this interface.
+ *
+ * @set_sta_mon_rssi_config: Configure RSSI threshold for a station.
+ * After configuration, the driver should (soon) send an event indicating
+ * the current level of a station is above/below the configured threshold;
+ * this may need some care when the configuration is changed
+ * (without first being disabled.)
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3817,6 +3837,9 @@ struct cfg80211_ops {
struct cfg80211_pmsr_request *request);
int (*update_owe_info)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_owe_info *owe_info);
+ int (*set_sta_mon_rssi_config)(struct wiphy *wiphy,
+ struct net_device *dev, const u8 *addr,
+ const struct cfg80211_sta_mon *sta_mon_cfg);
};
/*
@@ -6620,6 +6643,22 @@ bool cfg80211_rx_control_port(struct net_device *dev,
struct sk_buff *skb, bool unencrypted);
/**
+ * cfg80211_sta_mon_rssi_notify - Station's rssi out of range event
+ * @dev: network device
+ * @peer: Station's mac address
+ * @rssi_event: the triggered RSSI event
+ * @rssi_level: new RSSI level value or 0 if not available
+ * @gfp: context flags
+ *
+ * This function is called when a configured rssi threshold reached event
+ * occurs for a station.
+ */
+void
+cfg80211_sta_mon_rssi_notify(struct net_device *dev, const u8 *peer,
+ enum nl80211_cqm_rssi_threshold_event rssi_event,
+ s32 rssi_level, gfp_t gfp);
+
+/**
* cfg80211_cqm_rssi_notify - connection quality monitoring rssi event
* @dev: network device
* @rssi_event: the triggered RSSI event
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 25f70dd..cbe5866 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1070,6 +1070,12 @@
* OWE AKM by the host drivers that implement SME but rely
* on the user space for the cryptographic/DH IE processing in AP mode.
*
+ * @NL80211_CMD_SET_STA_MON: This command is used to configure station's
+ * connection monitoring notification trigger levels. This uses nested
+ * attribute %NL80211_ATTR_CQM with %NL80211_ATTR_CQM_* sub-attributes.
+ * @NL80211_CMD_NOTIFY_STA_MON: This is used as an event to notify
+ * the user space that a trigger level was reached for a station.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1292,6 +1298,9 @@ enum nl80211_commands {
NL80211_CMD_UPDATE_OWE_INFO,
+ NL80211_CMD_SET_STA_MON,
+ NL80211_CMD_NOTIFY_STA_MON,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2324,6 +2333,12 @@ enum nl80211_commands {
* should be picking up the lowest tx power, either tx power per-interface
* or per-station.
*
+ * @NL80211_ATTR_STA_MON_FIXED_THOLD: This u8 attribute is used with
+ * %NL80211_CMD_SET_STA_MON to indicate driver that the monitoring
+ * threshold is fixed(not modifying the low and high threshold upon
+ * crossing the threshold) or moving(modifying low and high threshold
+ * upon crossing the threshold) thresholds.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2777,6 +2792,8 @@ enum nl80211_attrs {
NL80211_ATTR_STA_TX_POWER_SETTING,
NL80211_ATTR_STA_TX_POWER,
+ NL80211_ATTR_STA_MON_FIXED_THOLD,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -5405,6 +5422,9 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power
* to a station.
*
+ * @NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG: Driver supports monitoring
+ * station's RSSI threshold value should adveritise this flag.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5449,6 +5469,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
NL80211_EXT_FEATURE_EXT_KEY_ID,
NL80211_EXT_FEATURE_STA_TX_PWR,
+ NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 846d25d..78657c0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -280,6 +280,17 @@ static int validate_ie_attr(const struct nlattr *attr,
NLA_POLICY_NESTED_ARRAY(nl80211_psmr_peer_attr_policy),
};
+static const struct nla_policy
+nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
+ [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
+ [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
+};
+
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
@@ -395,7 +406,8 @@ static int validate_ie_attr(const struct nlattr *attr,
[NL80211_ATTR_PS_STATE] = NLA_POLICY_RANGE(NLA_U32,
NL80211_PS_DISABLED,
NL80211_PS_ENABLED),
- [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
+ [NL80211_ATTR_CQM] =
+ NLA_POLICY_NESTED(nl80211_attr_cqm_policy),
[NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
[NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
[NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
@@ -546,6 +558,7 @@ static int validate_ie_attr(const struct nlattr *attr,
[NL80211_ATTR_PEER_MEASUREMENTS] =
NLA_POLICY_NESTED(nl80211_pmsr_attr_policy),
[NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
+ [NL80211_ATTR_STA_MON_FIXED_THOLD] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@@ -10498,17 +10511,6 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
return err;
}
-static const struct nla_policy
-nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
- [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
- [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
- [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
- [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
- [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
- [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
- [NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
-};
-
static int nl80211_set_cqm_txe(struct genl_info *info,
u32 rate, u32 pkts, u32 intvl)
{
@@ -10589,14 +10591,9 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
}
-static int nl80211_set_cqm_rssi(struct genl_info *info,
- const s32 *thresholds, int n_thresholds,
- u32 hysteresis)
+static int nl80211_validate_rssi_tholds(const s32 *thresholds, int n_thresholds)
{
- struct cfg80211_registered_device *rdev = info->user_ptr[0];
- struct net_device *dev = info->user_ptr[1];
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- int i, err;
+ int i;
s32 prev = S32_MIN;
/* Check all values negative and sorted */
@@ -10606,6 +10603,21 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
prev = thresholds[i];
}
+ return 0;
+}
+
+static int nl80211_set_cqm_rssi(struct genl_info *info,
+ const s32 *thresholds, int n_thresholds,
+ u32 hysteresis)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ err = nl80211_validate_rssi_tholds(thresholds, n_thresholds);
+ if (err)
+ return err;
if (wdev->iftype != NL80211_IFTYPE_STATION &&
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
@@ -10668,7 +10680,7 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
- nl80211_attr_cqm_policy, info->extack);
+ NULL, NULL);
if (err)
return err;
@@ -13405,6 +13417,78 @@ static int nl80211_update_owe_info(struct sk_buff *skb, struct genl_info *info)
return rdev_update_owe_info(rdev, dev, &owe_info);
}
+static int nl80211_set_sta_mon(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
+ struct cfg80211_sta_mon sta_mon_config = {};
+ struct nlattr *sta_mon;
+ u8 *addr = NULL;
+ int err;
+
+ if (wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO)
+ return -ENOTSUPP;
+
+ wdev_lock(wdev);
+ sta_mon = info->attrs[NL80211_ATTR_CQM];
+ if (!sta_mon || !info->attrs[NL80211_ATTR_MAC]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, sta_mon,
+ NULL, NULL);
+ if (err) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ sta_mon_config.fixed_thold =
+ nla_get_flag(info->attrs[NL80211_ATTR_STA_MON_FIXED_THOLD]);
+
+ if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
+ attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
+ int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+
+ sta_mon_config.rssi_tholds =
+ nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+ sta_mon_config.rssi_hyst =
+ nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
+
+ if (!rdev->ops->set_sta_mon_rssi_config ||
+ !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG)) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (len % 4) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ sta_mon_config.n_tholds = len / 4;
+ err = nl80211_validate_rssi_tholds(sta_mon_config.rssi_tholds,
+ sta_mon_config.n_tholds);
+ if (err) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = rdev_set_sta_mon_rssi_config(rdev, dev, addr,
+ &sta_mon_config);
+ goto out;
+ }
+
+out:
+ wdev_unlock(wdev);
+ return err;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -14242,6 +14326,13 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_SET_STA_MON,
+ .doit = nl80211_set_sta_mon,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
@@ -15443,7 +15534,8 @@ bool cfg80211_rx_control_port(struct net_device *dev,
EXPORT_SYMBOL(cfg80211_rx_control_port);
static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
- const char *mac, gfp_t gfp)
+ const char *mac, gfp_t gfp,
+ enum nl80211_commands cmd)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@@ -15455,7 +15547,7 @@ static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
cb = (void **)msg->cb;
- cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
+ cb[0] = nl80211hdr_put(msg, 0, 0, 0, cmd);
if (!cb[0]) {
nlmsg_free(msg);
return NULL;
@@ -15517,7 +15609,7 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
rssi_level = wdev->cqm_config->last_rssi_event_value;
}
- msg = cfg80211_prepare_cqm(dev, NULL, gfp);
+ msg = cfg80211_prepare_cqm(dev, NULL, gfp, NL80211_CMD_NOTIFY_CQM);
if (!msg)
return;
@@ -15538,13 +15630,48 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
}
EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
+void
+cfg80211_sta_mon_rssi_notify(struct net_device *dev, const u8 *peer,
+ enum nl80211_cqm_rssi_threshold_event rssi_event,
+ s32 rssi_level, gfp_t gfp)
+{
+ struct sk_buff *msg;
+
+ trace_cfg80211_sta_mon_rssi_notify(dev, peer, rssi_event, rssi_level);
+ if (WARN_ON(!peer))
+ return;
+
+ if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
+ rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
+ return;
+
+ msg = cfg80211_prepare_cqm(dev, peer, gfp, NL80211_CMD_NOTIFY_STA_MON);
+ if (!msg)
+ return;
+
+ if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+ rssi_event))
+ goto nla_put_failure;
+
+ if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
+ rssi_level))
+ goto nla_put_failure;
+
+ cfg80211_send_cqm(msg, gfp);
+ return;
+
+ nla_put_failure:
+ nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_sta_mon_rssi_notify);
+
void cfg80211_cqm_txe_notify(struct net_device *dev,
const u8 *peer, u32 num_packets,
u32 rate, u32 intvl, gfp_t gfp)
{
struct sk_buff *msg;
- msg = cfg80211_prepare_cqm(dev, peer, gfp);
+ msg = cfg80211_prepare_cqm(dev, peer, gfp, NL80211_CMD_NOTIFY_CQM);
if (!msg)
return;
@@ -15572,7 +15699,7 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
- msg = cfg80211_prepare_cqm(dev, peer, gfp);
+ msg = cfg80211_prepare_cqm(dev, peer, gfp, NL80211_CMD_NOTIFY_CQM);
if (!msg)
return;
@@ -15591,7 +15718,7 @@ void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
{
struct sk_buff *msg;
- msg = cfg80211_prepare_cqm(dev, NULL, gfp);
+ msg = cfg80211_prepare_cqm(dev, NULL, gfp, NL80211_CMD_NOTIFY_CQM);
if (!msg)
return;
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 18437a9..8d36745 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1286,4 +1286,17 @@ static inline int rdev_update_owe_info(struct cfg80211_registered_device *rdev,
return ret;
}
+static inline int
+rdev_set_sta_mon_rssi_config(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *addr,
+ const struct cfg80211_sta_mon *sta_mon_config)
+{
+ int ret = -EOPNOTSUPP;
+
+ ret = rdev->ops->set_sta_mon_rssi_config(&rdev->wiphy, dev,
+ addr, sta_mon_config);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 488ef2ce..113cd45 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3421,6 +3421,27 @@
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
);
+TRACE_EVENT(cfg80211_sta_mon_rssi_notify,
+ TP_PROTO(struct net_device *netdev, const u8 *addr,
+ enum nl80211_cqm_rssi_threshold_event rssi_event,
+ s32 rssi_level),
+ TP_ARGS(netdev, addr, rssi_event, rssi_level),
+ TP_STRUCT__entry(
+ NETDEV_ENTRY
+ MAC_ENTRY(addr)
+ __field(enum nl80211_cqm_rssi_threshold_event, rssi_event)
+ __field(s32, rssi_level)
+ ),
+ TP_fast_assign(
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(addr, addr);
+ __entry->rssi_event = rssi_event;
+ __entry->rssi_level = rssi_level;
+ ),
+ TP_printk(NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
+ ", rssi event: %d, level: %d", NETDEV_PR_ARG,
+ MAC_PR_ARG(addr), __entry->rssi_event, __entry->rssi_level)
+);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 5/5] mac80211: set NETIF_F_LLTX when using intermediate tx queues
From: Toke Høiland-Jørgensen @ 2019-04-17 9:17 UTC (permalink / raw)
To: Herbert Xu
Cc: Johannes Berg, Arend Van Spriel, Felix Fietkau, linux-wireless,
Eric Dumazet, netdev
In-Reply-To: <20190417033834.ep6t7r6ttvjek5g7@gondor.apana.org.au>
Herbert Xu <herbert@gondor.apana.org.au> writes:
> On Tue, Apr 16, 2019 at 02:18:36PM +0100, Toke Høiland-Jørgensen wrote:
>>
>> > The congestion control happens at two levels. You are right that the
>> > socket buffer acts as one limit. However, other applications may also
>> > rely on the TX queue being full as the throttle (by setting a
>> > sufficiently large socket buffer size).
>>
>> Do you happen to have an example of an application that does this that
>> could be used for testing? :)
>
> Have a look at
>
> commit 6ce9e7b5fe3195d1ae6e3a0753d4ddcac5cd699e
> Author: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Wed Sep 2 18:05:33 2009 -0700
>
> ip: Report qdisc packet drops
>
> You should be able to do a UDP flood while setting IP_RECVERR to
> detect the packet drop due to a full queue which AFAICS will never
> happen with the current mac80211 setup.
Also, looking at udp.c, it seems it uses net_xmit_errno() - which means
that returning NET_XMIT_CN has the same effect as NET_XMIT_SUCCESS when
propagated back to userspace? Which would kinda defeat the point of
going to the trouble of propagating up the return code (the mac80211
queue will never drop the most recently enqueued packet)...
-Toke
^ permalink raw reply
* Re: [PATCH v2] ath10k: fix different tx duration output
From: Toke Høiland-Jørgensen @ 2019-04-17 9:26 UTC (permalink / raw)
To: Lei Wang, ath10k; +Cc: linux-wireless, Lei Wang
In-Reply-To: <1555489045-18070-1-git-send-email-leiwa@codeaurora.org>
Lei Wang <leiwa@codeaurora.org> writes:
> TX duration output of tx_stats in debugfs and station dump had big
> difference because they got tx duration value from different statistic
> data. We should use the same statistic data.
So are you sure you picked the most accurate one of the two? :)
-Toke
^ permalink raw reply
* p54: drop device reference count if fails to enable device
From: Pan Bian @ 2019-04-17 9:41 UTC (permalink / raw)
To: Christian Lamparter, Kalle Valo, David S. Miller
Cc: linux-wireless, netdev, linux-kernel, Pan Bian
The function p54p_probe takes an extra reference count of the PCI
device. However, the extra reference count is not dropped when it fails
to enable the PCI device. This patch fixes the bug.
Signed-off-by: Pan Bian <bianpan2016@163.com>
---
drivers/net/wireless/intersil/p54/p54pci.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intersil/p54/p54pci.c b/drivers/net/wireless/intersil/p54/p54pci.c
index 27a4906..57ad564 100644
--- a/drivers/net/wireless/intersil/p54/p54pci.c
+++ b/drivers/net/wireless/intersil/p54/p54pci.c
@@ -554,7 +554,7 @@ static int p54p_probe(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Cannot enable new PCI device\n");
- return err;
+ goto err_put;
}
mem_addr = pci_resource_start(pdev, 0);
@@ -639,6 +639,7 @@ static int p54p_probe(struct pci_dev *pdev,
pci_release_regions(pdev);
err_disable_dev:
pci_disable_device(pdev);
+err_put:
pci_dev_put(pdev);
return err;
}
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] iwlwifi: don't panic in error path on non-msix systems
From: Michal Hocko @ 2019-04-17 10:11 UTC (permalink / raw)
To: Luca Coelho
Cc: kvalo, johannes, emmanuel.grumbach, linuxwifi, linux-kernel,
linux-wireless, Shahar S Matityahu, Luca Coelho
In-Reply-To: <20190417073516.24250-1-luca@coelho.fi>
Hi,
which tree is this supposed to be applied on? It doesn't do apply on top
of v5.1-rc4-3-gfd008d1a7a20. iwl_trans_pcie_sync_nmi doesn't exist in
drivers/net/wireless/intel/iwlwifi/pcie/trans.c. iwl_trans_sync_nmi
looks pretty similar. My patch massaging ended up with this. Please
double check. It compiles and even boots.
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index fe8269d023de..1f3969e2bcac 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -3639,20 +3639,27 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
void iwl_trans_sync_nmi(struct iwl_trans *trans)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT;
+ u32 inta_addr, sw_err_bit;
+
+ if (trans_pcie->msix_enabled) {
+ inta_addr = CSR_MSIX_HW_INT_CAUSES_AD;
+ sw_err_bit = MSIX_HW_INT_CAUSES_REG_SW_ERR;
+ } else {
+ inta_addr = CSR_INT;
+ sw_err_bit = CSR_INT_BIT_SW_ERR;
+ }
iwl_disable_interrupts(trans);
iwl_force_nmi(trans);
while (time_after(timeout, jiffies)) {
- u32 inta_hw = iwl_read32(trans,
- CSR_MSIX_HW_INT_CAUSES_AD);
+ u32 inta_hw = iwl_read32(trans, inta_addr);
/* Error detected by uCode */
- if (inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR) {
+ if (inta_hw & sw_err_bit) {
/* Clear causes register */
- iwl_write32(trans, CSR_MSIX_HW_INT_CAUSES_AD,
- inta_hw &
- MSIX_HW_INT_CAUSES_REG_SW_ERR);
+ iwl_write32(trans, inta_addr, inta_hw & sw_err_bit);
break;
}
--
Michal Hocko
SUSE Labs
^ permalink raw reply related
* Re: [PATCH] iwlwifi: don't panic in error path on non-msix systems
From: Luca Coelho @ 2019-04-17 10:17 UTC (permalink / raw)
To: Michal Hocko
Cc: kvalo, johannes, emmanuel.grumbach, linuxwifi, linux-kernel,
linux-wireless, Shahar S Matityahu
In-Reply-To: <20190417101102.GA5878@dhcp22.suse.cz>
On Wed, 2019-04-17 at 12:11 +0200, Michal Hocko wrote:
> Hi,
> which tree is this supposed to be applied on? It doesn't do apply on
> top
> of v5.1-rc4-3-gfd008d1a7a20. iwl_trans_pcie_sync_nmi doesn't exist in
> drivers/net/wireless/intel/iwlwifi/pcie/trans.c. iwl_trans_sync_nmi
> looks pretty similar. My patch massaging ended up with this. Please
> double check. It compiles and even boots.
Ah, sorry, I didn't mention that that patch was supposed to apply on
top of wireless-drivers-next, which is on its way to v5.2. We have
other patches touching this function there, thus the conflict.
> diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
> b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
> index fe8269d023de..1f3969e2bcac 100644
> --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
> +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
> @@ -3639,20 +3639,27 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct
> pci_dev *pdev,
>
> void iwl_trans_sync_nmi(struct iwl_trans *trans)
> {
> + struct iwl_trans_pcie *trans_pcie =
> IWL_TRANS_GET_PCIE_TRANS(trans);
> unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT;
> + u32 inta_addr, sw_err_bit;
> +
> + if (trans_pcie->msix_enabled) {
> + inta_addr = CSR_MSIX_HW_INT_CAUSES_AD;
> + sw_err_bit = MSIX_HW_INT_CAUSES_REG_SW_ERR;
> + } else {
> + inta_addr = CSR_INT;
> + sw_err_bit = CSR_INT_BIT_SW_ERR;
> + }
>
> iwl_disable_interrupts(trans);
> iwl_force_nmi(trans);
> while (time_after(timeout, jiffies)) {
> - u32 inta_hw = iwl_read32(trans,
> - CSR_MSIX_HW_INT_CAUSES_AD);
> + u32 inta_hw = iwl_read32(trans, inta_addr);
>
> /* Error detected by uCode */
> - if (inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR) {
> + if (inta_hw & sw_err_bit) {
> /* Clear causes register */
> - iwl_write32(trans, CSR_MSIX_HW_INT_CAUSES_AD,
> - inta_hw &
> - MSIX_HW_INT_CAUSES_REG_SW_ERR);
> + iwl_write32(trans, inta_addr, inta_hw &
> sw_err_bit);
> break;
> }
This looks good! So it fixed the problem you were having now?
--
Cheers,
Luca.
^ permalink raw reply
* Re: [PATCH] iwlwifi: don't panic in error path on non-msix systems
From: Luca Coelho @ 2019-04-17 10:53 UTC (permalink / raw)
To: Michal Hocko
Cc: kvalo, johannes, emmanuel.grumbach, linuxwifi, linux-kernel,
linux-wireless, Shahar S Matityahu
In-Reply-To: <3c1cb224613ac2cc3b20bfcf0c47e0df584c4e31.camel@coelho.fi>
On Wed, 2019-04-17 at 13:17 +0300, Luca Coelho wrote:
> On Wed, 2019-04-17 at 12:11 +0200, Michal Hocko wrote:
> > Hi,
> > which tree is this supposed to be applied on? It doesn't do apply
> > on
> > top
> > of v5.1-rc4-3-gfd008d1a7a20. iwl_trans_pcie_sync_nmi doesn't exist
> > in
> > drivers/net/wireless/intel/iwlwifi/pcie/trans.c. iwl_trans_sync_nmi
> > looks pretty similar. My patch massaging ended up with this. Please
> > double check. It compiles and even boots.
>
> Ah, sorry, I didn't mention that that patch was supposed to apply on
> top of wireless-drivers-next, which is on its way to v5.2. We have
> other patches touching this function there, thus the conflict.
Huh, I was confused. My patch actually applies on top of wireless-
drivers, which has other patches that touch the same function on their
way to v5.1 (but not there yet).
--
Luca.
^ permalink raw reply
* Re: [PATCH] iwlwifi: don't panic in error path on non-msix systems
From: Michal Hocko @ 2019-04-17 10:59 UTC (permalink / raw)
To: Luca Coelho
Cc: kvalo, johannes, emmanuel.grumbach, linuxwifi, linux-kernel,
linux-wireless, Shahar S Matityahu
In-Reply-To: <3c1cb224613ac2cc3b20bfcf0c47e0df584c4e31.camel@coelho.fi>
On Wed 17-04-19 13:17:10, Luca Coelho wrote:
> On Wed, 2019-04-17 at 12:11 +0200, Michal Hocko wrote:
> > Hi,
> > which tree is this supposed to be applied on? It doesn't do apply on
> > top
> > of v5.1-rc4-3-gfd008d1a7a20. iwl_trans_pcie_sync_nmi doesn't exist in
> > drivers/net/wireless/intel/iwlwifi/pcie/trans.c. iwl_trans_sync_nmi
> > looks pretty similar. My patch massaging ended up with this. Please
> > double check. It compiles and even boots.
>
> Ah, sorry, I didn't mention that that patch was supposed to apply on
> top of wireless-drivers-next, which is on its way to v5.2. We have
> other patches touching this function there, thus the conflict.
This is hard to tell. I haven't seen any "Error sending SCAN_CFG_CMD:"
message in the kernel log yet and I believe this is related to the
crash. But I might be easily wrong here.
In any case, I suspect that those events usually happen in a different
wireless environment than I am running right now. So give me some more
time before I can be more confident with an answer.
--
Michal Hocko
SUSE Labs
^ permalink raw reply
* Re: [PATCH] rtlwifi: rtl8188ee: Remove extraneous file
From: Larry Finger @ 2019-04-17 12:37 UTC (permalink / raw)
To: Kalle Valo; +Cc: linux-wireless, pkshih, Andrew Morton
In-Reply-To: <87tvex49yj.fsf@kamboji.qca.qualcomm.com>
On 4/16/19 9:55 PM, Kalle Valo wrote:
> Larry Finger <Larry.Finger@lwfinger.net> writes:
>
>> Somehow file drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej was
>> incorporated into the sources. Obviously, it can be removed.
>>
>> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
>> Reported-by: Andrew Morton <akpm@linux-foundation.org>
>> Cc: Andrew Morton <akpm@linux-foundation.org>
>> ---
>> Andrew,
>>
>> Thanks.
>>
>> Larry
>> ---
>> drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej | 10 ----------
>> 1 file changed, 10 deletions(-)
>> delete mode 100644 drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>>
>> diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>> b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>> deleted file mode 100644
>> index aa03d4605d8c..000000000000
>> --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>> +++ /dev/null
>
> What tree is this? On wireless-drivers I can't find this file:
>
> $ ls drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
> /bin/ls: cannot access 'drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej': No such file or directory
> $
>
> Actually I cannot find any .rej files:
>
> $ find -name '*.rej'
> $
>
It is in wireless-drivers-next. This extraneous file was added in commit
05f1be9594d5 ("rtlwifi: Convert the wake_match variable to local").
Larry
^ permalink raw reply
* Re: [PATCH] rtlwifi: rtl8188ee: Remove extraneous file
From: Larry Finger @ 2019-04-17 12:39 UTC (permalink / raw)
To: Pkshih, kvalo@codeaurora.org
Cc: linux-wireless@vger.kernel.org, akpm@linux-foundation.org
In-Reply-To: <1555464872.3420.2.camel@realtek.com>
On 4/16/19 8:34 PM, Pkshih wrote:
> On Tue, 2019-04-16 at 19:35 -0500, Larry Finger wrote:
>> Somehow file drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej was
>> incorporated into the sources. Obviously, it can be removed.
>>
>> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
>> Reported-by: Andrew Morton <akpm@linux-foundation.org>
>> Cc: Andrew Morton <akpm@linux-foundation.org>
>> ---
>> Andrew,
>>
>> Thanks.
>>
>> Larry
>> ---
>> drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej | 10 ----------
>> 1 file changed, 10 deletions(-)
>> delete mode 100644 drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>>
>> diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>> b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>> deleted file mode 100644
>> index aa03d4605d8c..000000000000
>> --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>> +++ /dev/null
>> @@ -1,10 +0,0 @@
>> ---- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c
>> -+++ drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c
>> -@@ -373,6 +373,7 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
>> - struct rx_fwinfo_88e *p_drvinfo;
>> - struct ieee80211_hdr *hdr;
>> - u32 phystatus = GET_RX_DESC_PHYST(pdesc);
>> -+ u8 wake_match;
>> -
>> - status->packet_report_type = (u8)GET_RX_STATUS_DESC_RPT_SEL(pdesc);
>> - if (status->packet_report_type == TX_REPORT2)
>
> The change of trx.c seems not belong to this patch, right?
That is correct. The change in trx.c was correctly done except for incorporation
of the extraneous file.
Larry
>
>
^ permalink raw reply
* Re: [PATCH] ath10k: remove iteration in wake_tx_queue
From: Erik Stromdahl @ 2019-04-17 13:29 UTC (permalink / raw)
To: Toke Høiland-Jørgensen, kvalo, linux-wireless, ath10k; +Cc: yiboz
In-Reply-To: <87imvdu5u8.fsf@toke.dk>
On 4/16/19 9:07 PM, Toke Høiland-Jørgensen wrote:
> Erik Stromdahl <erik.stromdahl@gmail.com> writes:
>
>> On 4/1/19 1:05 PM, Toke Høiland-Jørgensen wrote:
>>> Erik Stromdahl <erik.stromdahl@gmail.com> writes:
>>>
>>>> Iterating the TX queue and thereby dequeuing all available packets in the
>>>> queue could result in performance penalties on some SMP systems.
>>>>
>>>> The reason for this is most likely that the per-ac lock (active_txq_lock)
>>>> in mac80211 will be held by the CPU iterating the current queue.
>>>>
>>>> This will lock up other CPUs trying to push new messages on the TX
>>>> queue.
>>>>
>>>> Instead of iterating the queue we fetch just one packet at the time,
>>>> resulting in minimal starvation of the other CPUs.
>>>
>>> Did you test this with Felix' patches reducing the time the lock is held
>>> in mac80211?
>>>
>>> -Toke
>>>
>> Hi Toke,
>>
>> I am not aware of these patches. Can you please point them out for me?
>
> They've already been merged. Commits dcec1d9bc8a7 and 7ef769459f14 in
> mac80211-next :)
>
> -Toke
>
I see. I am using the ath tree and I couldn't find them there.
I can cherry-pick them to my own tree and try them out
(or wait until Kalle updates ath.git).
--
Erik
^ permalink raw reply
* Re: [PATCH] rtlwifi: rtl8188ee: Remove extraneous file
From: Kalle Valo @ 2019-04-17 14:15 UTC (permalink / raw)
To: Larry Finger; +Cc: linux-wireless, pkshih, Andrew Morton
In-Reply-To: <d393389d-f3f0-491e-c83b-50065f388d75@lwfinger.net>
Larry Finger <Larry.Finger@lwfinger.net> writes:
> On 4/16/19 9:55 PM, Kalle Valo wrote:
>> Larry Finger <Larry.Finger@lwfinger.net> writes:
>>
>>> Somehow file drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej was
>>> incorporated into the sources. Obviously, it can be removed.
>>>
>>> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
>>> Reported-by: Andrew Morton <akpm@linux-foundation.org>
>>> Cc: Andrew Morton <akpm@linux-foundation.org>
>>> ---
>>> Andrew,
>>>
>>> Thanks.
>>>
>>> Larry
>>> ---
>>> drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej | 10 ----------
>>> 1 file changed, 10 deletions(-)
>>> delete mode 100644 drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>>>
>>> diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>>> b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>>> deleted file mode 100644
>>> index aa03d4605d8c..000000000000
>>> --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>>> +++ /dev/null
>>
>> What tree is this? On wireless-drivers I can't find this file:
>>
>> $ ls drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej
>> /bin/ls: cannot access
>> 'drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c.rej': No such
>> file or directory
>> $
>>
>> Actually I cannot find any .rej files:
>>
>> $ find -name '*.rej'
>> $
>>
>
> It is in wireless-drivers-next. This extraneous file was added in
> commit 05f1be9594d5 ("rtlwifi: Convert the wake_match variable to
> local").
Ah, now I see it. But I think the commit adding was:
ddab2eee7949 rtlwifi: Convert the wake_match variable to local
I'll queue this for w-d-next.
--
Kalle Valo
^ permalink raw reply
* [PATCH v2 0/5] ath10k: SDIO and high latency patches from Silex
From: Erik Stromdahl @ 2019-04-17 19:14 UTC (permalink / raw)
To: kvalo, linux-wireless, ath10k; +Cc: Erik Stromdahl
This series adds a few more fixes for SDIO and high latency devices.
I have had these on my private tree for quite some time now so they
should be considered fairly well tested.
changes since v1:
Patch "ath10k: use clean packet headers" was renamed to
"ath10k: add initialization of HTC header" and PLL stuff was removed.
Patch "ath10k: sdio: add MSDU ID allocation in HTT TX path"
was removed since it became redundant after I had added Kalle's and
Wen's patches to my tree.
Patch "ath10k: sdio: replace skb_trim with explicit set of skb->len"
was rewritten and renamed to "ath10k: sdio: remove skb_trim in TX path"
Alagu Sankar (3):
ath10k: add initialization of HTC header
ath10k: high latency fixes for beacon buffer
ath10k: sdio: read RX packets in bundles
Erik Stromdahl (2):
ath10k: sdio: add missing error check
ath10k: sdio: remove skb_trim in TX path
drivers/net/wireless/ath/ath10k/htc.c | 1 +
drivers/net/wireless/ath/ath10k/mac.c | 31 ++++++--
drivers/net/wireless/ath/ath10k/sdio.c | 103 ++++++++++++++++++++-----
drivers/net/wireless/ath/ath10k/sdio.h | 4 +
4 files changed, 112 insertions(+), 27 deletions(-)
--
2.19.1
^ permalink raw reply
* [PATCH v2 2/5] ath10k: high latency fixes for beacon buffer
From: Erik Stromdahl @ 2019-04-17 19:15 UTC (permalink / raw)
To: kvalo, linux-wireless, ath10k; +Cc: Alagu Sankar, Erik Stromdahl
In-Reply-To: <20190417191503.18814-1-erik.stromdahl@gmail.com>
From: Alagu Sankar <alagusankar@silex-india.com>
Beacon buffer for high latency devices does not use DMA. other similar
buffer allocation methods in the driver have already been modified for
high latency path. Fix the beacon buffer allocation left out in the
earlier high latency changes.
Signed-off-by: Alagu Sankar <alagusankar@silex-india.com>
Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
---
drivers/net/wireless/ath/ath10k/mac.c | 31 ++++++++++++++++++++-------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index c9e700b844f8..2dd99ce44453 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -953,8 +953,12 @@ static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
ath10k_mac_vif_beacon_free(arvif);
if (arvif->beacon_buf) {
- dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
- arvif->beacon_buf, arvif->beacon_paddr);
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ kfree(arvif->beacon_buf);
+ else
+ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf,
+ arvif->beacon_paddr);
arvif->beacon_buf = NULL;
}
}
@@ -5210,10 +5214,17 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_MESH_POINT ||
vif->type == NL80211_IFTYPE_AP) {
- arvif->beacon_buf = dma_alloc_coherent(ar->dev,
- IEEE80211_MAX_FRAME_LEN,
- &arvif->beacon_paddr,
- GFP_ATOMIC);
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL) {
+ arvif->beacon_buf = kmalloc(IEEE80211_MAX_FRAME_LEN,
+ GFP_KERNEL);
+ arvif->beacon_paddr = (dma_addr_t)arvif->beacon_buf;
+ } else {
+ arvif->beacon_buf =
+ dma_alloc_coherent(ar->dev,
+ IEEE80211_MAX_FRAME_LEN,
+ &arvif->beacon_paddr,
+ GFP_ATOMIC);
+ }
if (!arvif->beacon_buf) {
ret = -ENOMEM;
ath10k_warn(ar, "failed to allocate beacon buffer: %d\n",
@@ -5424,8 +5435,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
err:
if (arvif->beacon_buf) {
- dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
- arvif->beacon_buf, arvif->beacon_paddr);
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ kfree(arvif->beacon_buf);
+ else
+ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+ arvif->beacon_buf,
+ arvif->beacon_paddr);
arvif->beacon_buf = NULL;
}
--
2.19.1
^ permalink raw reply related
* [PATCH v2 1/5] ath10k: add initialization of HTC header
From: Erik Stromdahl @ 2019-04-17 19:14 UTC (permalink / raw)
To: kvalo, linux-wireless, ath10k; +Cc: Alagu Sankar, Erik Stromdahl
In-Reply-To: <20190417191503.18814-1-erik.stromdahl@gmail.com>
From: Alagu Sankar <alagusankar@silex-india.com>
HTC header carries junk values that may be interpreted by the firmware
differently. Enable credit update only if flow control is enabled for
the corresponding endpoint.
Signed-off-by: Alagu Sankar <alagusankar@silex-india.com>
Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
---
drivers/net/wireless/ath/ath10k/htc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 805a7f8a04f2..1d4d1a1992fe 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -73,6 +73,7 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
struct ath10k_htc_hdr *hdr;
hdr = (struct ath10k_htc_hdr *)skb->data;
+ memset(hdr, 0, sizeof(struct ath10k_htc_hdr));
hdr->eid = ep->eid;
hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
--
2.19.1
^ permalink raw reply related
* [PATCH v2 3/5] ath10k: sdio: read RX packets in bundles
From: Erik Stromdahl @ 2019-04-17 19:15 UTC (permalink / raw)
To: kvalo, linux-wireless, ath10k; +Cc: Alagu Sankar, Erik Stromdahl
In-Reply-To: <20190417191503.18814-1-erik.stromdahl@gmail.com>
From: Alagu Sankar <alagusankar@silex-india.com>
The existing implementation of initiating multiple sdio transfers for
receive bundling is slowing down the receive speed.
Instead of having one sdio transfer for each packet in the bundle, we
read all packets in one sdio transfer.
This results in significant performance improvement on some targets.
On an imx6dl together with a QCA9377 SDIO device, the following
performance increase was obtained with iperf:
Before:
[ 3] 0.0- 1.0 sec 3.38 MBytes 28.3 Mbits/sec
After:
[ 3] 0.0- 1.0 sec 7.12 MBytes 59.8 Mbits/sec
Co-developed-by: Erik Stromdahl <erik.stromdahl@gmail.com>
Signed-off-by: Alagu Sankar <alagusankar@silex-india.com>
Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
---
drivers/net/wireless/ath/ath10k/sdio.c | 71 +++++++++++++++++++++-----
drivers/net/wireless/ath/ath10k/sdio.h | 2 +
2 files changed, 60 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index d5073fac9509..b89732aad97c 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -24,6 +24,8 @@
#include "trace.h"
#include "sdio.h"
+#define ATH10K_SDIO_READ_BUF_SIZE (32 * 1024)
+
/* inlined helper functions */
static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio,
@@ -618,41 +620,73 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
return ret;
}
-static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar,
- struct ath10k_sdio_rx_data *pkt)
+static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar)
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_data *pkt = &ar_sdio->rx_pkts[0];
struct sk_buff *skb = pkt->skb;
int ret;
- ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
- skb->data, pkt->alloc_len);
+ ret = ath10k_sdio_read(ar, ar_sdio->mbox_info.htc_addr,
+ skb->data, pkt->alloc_len);
+ if (ret) {
+ ath10k_warn(ar, "sdio_read error %d\n", ret);
+ goto err;
+ }
+
pkt->status = ret;
- if (!ret)
- skb_put(skb, pkt->act_len);
+ skb_put(skb, pkt->act_len);
+ return 0;
+
+err:
+ ar_sdio->n_rx_pkts = 0;
+ ath10k_sdio_mbox_free_rx_pkt(pkt);
return ret;
}
-static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar)
+static int ath10k_sdio_mbox_rx_fetch_bundle(struct ath10k *ar)
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ struct ath10k_sdio_rx_data *pkt;
int ret, i;
+ u32 pkt_offset = 0, pkt_bundle_len = 0;
+
+ for (i = 0; i < ar_sdio->n_rx_pkts; i++)
+ pkt_bundle_len += ar_sdio->rx_pkts[i].alloc_len;
+
+ if (pkt_bundle_len > ATH10K_SDIO_READ_BUF_SIZE) {
+ ret = -ENOSPC;
+ ath10k_warn(ar, "bundle size (%d) exceeding limit %d\n",
+ pkt_bundle_len, ATH10K_SDIO_READ_BUF_SIZE);
+ goto err;
+ }
+
+ ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr,
+ ar_sdio->sdio_read_buf, pkt_bundle_len);
+ if (ret)
+ goto err;
for (i = 0; i < ar_sdio->n_rx_pkts; i++) {
- ret = ath10k_sdio_mbox_rx_packet(ar,
- &ar_sdio->rx_pkts[i]);
- if (ret)
- goto err;
+ struct sk_buff *skb = ar_sdio->rx_pkts[i].skb;
+
+ pkt = &ar_sdio->rx_pkts[i];
+ skb_put(skb, pkt->act_len);
+ memcpy(skb->data, ar_sdio->sdio_read_buf + pkt_offset,
+ pkt->alloc_len);
+ pkt->status = 0;
+ pkt_offset += pkt->alloc_len;
}
return 0;
err:
/* Free all packets that was not successfully fetched. */
- for (; i < ar_sdio->n_rx_pkts; i++)
+ for (i = 0; i < ar_sdio->n_rx_pkts; i++)
ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]);
+ ar_sdio->n_rx_pkts = 0;
+
return ret;
}
@@ -695,7 +729,10 @@ static int ath10k_sdio_mbox_rxmsg_pending_handler(struct ath10k *ar,
*/
*done = false;
- ret = ath10k_sdio_mbox_rx_fetch(ar);
+ if (ar_sdio->n_rx_pkts > 1)
+ ret = ath10k_sdio_mbox_rx_fetch_bundle(ar);
+ else
+ ret = ath10k_sdio_mbox_rx_fetch(ar);
/* Process fetched packets. This will potentially update
* n_lookaheads depending on if the packets contain lookahead
@@ -2001,6 +2038,14 @@ static int ath10k_sdio_probe(struct sdio_func *func,
goto err_core_destroy;
}
+ ar_sdio->sdio_read_buf = devm_kzalloc(ar->dev,
+ ATH10K_SDIO_READ_BUF_SIZE,
+ GFP_KERNEL);
+ if (!ar_sdio->sdio_read_buf) {
+ ret = -ENOMEM;
+ goto err_core_destroy;
+ }
+
ar_sdio->func = func;
sdio_set_drvdata(func, ar_sdio);
diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index b8c7ac0330bd..07e2cc6a3bd8 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -196,6 +196,8 @@ struct ath10k_sdio {
struct ath10k *ar;
struct ath10k_sdio_irq_data irq_data;
+ u8 *sdio_read_buf;
+
/* temporary buffer for BMI requests */
u8 *bmi_buf;
--
2.19.1
^ permalink raw reply related
* [PATCH v2 4/5] ath10k: sdio: add missing error check
From: Erik Stromdahl @ 2019-04-17 19:15 UTC (permalink / raw)
To: kvalo, linux-wireless, ath10k; +Cc: Erik Stromdahl
In-Reply-To: <20190417191503.18814-1-erik.stromdahl@gmail.com>
Although not likely, the bundle allocation might fail.
Add proper error check and warning print.
Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
---
drivers/net/wireless/ath/ath10k/sdio.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index b89732aad97c..b8b3059721ee 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -586,6 +586,11 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
act_len,
&bndl_cnt);
+ if (ret) {
+ ath10k_warn(ar, "alloc_bundle error %d\n", ret);
+ goto err;
+ }
+
n_lookaheads += bndl_cnt;
i += bndl_cnt;
/*Next buffer will be the last in the bundle */
--
2.19.1
^ permalink raw reply related
* [PATCH v2 5/5] ath10k: sdio: remove skb_trim in TX path
From: Erik Stromdahl @ 2019-04-17 19:15 UTC (permalink / raw)
To: kvalo, linux-wireless, ath10k; +Cc: Erik Stromdahl
In-Reply-To: <20190417191503.18814-1-erik.stromdahl@gmail.com>
This patch fixes a bug with padding of the skb data buffer.
Since skb_trim can only be used to reduce the skb len, it is useless when
we pad (increase the length of) the skb. Instead we allocate a new
buffer with enough space to contain both the TX data and padding.
Since some skb's have multiple references, we can't use skb_put_padto()
to extend and pad skb->data (since it causes a panic if there is more
than one reference).
Also, in order to avoid the following possible deadlock issue (reported by
lockdep):
[ 26.508508] Possible interrupt unsafe locking scenario:
[ 26.508508]
[ 26.515314] CPU0 CPU1
[ 26.519862] ---- ----
[ 26.524408] lock(fs_reclaim);
[ 26.527573] local_irq_disable();
[ 26.533508] lock(_xmit_ETHER#2);
[ 26.539453] lock(fs_reclaim);
[ 26.545135] <Interrupt>
[ 26.547769] lock(_xmit_ETHER#2);
[ 26.551370]
[ 26.551370] *** DEADLOCK ***
... we use the GFP_NOFS flag with kzalloc()
Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
---
drivers/net/wireless/ath/ath10k/sdio.c | 27 ++++++++++++++++++++------
drivers/net/wireless/ath/ath10k/sdio.h | 2 ++
2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index b8b3059721ee..68d8e2d1b2ed 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -1279,6 +1279,7 @@ static void ath10k_sdio_free_bus_req(struct ath10k *ar,
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
+ kfree(bus_req->buf);
memset(bus_req, 0, sizeof(*bus_req));
spin_lock_bh(&ar_sdio->lock);
@@ -1294,7 +1295,7 @@ static void __ath10k_sdio_write_async(struct ath10k *ar,
int ret;
skb = req->skb;
- ret = ath10k_sdio_write(ar, req->address, skb->data, skb->len);
+ ret = ath10k_sdio_write(ar, req->address, req->buf, req->buf_len);
if (ret)
ath10k_warn(ar, "failed to write skb to 0x%x asynchronously: %d",
req->address, ret);
@@ -1330,6 +1331,7 @@ static void ath10k_sdio_write_async_work(struct work_struct *work)
static int ath10k_sdio_prep_async_req(struct ath10k *ar, u32 addr,
struct sk_buff *skb,
+ size_t alloc_len,
struct completion *comp,
bool htc_msg, enum ath10k_htc_ep_id eid)
{
@@ -1343,9 +1345,17 @@ static int ath10k_sdio_prep_async_req(struct ath10k *ar, u32 addr,
if (!bus_req) {
ath10k_warn(ar,
"unable to allocate bus request for async request\n");
- return -ENOMEM;
+ goto err;
}
+ bus_req->buf_len = alloc_len;
+ bus_req->buf = kzalloc(alloc_len, GFP_NOFS);
+ if (!bus_req->buf) {
+ ath10k_warn(ar,
+ "unable to allocate data buffer for bus request\n");
+ goto err_free_bus_req;
+ }
+ memcpy(bus_req->buf, skb->data, skb->len);
bus_req->skb = skb;
bus_req->eid = eid;
bus_req->address = addr;
@@ -1357,6 +1367,11 @@ static int ath10k_sdio_prep_async_req(struct ath10k *ar, u32 addr,
spin_unlock_bh(&ar_sdio->wr_async_lock);
return 0;
+
+err_free_bus_req:
+ ath10k_sdio_free_bus_req(ar, bus_req);
+err:
+ return -ENOMEM;
}
/* IRQ handler */
@@ -1501,12 +1516,11 @@ static int ath10k_sdio_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
skb = items[i].transfer_context;
padded_len = ath10k_sdio_calc_txrx_padded_len(ar_sdio,
skb->len);
- skb_trim(skb, padded_len);
/* Write TX data to the end of the mbox address space */
address = ar_sdio->mbox_addr[eid] + ar_sdio->mbox_size[eid] -
- skb->len;
- ret = ath10k_sdio_prep_async_req(ar, address, skb,
+ padded_len;
+ ret = ath10k_sdio_prep_async_req(ar, address, skb, padded_len,
NULL, true, eid);
if (ret)
return ret;
@@ -1761,7 +1775,8 @@ static void ath10k_sdio_irq_disable(struct ath10k *ar)
init_completion(&irqs_disabled_comp);
ret = ath10k_sdio_prep_async_req(ar, MBOX_INT_STATUS_ENABLE_ADDRESS,
- skb, &irqs_disabled_comp, false, 0);
+ skb, skb->len, &irqs_disabled_comp,
+ false, 0);
if (ret)
goto out;
diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h
index 07e2cc6a3bd8..5a727993fbda 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.h
+++ b/drivers/net/wireless/ath/ath10k/sdio.h
@@ -105,6 +105,8 @@ struct ath10k_sdio_bus_request {
u32 address;
struct sk_buff *skb;
+ u8 *buf;
+ size_t buf_len;
enum ath10k_htc_ep_id eid;
int status;
/* Specifies if the current request is an HTC message.
--
2.19.1
^ permalink raw reply related
* [PATCH v7 02/21] drivers/net/b44: Align pwol_mask to unsigned long for better performance
From: Fenghua Yu @ 2019-04-17 21:33 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
Paolo Bonzini, Dave Hansen, Ashok Raj, Peter Zijlstra,
Ravi V Shankar, Xiaoyao Li , Christopherson Sean J, Kalle Valo,
Michael Chan
Cc: linux-kernel, x86, kvm, netdev, linux-wireless, Fenghua Yu
In-Reply-To: <1555536851-17462-1-git-send-email-fenghua.yu@intel.com>
From: Peter Zijlstra <peterz@infradead.org>
A bit in pwol_mask is set in b44_magic_pattern() by atomic set_bit().
But since pwol_mask is local and never exposed to concurrency, there is
no need to set bit in pwol_mask atomically.
set_bit() sets the bit in a single unsigned long location. Because
pwol_mask may not be aligned to unsigned long, the location may cross two
cache lines. On x86, accessing two cache lines in locked instruction in
set_bit() is called split locked access and can cause overall performance
degradation.
So use non atomic __set_bit() to set pwol_mask bits. __set_bit() won't hit
split lock issue on x86.
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
---
drivers/net/ethernet/broadcom/b44.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 97ab0dd25552..5738ab963dfb 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -1520,7 +1520,7 @@ static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset)
memset(ppattern + offset, 0xff, magicsync);
for (j = 0; j < magicsync; j++)
- set_bit(len++, (unsigned long *) pmask);
+ __set_bit(len++, (unsigned long *)pmask);
for (j = 0; j < B44_MAX_PATTERNS; j++) {
if ((B44_PATTERN_SIZE - len) >= ETH_ALEN)
@@ -1532,7 +1532,7 @@ static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset)
for (k = 0; k< ethaddr_bytes; k++) {
ppattern[offset + magicsync +
(j * ETH_ALEN) + k] = macaddr[k];
- set_bit(len++, (unsigned long *) pmask);
+ __set_bit(len++, (unsigned long *)pmask);
}
}
return len - 1;
--
2.19.1
^ permalink raw reply related
* [PATCH v7 10/21] x86/split_lock: Define per CPU variable to cache MSR TEST_CTL
From: Fenghua Yu @ 2019-04-17 21:34 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
Paolo Bonzini, Dave Hansen, Ashok Raj, Peter Zijlstra,
Ravi V Shankar, Xiaoyao Li , Christopherson Sean J, Kalle Valo,
Michael Chan
Cc: linux-kernel, x86, kvm, netdev, linux-wireless, Fenghua Yu,
Xiaoyao Li
In-Reply-To: <1555536851-17462-1-git-send-email-fenghua.yu@intel.com>
MSR TEST_CTL (0x33) value is cached in per CPU variable msr_test_ctl_cache.
The cached value will be used in virutalization to avoid costly MSR read.
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@linux.intel.com>
---
arch/x86/include/asm/cpu.h | 1 +
arch/x86/kernel/cpu/intel.c | 3 +++
2 files changed, 4 insertions(+)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index 4e03f53fc079..cd7493f20234 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -40,6 +40,7 @@ int mwait_usable(const struct cpuinfo_x86 *);
unsigned int x86_family(unsigned int sig);
unsigned int x86_model(unsigned int sig);
unsigned int x86_stepping(unsigned int sig);
+DECLARE_PER_CPU(u64, msr_test_ctl_cache);
#ifdef CONFIG_CPU_SUP_INTEL
void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c);
#else
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 62f61a961eb6..997d683d3c27 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -31,6 +31,9 @@
#include <asm/apic.h>
#endif
+DEFINE_PER_CPU(u64, msr_test_ctl_cache);
+EXPORT_PER_CPU_SYMBOL_GPL(msr_test_ctl_cache);
+
/*
* Just in case our CPU detection goes bad, or you have a weird system,
* allow a way to override the automatic disabling of MPX.
--
2.19.1
^ permalink raw reply related
* [PATCH v7 20/21] x86/clearcpuid: Clear CPUID bit in CPUID faulting
From: Fenghua Yu @ 2019-04-17 21:34 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
Paolo Bonzini, Dave Hansen, Ashok Raj, Peter Zijlstra,
Ravi V Shankar, Xiaoyao Li , Christopherson Sean J, Kalle Valo,
Michael Chan
Cc: linux-kernel, x86, kvm, netdev, linux-wireless, Fenghua Yu
In-Reply-To: <1555536851-17462-1-git-send-email-fenghua.yu@intel.com>
From: Peter Zijlstra <peterz@infradead.org>
After kernel clears a CPUID bit through clearcpuid or other kernel options,
CPUID instruction executed from user space should see the same value for
the bit. The CPUID faulting handler returns the cleared bit to user.
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
---
arch/x86/include/asm/cpufeature.h | 4 +++
arch/x86/kernel/cpu/common.c | 2 ++
arch/x86/kernel/cpu/cpuid-deps.c | 52 ++++++++++++++++++++++++++++
arch/x86/kernel/cpu/intel.c | 56 +++++++++++++++++++++++++++++--
arch/x86/kernel/cpu/scattered.c | 17 ++++++++++
arch/x86/kernel/process.c | 3 ++
arch/x86/kernel/traps.c | 11 ++++++
7 files changed, 142 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 823c4ab82e12..53875fd13f5a 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -228,5 +228,9 @@ static __always_inline __pure bool _static_cpu_has(u16 bit)
#define CPU_FEATURE_TYPEVAL boot_cpu_data.x86_vendor, boot_cpu_data.x86, \
boot_cpu_data.x86_model
+extern int cpuid_fault;
+u32 scattered_cpuid_mask(u32 leaf, u32 count, enum cpuid_regs_idx reg);
+u32 cpuid_cap_mask(u32 leaf, u32 count, enum cpuid_regs_idx reg);
+
#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
#endif /* _ASM_X86_CPUFEATURE_H */
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index e1d41405c27b..020597bca252 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1503,6 +1503,8 @@ void print_cpu_info(struct cpuinfo_x86 *c)
pr_cont(")\n");
}
+int cpuid_fault;
+
/*
* clearcpuid= was already parsed in fpu__init_parse_early_param.
* But we need to keep a dummy __setup around otherwise it would
diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
index 1a71434f7b46..d42aa4fa3021 100644
--- a/arch/x86/kernel/cpu/cpuid-deps.c
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -113,9 +113,61 @@ static void do_clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
{
+ if (boot_cpu_has(feature))
+ cpuid_fault = 1;
do_clear_cpu_cap(c, feature);
}
+u32 cpuid_cap_mask(u32 leaf, u32 count, enum cpuid_regs_idx reg)
+{
+ switch (leaf) {
+ case 0x1:
+ if (reg == CPUID_EDX)
+ return ~cpu_caps_cleared[CPUID_1_EDX];
+ if (reg == CPUID_ECX)
+ return ~cpu_caps_cleared[CPUID_1_ECX];
+ break;
+
+ case 0x6:
+ if (reg == CPUID_EAX)
+ return ~cpu_caps_cleared[CPUID_6_EAX];
+ break;
+
+ case 0x7:
+ if (reg == CPUID_EDX)
+ return ~cpu_caps_cleared[CPUID_7_EDX];
+ if (reg == CPUID_ECX)
+ return ~cpu_caps_cleared[CPUID_7_ECX];
+ if (reg == CPUID_EBX && count == 0)
+ return ~cpu_caps_cleared[CPUID_7_0_EBX];
+ break;
+
+ case 0xD:
+ if (reg == CPUID_EAX)
+ return ~cpu_caps_cleared[CPUID_D_1_EAX];
+ break;
+
+ case 0xF:
+ if (reg == CPUID_EDX) {
+ if (count == 0)
+ return ~cpu_caps_cleared[CPUID_F_0_EDX];
+ if (count == 1)
+ return ~cpu_caps_cleared[CPUID_F_0_EDX];
+ }
+ break;
+
+ case 0x80000007:
+ if (reg == CPUID_EDX) {
+ if (test_bit(X86_FEATURE_CONSTANT_TSC,
+ (unsigned long *)cpu_caps_cleared))
+ return ~(1 << 8);
+ }
+ break;
+ }
+
+ return scattered_cpuid_mask(leaf, count, reg);
+}
+
void setup_clear_cpu_cap(unsigned int feature)
{
do_clear_cpu_cap(NULL, feature);
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index f2c04aa36d78..3005a1e802b7 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -19,6 +19,9 @@
#include <asm/microcode_intel.h>
#include <asm/hwcap2.h>
#include <asm/elf.h>
+#include <asm/insn.h>
+#include <asm/insn-eval.h>
+#include <asm/inat.h>
#ifdef CONFIG_X86_64
#include <linux/topology.h>
@@ -649,13 +652,60 @@ static void intel_bsp_resume(struct cpuinfo_x86 *c)
init_intel_energy_perf(c);
}
+bool fixup_cpuid_exception(struct pt_regs *regs)
+{
+ unsigned int leaf, count, eax, ebx, ecx, edx;
+ unsigned long seg_base = 0;
+ unsigned char buf[2];
+ int not_copied;
+
+ if (!cpuid_fault)
+ return false;
+
+ if (test_thread_flag(TIF_NOCPUID))
+ return false;
+
+ if (!user_64bit_mode(regs))
+ seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS);
+
+ if (seg_base == -1L)
+ return false;
+
+ not_copied = copy_from_user(buf, (void __user *)(seg_base + regs->ip),
+ sizeof(buf));
+ if (not_copied)
+ return false;
+
+ if (buf[0] != 0x0F || buf[1] != 0xA2) /* CPUID - OF A2 */
+ return false;
+
+ leaf = regs->ax;
+ count = regs->cx;
+
+ cpuid_count(leaf, count, &eax, &ebx, &ecx, &edx);
+
+ regs->ip += 2;
+ regs->ax = eax & cpuid_cap_mask(leaf, count, CPUID_EAX);
+ regs->bx = ebx & cpuid_cap_mask(leaf, count, CPUID_EBX);
+ regs->cx = ecx & cpuid_cap_mask(leaf, count, CPUID_ECX);
+ regs->dx = edx & cpuid_cap_mask(leaf, count, CPUID_EDX);
+
+ return true;
+}
+
static void init_cpuid_fault(struct cpuinfo_x86 *c)
{
u64 msr;
- if (!rdmsrl_safe(MSR_PLATFORM_INFO, &msr)) {
- if (msr & MSR_PLATFORM_INFO_CPUID_FAULT)
- set_cpu_cap(c, X86_FEATURE_CPUID_FAULT);
+ if (rdmsrl_safe(MSR_PLATFORM_INFO, &msr))
+ return;
+
+ if (msr & MSR_PLATFORM_INFO_CPUID_FAULT) {
+ set_cpu_cap(c, X86_FEATURE_CPUID_FAULT);
+ if (cpuid_fault) {
+ this_cpu_or(msr_misc_features_shadow,
+ MSR_MISC_FEATURES_ENABLES_CPUID_FAULT);
+ }
}
}
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 94aa1c72ca98..353756c27096 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -62,3 +62,20 @@ void init_scattered_cpuid_features(struct cpuinfo_x86 *c)
set_cpu_cap(c, cb->feature);
}
}
+
+u32 scattered_cpuid_mask(u32 leaf, u32 count, enum cpuid_regs_idx reg)
+{
+ const struct cpuid_bit *cb;
+ u32 mask = ~0U;
+
+ for (cb = cpuid_bits; cb->feature; cb++) {
+ if (cb->level == leaf && cb->sub_leaf == count &&
+ cb->reg == reg) {
+ if (test_bit(cb->feature,
+ (unsigned long *)cpu_caps_cleared))
+ mask &= ~BIT(cb->bit);
+ }
+ }
+
+ return mask;
+}
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 58ac7be52c7a..2b1dfd7ae65d 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -196,6 +196,9 @@ static void set_cpuid_faulting(bool on)
{
u64 msrval;
+ if (cpuid_fault)
+ return;
+
msrval = this_cpu_read(msr_misc_features_shadow);
msrval &= ~MSR_MISC_FEATURES_ENABLES_CPUID_FAULT;
msrval |= (on << MSR_MISC_FEATURES_ENABLES_CPUID_FAULT_BIT);
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index c776bc0a47f5..99e9b15c37d0 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -551,6 +551,12 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, 0, NULL);
}
+#ifdef CONFIG_CPU_SUP_INTEL
+extern bool fixup_cpuid_exception(struct pt_regs *regs);
+#else
+static inline bool fixup_cpuid_exception(struct pt_regs *regs) { return false; }
+#endif
+
dotraplinkage void
do_general_protection(struct pt_regs *regs, long error_code)
{
@@ -565,6 +571,11 @@ do_general_protection(struct pt_regs *regs, long error_code)
return;
}
+ if (static_cpu_has(X86_FEATURE_CPUID_FAULT)) {
+ if (user_mode(regs) && fixup_cpuid_exception(regs))
+ return;
+ }
+
if (v8086_mode(regs)) {
local_irq_enable();
handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
--
2.19.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox