* wl12xx stuck in fw
From: Nicklas Persson @ 2016-10-21 12:57 UTC (permalink / raw)
To: linux-wireless
Hi, I have been debugging my WLAN driver interface for a while. I have
a Beaglebone equivalent board with the TI wl1271 wireless module. I am
very new to linux drivers and wireless configuration so these couple
of days I have spent have been really interesting and I have much more
knowledge now.
My problem is that when I run "ifconfig wlan0 up" I get the following
message over and over again:
"wlcore: ERROR Tx stuck (in FW) for 5000 ms. Starting recover"
I successfully done a calibration, that does not help. I also tried
with the default .nvs file that is provided.
I have tried with different firmware binaries with no luck. Actually,
I have browsed the source code for wl12xx and wlcore and it seems like
I need to use the 5-series of firmware binaries so I have been using
those for the most time.
I have rebuilt the kernel with a lot of added printk()'s all over the
place but I do not understand at all what is happening. My guess is
that there is something with the watchdog and that the driver thinks
that the firmware/wlan module is not responding.
I am really desperate for some guidance or some pointers. What can I try next?
Thanks,
Regards Nicklas.
^ permalink raw reply
* [PATCH 2/2] mac80211: use inline kernel-doc for struct ieee80211_hw
From: Jani Nikula @ 2016-10-21 12:57 UTC (permalink / raw)
To: johannes, linux-wireless; +Cc: linux-doc, Jani Nikula
In-Reply-To: <1477054644-5945-1-git-send-email-jani.nikula@intel.com>
It's easier to manage the kernel-doc for the fields when they
documentation is next to the field.
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
The same treatment is sorely needed for struct ieee80211_ops also, but I
don't have the time... this would get rid of the rest of the warnings in
mac80211.h.
---
include/net/mac80211.h | 280 ++++++++++++++++++++++++++++++-------------------
1 file changed, 173 insertions(+), 107 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e2dba93e374f..7f659c21ffba 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2078,147 +2078,213 @@ enum ieee80211_hw_flags {
/**
* struct ieee80211_hw - hardware information and state
*
- * This structure contains the configuration and hardware
- * information for an 802.11 PHY.
- *
- * @wiphy: This points to the &struct wiphy allocated for this
- * 802.11 PHY. You must fill in the @perm_addr and @dev
- * members of this structure using SET_IEEE80211_DEV()
- * and SET_IEEE80211_PERM_ADDR(). Additionally, all supported
- * bands (with channels, bitrates) are registered here.
- *
- * @conf: &struct ieee80211_conf, device configuration, don't use.
- *
- * @priv: pointer to private area that was allocated for driver use
- * along with this structure.
- *
- * @flags: hardware flags, see &enum ieee80211_hw_flags.
- *
- * @extra_tx_headroom: headroom to reserve in each transmit skb
- * for use by the driver (e.g. for transmit headers.)
- *
- * @extra_beacon_tailroom: tailroom to reserve in each beacon tx skb.
- * Can be used by drivers to add extra IEs.
- *
- * @max_signal: Maximum value for signal (rssi) in RX information, used
- * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
- *
- * @max_listen_interval: max listen interval in units of beacon interval
- * that HW supports
- *
- * @queues: number of available hardware transmit queues for
- * data packets. WMM/QoS requires at least four, these
- * queues need to have configurable access parameters.
- *
- * @rate_control_algorithm: rate control algorithm for this hardware.
- * If unset (NULL), the default algorithm will be used. Must be
- * set before calling ieee80211_register_hw().
- *
- * @vif_data_size: size (in bytes) of the drv_priv data area
- * within &struct ieee80211_vif.
- * @sta_data_size: size (in bytes) of the drv_priv data area
- * within &struct ieee80211_sta.
- * @chanctx_data_size: size (in bytes) of the drv_priv data area
- * within &struct ieee80211_chanctx_conf.
- * @txq_data_size: size (in bytes) of the drv_priv data area
- * within @struct ieee80211_txq.
- *
- * @max_rates: maximum number of alternate rate retry stages the hw
- * can handle.
- * @max_report_rates: maximum number of alternate rate retry stages
- * the hw can report back.
- * @max_rate_tries: maximum number of tries for each stage
- *
- * @max_rx_aggregation_subframes: maximum buffer size (number of
- * sub-frames) to be used for A-MPDU block ack receiver
- * aggregation.
- * This is only relevant if the device has restrictions on the
- * number of subframes, if it relies on mac80211 to do reordering
- * it shouldn't be set.
- *
- * @max_tx_aggregation_subframes: maximum number of subframes in an
- * aggregate an HT driver will transmit. Though ADDBA will advertise
- * a constant value of 64 as some older APs can crash if the window
- * size is smaller (an example is LinkSys WRT120N with FW v1.0.07
- * build 002 Jun 18 2012).
- *
- * @max_tx_fragments: maximum number of tx buffers per (A)-MSDU, sum
- * of 1 + skb_shinfo(skb)->nr_frags for each skb in the frag_list.
- *
- * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
- * (if %IEEE80211_HW_QUEUE_CONTROL is set)
- *
- * @radiotap_mcs_details: lists which MCS information can the HW
- * reports, by default it is set to _MCS, _GI and _BW but doesn't
- * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_\* values, only
- * adding _BW is supported today.
- *
- * @radiotap_vht_details: lists which VHT MCS information the HW reports,
- * the default is _GI | _BANDWIDTH.
- * Use the %IEEE80211_RADIOTAP_VHT_KNOWN_\* values.
- *
- * @radiotap_timestamp: Information for the radiotap timestamp field; if the
- * 'units_pos' member is set to a non-negative value it must be set to
- * a combination of a IEEE80211_RADIOTAP_TIMESTAMP_UNIT_* and a
- * IEEE80211_RADIOTAP_TIMESTAMP_SPOS_* value, and then the timestamp
- * field will be added and populated from the &struct ieee80211_rx_status
- * device_timestamp. If the 'accuracy' member is non-negative, it's put
- * into the accuracy radiotap field and the accuracy known flag is set.
- *
- * @netdev_features: netdev features to be set in each netdev created
- * from this HW. Note that not all features are usable with mac80211,
- * other features will be rejected during HW registration.
- *
- * @uapsd_queues: This bitmap is included in (re)association frame to indicate
- * for each access category if it is uAPSD trigger-enabled and delivery-
- * enabled. Use IEEE80211_WMM_IE_STA_QOSINFO_AC_* to set this bitmap.
- * Each bit corresponds to different AC. Value '1' in specific bit means
- * that corresponding AC is both trigger- and delivery-enabled. '0' means
- * neither enabled.
- *
- * @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP may
- * deliver to a WMM STA during any Service Period triggered by the WMM STA.
- * Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values.
- *
- * @n_cipher_schemes: a size of an array of cipher schemes definitions.
- * @cipher_schemes: a pointer to an array of cipher scheme definitions
- * supported by HW.
- * @max_nan_de_entries: maximum number of NAN DE functions supported by the
- * device.
+ * This structure contains the configuration and hardware information for an
+ * 802.11 PHY.
*/
struct ieee80211_hw {
+ /**
+ * @conf: &struct ieee80211_conf, device configuration, don't use.
+ */
struct ieee80211_conf conf;
+
+ /**
+ * @wiphy: This points to the &struct wiphy allocated for this 802.11
+ * PHY. You must fill in the @perm_addr and @dev members of this
+ * structure using SET_IEEE80211_DEV() and
+ * SET_IEEE80211_PERM_ADDR(). Additionally, all supported bands (with
+ * channels, bitrates) are registered here.
+ */
struct wiphy *wiphy;
+
+ /**
+ * @rate_control_algorithm: rate control algorithm for this hardware.
+ * If unset (NULL), the default algorithm will be used. Must be set
+ * before calling ieee80211_register_hw().
+ */
const char *rate_control_algorithm;
+
+ /**
+ * @priv: pointer to private area that was allocated for driver use
+ * along with this structure.
+ */
void *priv;
+
+ /**
+ * @flags: hardware flags, see &enum ieee80211_hw_flags.
+ */
unsigned long flags[BITS_TO_LONGS(NUM_IEEE80211_HW_FLAGS)];
+
+ /**
+ * @extra_tx_headroom: headroom to reserve in each transmit skb for use
+ * by the driver (e.g. for transmit headers.)
+ */
unsigned int extra_tx_headroom;
+
+ /**
+ * @extra_beacon_tailroom: tailroom to reserve in each beacon tx skb.
+ * Can be used by drivers to add extra IEs.
+ */
unsigned int extra_beacon_tailroom;
+
+ /**
+ * @vif_data_size: size (in bytes) of the drv_priv data area
+ * within &struct ieee80211_vif.
+ */
int vif_data_size;
+
+ /**
+ * @sta_data_size: size (in bytes) of the drv_priv data area within
+ * &struct ieee80211_sta.
+ */
int sta_data_size;
+
+ /**
+ * @chanctx_data_size: size (in bytes) of the drv_priv data area within
+ * &struct ieee80211_chanctx_conf.
+ */
int chanctx_data_size;
+
+ /**
+ * @txq_data_size: size (in bytes) of the drv_priv data area
+ * within @struct ieee80211_txq.
+ */
int txq_data_size;
+
+ /**
+ * @queues: number of available hardware transmit queues for data
+ * packets. WMM/QoS requires at least four, these queues need to have
+ * configurable access parameters.
+ */
u16 queues;
+
+ /**
+ * @max_listen_interval: max listen interval in units of beacon interval
+ * that HW supports
+ */
u16 max_listen_interval;
+
+ /**
+ * @max_signal: Maximum value for signal (rssi) in RX information, used
+ * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
+ */
s8 max_signal;
+
+ /**
+ * @max_rates: maximum number of alternate rate retry stages the hw can
+ * handle.
+ */
u8 max_rates;
+
+ /**
+ * @max_report_rates: maximum number of alternate rate retry stages
+ * the hw can report back.
+ */
u8 max_report_rates;
+
+ /**
+ * @max_rate_tries: maximum number of tries for each stage
+ */
u8 max_rate_tries;
+
+ /**
+ * @max_rx_aggregation_subframes: maximum buffer size (number of
+ * sub-frames) to be used for A-MPDU block ack receiver aggregation.
+ * This is only relevant if the device has restrictions on the number of
+ * subframes, if it relies on mac80211 to do reordering it shouldn't be
+ * set.
+ */
u8 max_rx_aggregation_subframes;
+
+ /**
+ * @max_tx_aggregation_subframes: maximum number of subframes in an
+ * aggregate an HT driver will transmit. Though ADDBA will advertise a
+ * constant value of 64 as some older APs can crash if the window size
+ * is smaller (an example is LinkSys WRT120N with FW v1.0.07 build 002
+ * Jun 18 2012).
+ */
u8 max_tx_aggregation_subframes;
+
+ /**
+ * @max_tx_fragments: maximum number of tx buffers per (A)-MSDU, sum of
+ * 1 + skb_shinfo(skb)->nr_frags for each skb in the frag_list.
+ */
u8 max_tx_fragments;
+
+ /**
+ * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX (if
+ * %IEEE80211_HW_QUEUE_CONTROL is set)
+ */
u8 offchannel_tx_hw_queue;
+
+ /**
+ * @radiotap_mcs_details: lists which MCS information can the HW
+ * reports, by default it is set to _MCS, _GI and _BW but doesn't
+ * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_\* values, only adding
+ * _BW is supported today.
+ */
u8 radiotap_mcs_details;
+
+ /**
+ * @radiotap_vht_details: lists which VHT MCS information the HW
+ * reports, the default is _GI | _BANDWIDTH. Use the
+ * %IEEE80211_RADIOTAP_VHT_KNOWN_\* values.
+ */
u16 radiotap_vht_details;
+
+ /**
+ * @radiotap_timestamp: Information for the radiotap timestamp field; if
+ * the 'units_pos' member is set to a non-negative value it must be set
+ * to a combination of a IEEE80211_RADIOTAP_TIMESTAMP_UNIT_* and a
+ * IEEE80211_RADIOTAP_TIMESTAMP_SPOS_* value, and then the timestamp
+ * field will be added and populated from the &struct
+ * ieee80211_rx_status device_timestamp. If the 'accuracy' member is
+ * non-negative, it's put into the accuracy radiotap field and the
+ * accuracy known flag is set.
+ */
struct {
int units_pos;
s16 accuracy;
} radiotap_timestamp;
+
+ /**
+ * @netdev_features: netdev features to be set in each netdev created
+ * from this HW. Note that not all features are usable with mac80211,
+ * other features will be rejected during HW registration.
+ */
netdev_features_t netdev_features;
+
+ /**
+ * @uapsd_queues: This bitmap is included in (re)association frame to
+ * indicate for each access category if it is uAPSD trigger-enabled and
+ * delivery- enabled. Use IEEE80211_WMM_IE_STA_QOSINFO_AC_* to set this
+ * bitmap. Each bit corresponds to different AC. Value '1' in specific
+ * bit means that corresponding AC is both trigger- and
+ * delivery-enabled. '0' means neither enabled.
+ */
u8 uapsd_queues;
+
+ /**
+ * @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP
+ * may deliver to a WMM STA during any Service Period triggered by the
+ * WMM STA. Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values.
+ */
u8 uapsd_max_sp_len;
+
+ /**
+ * @n_cipher_schemes: a size of an array of cipher schemes definitions.
+ */
u8 n_cipher_schemes;
+
+ /**
+ * @cipher_schemes: a pointer to an array of cipher scheme definitions
+ * supported by HW.
+ */
const struct ieee80211_cipher_scheme *cipher_schemes;
+
+ /**
+ * @max_nan_de_entries: maximum number of NAN DE functions supported by
+ * the device.
+ */
u8 max_nan_de_entries;
};
--
2.1.4
^ permalink raw reply related
* [PATCH 1/2] mac80211: fix some sphinx warnings
From: Jani Nikula @ 2016-10-21 12:57 UTC (permalink / raw)
To: johannes, linux-wireless; +Cc: linux-doc, Jani Nikula
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
include/net/mac80211.h | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a810dfcb83c2..e2dba93e374f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -811,14 +811,18 @@ enum mac80211_rate_control_flags {
* in the control information, and it will be filled by the rate
* control algorithm according to what should be sent. For example,
* if this array contains, in the format { <idx>, <count> } the
- * information
+ * information::
+ *
* { 3, 2 }, { 2, 2 }, { 1, 4 }, { -1, 0 }, { -1, 0 }
+ *
* then this means that the frame should be transmitted
* up to twice at rate 3, up to twice at rate 2, and up to four
* times at rate 1 if it doesn't get acknowledged. Say it gets
* acknowledged by the peer after the fifth attempt, the status
- * information should then contain
+ * information should then contain::
+ *
* { 3, 2 }, { 2, 2 }, { 1, 1 }, { -1, 0 } ...
+ *
* since it was transmitted twice at rate 3, twice at rate 2
* and once at rate 1 after which we received an acknowledgement.
*/
@@ -1168,8 +1172,8 @@ enum mac80211_rx_vht_flags {
* @rate_idx: index of data rate into band's supported rates or MCS index if
* HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
* @vht_nss: number of streams (VHT only)
- * @flag: %RX_FLAG_*
- * @vht_flag: %RX_VHT_FLAG_*
+ * @flag: %RX_FLAG_\*
+ * @vht_flag: %RX_VHT_FLAG_\*
* @rx_flags: internal RX flags for mac80211
* @ampdu_reference: A-MPDU reference number, must be a different value for
* each A-MPDU but the same for each subframe within one A-MPDU
@@ -1432,7 +1436,7 @@ enum ieee80211_vif_flags {
* @probe_req_reg: probe requests should be reported to mac80211 for this
* interface.
* @drv_priv: data area for driver use, will always be aligned to
- * sizeof(void *).
+ * sizeof(void \*).
* @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
*/
struct ieee80211_vif {
@@ -1743,7 +1747,7 @@ struct ieee80211_sta_rates {
* @wme: indicates whether the STA supports QoS/WME (if local devices does,
* otherwise always false)
* @drv_priv: data area for driver use, will always be aligned to
- * sizeof(void *), size is determined in hw information.
+ * sizeof(void \*), size is determined in hw information.
* @uapsd_queues: bitmap of queues configured for uapsd. Only valid
* if wme is supported.
* @max_sp: max Service Period. Only valid if wme is supported.
@@ -2146,12 +2150,12 @@ enum ieee80211_hw_flags {
*
* @radiotap_mcs_details: lists which MCS information can the HW
* reports, by default it is set to _MCS, _GI and _BW but doesn't
- * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only
+ * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_\* values, only
* adding _BW is supported today.
*
* @radiotap_vht_details: lists which VHT MCS information the HW reports,
* the default is _GI | _BANDWIDTH.
- * Use the %IEEE80211_RADIOTAP_VHT_KNOWN_* values.
+ * Use the %IEEE80211_RADIOTAP_VHT_KNOWN_\* values.
*
* @radiotap_timestamp: Information for the radiotap timestamp field; if the
* 'units_pos' member is set to a non-negative value it must be set to
@@ -2486,6 +2490,7 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
* in the software stack cares about, we will, in the future, have mac80211
* tell the driver which information elements are interesting in the sense
* that we want to see changes in them. This will include
+ *
* - a list of information element IDs
* - a list of OUIs for the vendor information element
*
--
2.1.4
^ permalink raw reply related
* Re: sequence diagrams in rst documentation
From: Jani Nikula @ 2016-10-21 12:56 UTC (permalink / raw)
To: Johannes Berg, Jonathan Corbet; +Cc: linux-wireless, linux-doc, Markus Heiser
In-Reply-To: <1477053099.4068.42.camel@sipsolutions.net>
On Fri, 21 Oct 2016, Johannes Berg <johannes@sipsolutions.net> wrote:
>> > https://pythonhosted.org/sphinxcontrib-aafig/
>> >
>> > I've not actually played with it at all, but I like the idea that
>> > we'd have readable diagrams in the source docs as well...
>>
>> Well, maybe. I agree having it readable in the source docs as well is
>> nice, but for sequence diagrams in particular, I don't think
>>
>> +-------+ +-----------+
>> | Hello +-------->+ aafigure! |
>> +-------+ +-----------+
>>
>> really beats
>>
>> Hello -> aafigure!
>
>
> I found another one:
>
> https://pypi.python.org/pypi/sphinxcontrib-plantuml
>
> That one has really nice output and features, but ends up being a
> *java* (of all the things) tool that the thing calls out to ...
>
>
> Perhaps we can have a compromise and embed the raw text when the
> tooling isn't all installed, so you can still build useful
> documentation, but to get all the "prettiness" you might have to
> install more dependencies?
I had the same conclusion for math:: directives pulling in latex
dependency [1]. Hopefully Markus can help here.
BR,
Jani.
[1] http://lkml.kernel.org/r/877f93qdd2.fsf@intel.com
--
Jani Nikula, Intel Open Source Technology Center
^ permalink raw reply
* Re: sequence diagrams in rst documentation
From: Johannes Berg @ 2016-10-21 12:31 UTC (permalink / raw)
To: Jonathan Corbet; +Cc: linux-wireless, linux-doc
In-Reply-To: <1476863488.5927.10.camel@sipsolutions.net>
> > https://pythonhosted.org/sphinxcontrib-aafig/
> >
> > I've not actually played with it at all, but I like the idea that
> > we'd have readable diagrams in the source docs as well...
>
> Well, maybe. I agree having it readable in the source docs as well is
> nice, but for sequence diagrams in particular, I don't think
>
> +-------+ +-----------+
> | Hello +-------->+ aafigure! |
> +-------+ +-----------+
>
> really beats
>
> Hello -> aafigure!
I found another one:
https://pypi.python.org/pypi/sphinxcontrib-plantuml
That one has really nice output and features, but ends up being a
*java* (of all the things) tool that the thing calls out to ...
Perhaps we can have a compromise and embed the raw text when the
tooling isn't all installed, so you can still build useful
documentation, but to get all the "prettiness" you might have to
install more dependencies?
johannes
^ permalink raw reply
* Re: [PATCH v3] cfg80211: Check radar_detect and num_different_channels with beacon interface combinations.
From: Johannes Berg @ 2016-10-21 12:27 UTC (permalink / raw)
To: Purushottam Kushwaha; +Cc: linux-wireless, jouni, usdutt, amarnath
In-Reply-To: <1476371730-23027-1-git-send-email-pkushwah@qti.qualcomm.com>
On Thu, 2016-10-13 at 20:45 +0530, Purushottam Kushwaha wrote:
> This commit enhances the current beacon interval validation to also
> consider
> the "radar_detect" and "num_different_channels".
>
> Move calculation of GCD for all beaconing interfaces to
> "cfg80211_iter_combinations".
>
> Rename "cfg80211_validate_beacon_int" to
> "cfg80211_validate_beacon_combination"
> as the validation considers other parameters.
So this was better, but I think we're mixing too many things in here.
I'm not convinced, for example, that checking if radar is required is
really the right thing, it might still be enabled even if it's not
required (any more, regulatory may change)?
Not that I don't think that's a worthwhile goal - moving more of the
data/calculation back into cfg80211 - but I don't think it should be
mixed in here.
I've just sent out a few patches that, I think, implement the necessary
validation for just the beacon intervals, without all this extra
baggage. Please take a look and let me know what you think.
johannes
^ permalink raw reply
* [PATCH 4/4] mac80211: validate new interface's beacon intervals
From: Johannes Berg @ 2016-10-21 12:25 UTC (permalink / raw)
To: linux-wireless
Cc: Purushottam Kushwaha, jouni, usdutt, amarnath, Johannes Berg
In-Reply-To: <1477052714-11223-1-git-send-email-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
As part of interface combination checking, verify any new
interface's beacon intervals. In fact, just always add the
beacon interval since that's harmless.
With this patch, mac80211 is prepared for drivers that set
the min_beacon_int_gcd parameter in interface combinations.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/cfg.c | 3 ++-
net/mac80211/util.c | 10 ++++++++++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index eb68add4393c..e91e503bf992 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -864,6 +864,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
}
sdata->needed_rx_chains = sdata->local->rx_chains;
+ sdata->vif.bss_conf.beacon_int = params->beacon_interval;
+
mutex_lock(&local->mtx);
err = ieee80211_vif_use_channel(sdata, ¶ms->chandef,
IEEE80211_CHANCTX_SHARED);
@@ -894,7 +896,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
vlan->vif.type);
}
- sdata->vif.bss_conf.beacon_int = params->beacon_interval;
sdata->vif.bss_conf.dtim_period = params->dtim_period;
sdata->vif.bss_conf.enable_beacon = true;
sdata->vif.bss_conf.allow_p2p_go_ps = sdata->vif.p2p;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7f24bdc68f71..ac59fbd280df 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3326,6 +3326,16 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
return -EINVAL;
+ if (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
+ /*
+ * always passing this is harmless, since it'll be the
+ * same value that cfg80211 finds if it finds the same
+ * interface ... and that's always allowed
+ */
+ params.new_beacon_int = sdata->vif.bss_conf.beacon_int;
+ }
+
/* Always allow software iftypes */
if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
if (radar_detect)
--
2.8.1
^ permalink raw reply related
* [PATCH 2/4] cfg80211: disallow beacon_int_min_gcd with IBSS
From: Johannes Berg @ 2016-10-21 12:25 UTC (permalink / raw)
To: linux-wireless
Cc: Purushottam Kushwaha, jouni, usdutt, amarnath, Johannes Berg
In-Reply-To: <1477052714-11223-1-git-send-email-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
This can't really be supported right now, because the IBSS
interface may change its beacon interval at any time due to
joining another network; thus, there's already "support"
for different beacon intervals here, implicitly.
Until we figure out how we should handle this case (continue
to allow it to arbitrarily join? Join only if compatible?)
disallow advertising that different beacon intervals are
supported if IBSS is allowed.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/wireless/core.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 725adff6c7d4..158c59ecf90a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -562,6 +562,21 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
c->limits[j].max > 1))
return -EINVAL;
+ /*
+ * This isn't well-defined right now. If you have an
+ * IBSS interface, then its beacon interval may change
+ * by joining other networks, and nothing prevents it
+ * from doing that.
+ * So technically we probably shouldn't even allow AP
+ * and IBSS in the same interface, but it seems that
+ * some drivers support that, possibly only with fixed
+ * beacon intervals for IBSS.
+ */
+ if (WARN_ON(types & BIT(NL80211_IFTYPE_ADHOC) &&
+ c->beacon_int_min_gcd)) {
+ return -EINVAL;
+ }
+
cnt += c->limits[j].max;
/*
* Don't advertise an unsupported type
--
2.8.1
^ permalink raw reply related
* [PATCH 3/4] cfg80211: validate beacon int as part of iface combinations
From: Johannes Berg @ 2016-10-21 12:25 UTC (permalink / raw)
To: linux-wireless
Cc: Purushottam Kushwaha, jouni, usdutt, amarnath, Johannes Berg
In-Reply-To: <1477052714-11223-1-git-send-email-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
Remove the pointless checking against interface combinations in
the initial basic beacon interval validation, that currently isn't
taking into account radar detection or channels properly. Instead,
just validate the basic range there, and then delay real checking
to the interface combination validation that drivers must do.
This means that drivers wanting to use the beacon_int_min_gcd will
now have to pass the new_beacon_int when validating the AP/mesh
start.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/cfg80211.h | 12 +++-----
net/wireless/util.c | 82 +++++++++++++++++++++++++++++++-------------------
2 files changed, 55 insertions(+), 39 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ec39f891b7a3..d1ffbc3a8e55 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -784,19 +784,15 @@ struct cfg80211_csa_settings {
* @iftype_num: array with the number of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
- * @beacon_int_gcd: a value specifying GCD of all beaconing interfaces,
- * the GCD of a single value is considered the value itself, so for
- * a single interface this should be set to that interface's beacon
- * interval
- * @beacon_int_different: a flag indicating whether or not all beacon
- * intervals (of beaconing interfaces) are different or not.
+ * @new_beacon_int: set this to the beacon interval of a new interface
+ * that's not operating yet, if such is to be checked as part of
+ * the verification
*/
struct iface_combination_params {
int num_different_channels;
u8 radar_detect;
int iftype_num[NUM_NL80211_IFTYPES];
- u32 beacon_int_gcd;
- bool beacon_int_different;
+ u32 new_beacon_int;
};
/**
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 78bf53705466..40d7a6bf9432 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -13,6 +13,7 @@
#include <net/dsfield.h>
#include <linux/if_vlan.h>
#include <linux/mpls.h>
+#include <linux/gcd.h>
#include "core.h"
#include "rdev-ops.h"
@@ -1558,47 +1559,52 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
}
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
-int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
- enum nl80211_iftype iftype, u32 beacon_int)
+static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
+ u32 *beacon_int_gcd,
+ bool *beacon_int_different)
{
struct wireless_dev *wdev;
- struct iface_combination_params params = {
- .beacon_int_gcd = beacon_int, /* GCD(n) = n */
- };
- if (beacon_int < 10 || beacon_int > 10000)
- return -EINVAL;
+ *beacon_int_gcd = 0;
+ *beacon_int_different = false;
- params.iftype_num[iftype] = 1;
- list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
if (!wdev->beacon_interval)
continue;
- params.iftype_num[wdev->iftype]++;
- }
-
- list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
- u32 bi_prev = wdev->beacon_interval;
-
- if (!wdev->beacon_interval)
+ if (!*beacon_int_gcd) {
+ *beacon_int_gcd = wdev->beacon_interval;
continue;
+ }
- /* slight optimisation - skip identical BIs */
- if (wdev->beacon_interval == beacon_int)
+ if (wdev->beacon_interval == *beacon_int_gcd)
continue;
- params.beacon_int_different = true;
-
- /* Get the GCD */
- while (bi_prev != 0) {
- u32 tmp_bi = bi_prev;
+ *beacon_int_different = true;
+ *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval);
+ }
- bi_prev = params.beacon_int_gcd % bi_prev;
- params.beacon_int_gcd = tmp_bi;
- }
+ if (new_beacon_int && *beacon_int_gcd != new_beacon_int) {
+ *beacon_int_different = true;
+ *beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int);
}
+}
- return cfg80211_check_combinations(&rdev->wiphy, ¶ms);
+int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
+ enum nl80211_iftype iftype, u32 beacon_int)
+{
+ /*
+ * This is just a basic pre-condition check; if interface combinations
+ * are possible the driver must already be checking those with a call
+ * to cfg80211_check_combinations(), in which case we'll validate more
+ * through the cfg80211_calculate_bi_data() call and code in
+ * cfg80211_iter_combinations().
+ */
+
+ if (beacon_int < 10 || beacon_int > 10000)
+ return -EINVAL;
+
+ return 0;
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
@@ -1612,6 +1618,21 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
int i, j, iftype;
int num_interfaces = 0;
u32 used_iftypes = 0;
+ u32 beacon_int_gcd;
+ bool beacon_int_different;
+
+ /*
+ * This is a bit strange, since the iteration used to rely only on
+ * the data given by the driver, but here it now relies on context,
+ * in form of the currently operating interfaces.
+ * This is OK for all current users, and saves us from having to
+ * push the GCD calculations into all the drivers.
+ * In the future, this should probably rely more on data that's in
+ * cfg80211 already - the only thing not would appear to be any new
+ * interfaces (while being brought up) and channel/radar data.
+ */
+ cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
+ &beacon_int_gcd, &beacon_int_different);
if (params->radar_detect) {
rcu_read_lock();
@@ -1674,12 +1695,11 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
- if (params->beacon_int_gcd) {
+ if (beacon_int_gcd) {
if (c->beacon_int_min_gcd &&
- params->beacon_int_gcd < c->beacon_int_min_gcd)
+ beacon_int_gcd < c->beacon_int_min_gcd)
goto cont;
- if (!c->beacon_int_min_gcd &&
- params->beacon_int_different)
+ if (!c->beacon_int_min_gcd && beacon_int_different)
goto cont;
}
--
2.8.1
^ permalink raw reply related
* [PATCH 1/4] cfg80211: mesh: track (and thus validate) beacon interval
From: Johannes Berg @ 2016-10-21 12:25 UTC (permalink / raw)
To: linux-wireless
Cc: Purushottam Kushwaha, jouni, usdutt, amarnath, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
This is needed for beacon interval validation; if we don't
store it, then new interfaces added won't validate that the
beacon interval is the same as existing ones. Fix this.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/wireless/mesh.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index fa2066b56f36..2d8518a37eab 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -183,6 +183,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
wdev->mesh_id_len = setup->mesh_id_len;
wdev->chandef = setup->chandef;
+ wdev->beacon_interval = setup->beacon_interval;
}
return err;
@@ -258,6 +259,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
err = rdev_leave_mesh(rdev, dev);
if (!err) {
wdev->mesh_id_len = 0;
+ wdev->beacon_interval = 0;
memset(&wdev->chandef, 0, sizeof(wdev->chandef));
rdev_set_qos_map(rdev, dev, NULL);
}
--
2.8.1
^ permalink raw reply related
* brcmfmac interface combinations
From: Johannes Berg @ 2016-10-21 11:55 UTC (permalink / raw)
To: Arend van Spriel; +Cc: linux-wireless
Hi Arend,
I'm looking into the interface combinations stuff, mostly due to the
patches from QCA to add the support for differing beacon intervals.
One thing that I was considering, was to change the API
for cfg80211_check_combinations() to not require the driver to fill in
the # of interfaces of each given type, but just have it pass the new
one, if present, or so.
However, there's a major difference between brcmfmac and mac80211 (the
only "drivers" using this), namely this: mac80211 allows *adding* any
kind of interface, as long as you don't actually try to operate it.
brcmfmac, on the other hand, prevents even adding an interface if it
doesn't fit the combinations.
I'm wondering if this is intentional?
I suspect that we can't change mac80211 at this point, and the brcmfmac
behaviour might be unexpected to some people who are used to working
with mac80211, but I'm not sure you'd want to change it either?
johannes
^ permalink raw reply
* [mac80211-next:master 25/25] net/mac80211/util.c:3411:8: error: implicit declaration of function 'cfg80211_iter_combinations'
From: kbuild test robot @ 2016-10-21 10:40 UTC (permalink / raw)
To: Johannes Berg; +Cc: kbuild-all, linux-wireless
[-- Attachment #1: Type: text/plain, Size: 2178 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git master
head: 9fd96261756ed32c762d417b2c4dfd1febbbf71c
commit: 9fd96261756ed32c762d417b2c4dfd1febbbf71c [25/25] cfg80211: don't export cfg80211_iter_combinations()
config: x86_64-randconfig-x019-201642 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
git checkout 9fd96261756ed32c762d417b2c4dfd1febbbf71c
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
net/mac80211/util.c: In function 'ieee80211_max_num_channels':
>> net/mac80211/util.c:3411:8: error: implicit declaration of function 'cfg80211_iter_combinations' [-Werror=implicit-function-declaration]
err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms,
^~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/cfg80211_iter_combinations +3411 net/mac80211/util.c
e227300c Purushottam Kushwaha 2016-10-12 3405 ieee80211_chanctx_radar_detect(local, ctx);
6fa001bc Michal Kazior 2014-04-09 3406 }
6fa001bc Michal Kazior 2014-04-09 3407
6fa001bc Michal Kazior 2014-04-09 3408 list_for_each_entry_rcu(sdata, &local->interfaces, list)
e227300c Purushottam Kushwaha 2016-10-12 3409 params.iftype_num[sdata->wdev.iftype]++;
6fa001bc Michal Kazior 2014-04-09 3410
e227300c Purushottam Kushwaha 2016-10-12 @3411 err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms,
e227300c Purushottam Kushwaha 2016-10-12 3412 ieee80211_iter_max_chans,
6fa001bc Michal Kazior 2014-04-09 3413 &max_num_different_channels);
6fa001bc Michal Kazior 2014-04-09 3414 if (err < 0)
:::::: The code at line 3411 was first introduced by commit
:::::: e227300c8395dffaa7614ce7c7666a82180ebc60 cfg80211: pass struct to interface combination check/iter
:::::: TO: Purushottam Kushwaha <pkushwah@qti.qualcomm.com>
:::::: CC: Johannes Berg <johannes.berg@intel.com>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 24924 bytes --]
^ permalink raw reply
* Re: [PATCH] cfg80211: don't export cfg80211_iter_combinations()
From: Johannes Berg @ 2016-10-21 10:24 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <1477045188-13733-1-git-send-email-johannes@sipsolutions.net>
On Fri, 2016-10-21 at 12:19 +0200, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> Nothing uses it outside of cfg80211, and since only
> cfg80211_check_combinations() uses it in the same file
> it can even be static - do that.
>
Err, obviously my git grep foo failed me ... :)
johannes
^ permalink raw reply
* [PATCH] cfg80211: don't export cfg80211_iter_combinations()
From: Johannes Berg @ 2016-10-21 10:19 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
Nothing uses it outside of cfg80211, and since only
cfg80211_check_combinations() uses it in the same file
it can even be static - do that.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/cfg80211.h | 18 ------------------
net/wireless/util.c | 12 ++++++------
2 files changed, 6 insertions(+), 24 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ec39f891b7a3..db3d020d7349 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5628,24 +5628,6 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
int cfg80211_check_combinations(struct wiphy *wiphy,
struct iface_combination_params *params);
-/**
- * cfg80211_iter_combinations - iterate over matching combinations
- *
- * @wiphy: the wiphy
- * @params: the interface combinations parameter
- * @iter: function to call for each matching combination
- * @data: pointer to pass to iter function
- *
- * This function can be called by the driver to check what possible
- * combinations it fits in at a given moment, e.g. for channel switching
- * purposes.
- */
-int cfg80211_iter_combinations(struct wiphy *wiphy,
- struct iface_combination_params *params,
- void (*iter)(const struct ieee80211_iface_combination *c,
- void *data),
- void *data);
-
/*
* cfg80211_stop_iface - trigger interface disconnection
*
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 78bf53705466..8a244fb769e6 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1601,11 +1601,12 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
return cfg80211_check_combinations(&rdev->wiphy, ¶ms);
}
-int cfg80211_iter_combinations(struct wiphy *wiphy,
- struct iface_combination_params *params,
- void (*iter)(const struct ieee80211_iface_combination *c,
- void *data),
- void *data)
+static int
+cfg80211_iter_combinations(struct wiphy *wiphy,
+ struct iface_combination_params *params,
+ void (*iter)(const struct ieee80211_iface_combination *c,
+ void *data),
+ void *data)
{
const struct ieee80211_regdomain *regdom;
enum nl80211_dfs_regions region = 0;
@@ -1694,7 +1695,6 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
return 0;
}
-EXPORT_SYMBOL(cfg80211_iter_combinations);
static void
cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
--
2.8.1
^ permalink raw reply related
* [PATCH] cfg80211: fix beacon interval in interface combination iteration
From: Johannes Berg @ 2016-10-21 10:15 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
We shouldn't abort the iteration with an error when one of the
potential combinations can't accomodate the beacon interval
request, we should just skip that particular combination. Fix
the code to do so.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/wireless/util.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index ec17c2800117..78bf53705466 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1676,10 +1676,8 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if (params->beacon_int_gcd) {
if (c->beacon_int_min_gcd &&
- params->beacon_int_gcd < c->beacon_int_min_gcd) {
- kfree(limits);
- return -EINVAL;
- }
+ params->beacon_int_gcd < c->beacon_int_min_gcd)
+ goto cont;
if (!c->beacon_int_min_gcd &&
params->beacon_int_different)
goto cont;
--
2.8.1
^ permalink raw reply related
* [PATCH 2/2] rsi: Device initialization sequence is changed
From: Prameela Rani Garnepudi @ 2016-10-21 10:10 UTC (permalink / raw)
To: linux-wireless
Cc: kvalo, johannes.berg, hofrat, xypron.glpk, prameela.garnepudi,
Prameela Rani Garnepudi
BT Co-ex support has been added in the firmware and hence BT, COEX queues are
introducted. To support the latest firmware queues, packet processing,
and initialization sequence is modified in the Host.
Common device configuration parameters (tx command frame) need to be send after
common card ready indication from the firmware. This frame contains information
about the driver mode, coex mode, protocols to support etc. Once it is sent,
then second level card ready indication comes for each protocol (WLAN, BT etc).
Currently host supports only WLAN mode. New command frames are added as part
of these changes.
Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
---
drivers/net/wireless/rsi/rsi_91x_main.c | 14 +-
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 281 ++++++++++++++++++++++++----
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 39 +++-
drivers/net/wireless/rsi/rsi_91x_usb.c | 97 ++++++----
drivers/net/wireless/rsi/rsi_main.h | 49 ++++-
drivers/net/wireless/rsi/rsi_mgmt.h | 195 ++++++++++++++++---
drivers/net/wireless/rsi/rsi_usb.h | 1 +
7 files changed, 559 insertions(+), 117 deletions(-)
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 8810862..ad725a4 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -121,11 +121,23 @@ int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)
actual_length = *(u16 *)&frame_desc[0];
offset = *(u16 *)&frame_desc[2];
+ if ((actual_length < (4 + FRAME_DESC_SZ)) || (offset < 4)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: actual_length (%d) is less than 20 or"
+ " offset(%d) is less than 4\n",
+ __func__, actual_length, offset);
+ break;
+ }
queueno = rsi_get_queueno(frame_desc, offset);
length = rsi_get_length(frame_desc, offset);
- extended_desc = rsi_get_extended_desc(frame_desc, offset);
+ if (queueno == RSI_WIFI_DATA_Q || queueno == RSI_WIFI_MGMT_Q)
+ extended_desc = rsi_get_extended_desc(frame_desc,
+ offset);
switch (queueno) {
+ case RSI_COEX_Q:
+ rsi_mgmt_pkt_recv(common, (frame_desc + offset));
+ break;
case RSI_WIFI_DATA_Q:
skb = rsi_prepare_skb(common,
(frame_desc + offset),
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 7aec45a..1bffd7d 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -18,6 +18,16 @@
#include "rsi_mgmt.h"
#include "rsi_common.h"
+struct rsi_config_vals dev_config_vals[] = {
+ {
+ .lp_ps_handshake = 0,
+ .ulp_ps_handshake = 0,
+ .sleep_config_params = 0,
+ .ext_pa_or_bt_coex_en = 0,
+ },
+};
+
+/* Bootup Parameters for 20MHz */
static struct bootup_params boot_params_20 = {
.magic_number = cpu_to_le16(0x5aa5),
.crystal_good_time = 0x0,
@@ -199,6 +209,39 @@ static struct bootup_params boot_params_40 = {
.dcdc_operation_mode = 0x0,
.soc_reset_wait_cnt = 0x0
};
+#define UNUSED_GPIO 1
+#define USED_GPIO 0
+struct rsi_ulp_gpio_vals unused_ulp_gpio_bitmap = {
+ .motion_sensor_gpio_ulp_wakeup = UNUSED_GPIO,
+ .sleep_ind_from_device = UNUSED_GPIO,
+ .ulp_gpio_2 = UNUSED_GPIO,
+ .push_button_ulp_wakeup = UNUSED_GPIO,
+};
+
+struct rsi_soc_gpio_vals unused_soc_gpio_bitmap = {
+ .pspi_csn_0 = USED_GPIO, //GPIO_0
+ .pspi_csn_1 = USED_GPIO, //GPIO_1
+ .host_wakeup_intr = UNUSED_GPIO, //GPIO_2
+ .pspi_data_0 = USED_GPIO, //GPIO_3
+ .pspi_data_1 = USED_GPIO, //GPIO_4
+ .pspi_data_2 = USED_GPIO, //GPIO_5
+ .pspi_data_3 = USED_GPIO, //GPIO_6
+ .i2c_scl = USED_GPIO, //GPIO_7
+ .i2c_sda = USED_GPIO, //GPIO_8
+ .uart1_rx = UNUSED_GPIO, //GPIO_9
+ .uart1_tx = UNUSED_GPIO, //GPIO_10
+ .uart1_rts_i2s_clk = UNUSED_GPIO, //GPIO_11
+ .uart1_cts_i2s_ws = UNUSED_GPIO, //GPIO_12
+ .dbg_uart_rx_i2s_din = UNUSED_GPIO, //GPIO_13
+ .dbg_uart_tx_i2s_dout = UNUSED_GPIO, //GPIO_14
+ .lp_wakeup_boot_bypass = UNUSED_GPIO, //GPIO_15
+ .led_0 = USED_GPIO, //GPIO_16
+ .btcoex_wlan_active_ext_pa_ant_sel_A = UNUSED_GPIO, //GPIO_17
+ .btcoex_bt_priority_ext_pa_ant_sel_B = UNUSED_GPIO, //GPIO_18
+ .btcoex_bt_active_ext_pa_on_off = UNUSED_GPIO, //GPIO_19
+ .rf_reset = USED_GPIO, //GPIO_20
+ .sleep_ind_from_device = UNUSED_GPIO,
+};
static u16 mcs[] = {13, 26, 39, 52, 78, 104, 117, 130};
@@ -218,6 +261,26 @@ static void rsi_set_default_parameters(struct rsi_common *common)
common->fsm_state = FSM_CARD_NOT_READY;
common->iface_down = true;
common->endpoint = EP_2GHZ_20MHZ;
+ common->driver_mode = 1; /* End-to-End Mode */
+#ifdef CONFIG_RSI_COEX
+ common->coex_mode = 4;
+#else
+ common->coex_mode = 1; /*Default coex mode is WIFI alone */
+#endif
+ common->oper_mode = 1;
+ common->ta_aggr = 0;
+ common->skip_fw_load = 0; /* Default disable skipping fw loading */
+ common->lp_ps_handshake_mode = 0; /* Default No HandShake mode*/
+ common->ulp_ps_handshake_mode = 2; /* Default PKT HandShake mode*/
+ common->rf_power_val = 0; /* Default 1.9V */
+ common->device_gpio_type = TA_GPIO; /* Default TA GPIO */
+ common->country_code = 840; /* Default US */
+ common->wlan_rf_power_mode = 0;
+ common->bt_rf_power_mode = 0;
+ common->obm_ant_sel_val = 2;
+ common->antenna_diversity = 0;
+ common->tx_power = RSI_TXPOWER_MAX;
+
}
/**
@@ -301,10 +364,11 @@ static int rsi_load_radio_caps(struct rsi_common *common)
radio_caps = (struct rsi_radio_caps *)skb->data;
radio_caps->desc_word[1] = cpu_to_le16(RADIO_CAPABILITIES);
- radio_caps->desc_word[4] = cpu_to_le16(RSI_RF_TYPE << 8);
+ radio_caps->desc_word[4] = cpu_to_le16(common->channel);
+ radio_caps->desc_word[4] |= cpu_to_le16(RSI_RF_TYPE << 8);
+ radio_caps->desc_word[7] |= cpu_to_le16(RSI_LMAC_CLOCK_80MHZ);
if (common->channel_width == BW_40MHZ) {
- radio_caps->desc_word[7] |= cpu_to_le16(RSI_LMAC_CLOCK_80MHZ);
radio_caps->desc_word[7] |= cpu_to_le16(RSI_ENABLE_40MHZ);
if (common->fsm_state == FSM_MAC_INIT_DONE) {
@@ -345,7 +409,7 @@ static int rsi_load_radio_caps(struct rsi_common *common)
radio_caps->qos_params[ii].txop_q = 0;
}
- for (ii = 0; ii < MAX_HW_QUEUES - 4; ii++) {
+ for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) {
radio_caps->qos_params[ii].cont_win_min_q =
cpu_to_le16(common->edca_params[ii].cw_min);
radio_caps->qos_params[ii].cont_win_max_q =
@@ -356,6 +420,10 @@ static int rsi_load_radio_caps(struct rsi_common *common)
cpu_to_le16(common->edca_params[ii].txop);
}
+ radio_caps->qos_params[BROADCAST_HW_Q].txop_q = 0xffff;
+ radio_caps->qos_params[MGMT_HW_Q].txop_q = 0;
+ radio_caps->qos_params[BEACON_HW_Q].txop_q = 0xffff;
+
memcpy(&common->rate_pwr[0], &gc[0], 40);
for (ii = 0; ii < 20; ii++)
radio_caps->gcpd_per_rate[inx++] =
@@ -469,7 +537,7 @@ static int rsi_hal_send_sta_notify_frame(struct rsi_common *common,
memset(skb->data, 0, sizeof(struct rsi_peer_notify));
peer_notify = (struct rsi_peer_notify *)skb->data;
- peer_notify->command = cpu_to_le16(opmode << 1);
+ peer_notify->command = 0;
switch (notify_event) {
case STA_CONNECTED:
@@ -499,7 +567,6 @@ static int rsi_hal_send_sta_notify_frame(struct rsi_common *common,
if (!status && qos_enable) {
rsi_set_contention_vals(common);
- status = rsi_load_radio_caps(common);
}
return status;
}
@@ -595,6 +662,7 @@ static int rsi_program_bb_rf(struct rsi_common *common)
mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
mgmt_frame->desc_word[1] = cpu_to_le16(BBP_PROG_IN_TA);
mgmt_frame->desc_word[4] = cpu_to_le16(common->endpoint);
+ mgmt_frame->desc_word[3] = cpu_to_le16(common->rf_pwr_mode);
if (common->rf_reset) {
mgmt_frame->desc_word[7] = cpu_to_le16(RF_RESET_ENABLE);
@@ -752,6 +820,53 @@ int rsi_hal_load_key(struct rsi_common *common,
return rsi_send_internal_mgmt_frame(common, skb);
}
+/**
+ * rsi_send_common_dev_params() - This function send the common device
+ * configuration parameters to device.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_send_common_dev_params(struct rsi_common *common)
+{
+ struct sk_buff *skb = NULL;
+ u32 *soc_gpio, len;
+ u16 *frame, *ulp_gpio, *desc;
+
+ len = 0x20;
+
+ skb = dev_alloc_skb(len + FRAME_DESC_SZ);
+ if (!skb)
+ return -ENOMEM;
+ memset(skb->data, 0, len + FRAME_DESC_SZ);
+
+ desc = (u16 *)&skb->data[0];
+ frame = (u16 *)&skb->data[FRAME_DESC_SZ];
+
+ desc[0] = cpu_to_le16(len | (RSI_COEX_Q << 12));
+ desc[1] = cpu_to_le16(COMMON_DEV_CONFIG);
+
+ frame[0] = (u16)common->lp_ps_handshake_mode;
+ frame[0] |= (u16)common->ulp_ps_handshake_mode << 8;
+
+ ulp_gpio = (u16 *)&unused_ulp_gpio_bitmap;
+ soc_gpio = (u32 *)&unused_soc_gpio_bitmap;
+
+ frame[1] |= (*ulp_gpio) << 8;
+ *(u32 *)&frame[2] = *soc_gpio;
+ frame[4] |= ((u16)common->oper_mode << 8);
+ frame[5] |= ((u16)common->wlan_rf_power_mode);
+ frame[5] |= ((u16)common->bt_rf_power_mode << 8);
+ frame[6] |= ((u16)common->driver_mode << 8);
+ frame[7] = 3; //((u16 )d_assets->region_code);
+ frame[7] |= ((u16)common->obm_ant_sel_val << 8);
+
+ skb_put(skb, len + FRAME_DESC_SZ);
+
+ return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+
/*
* rsi_load_bootup_params() - This function send bootup params to the firmware.
* @common: Pointer to the driver private structure.
@@ -1140,6 +1255,7 @@ void rsi_inform_bss_status(struct rsi_common *common,
u16 aid)
{
if (status) {
+ common->hw_data_qs_blocked = true;
rsi_hal_send_sta_notify_frame(common,
RSI_IFTYPE_STATION,
STA_CONNECTED,
@@ -1148,13 +1264,17 @@ void rsi_inform_bss_status(struct rsi_common *common,
aid);
if (common->min_rate == 0xffff)
rsi_send_auto_rate_request(common);
+ if (!rsi_send_block_unblock_frame(common, false))
+ common->hw_data_qs_blocked = false;
} else {
+ common->hw_data_qs_blocked = true;
rsi_hal_send_sta_notify_frame(common,
RSI_IFTYPE_STATION,
STA_DISCONNECTED,
bssid,
qos_enable,
aid);
+ rsi_send_block_unblock_frame(common, true);
}
}
@@ -1168,6 +1288,7 @@ void rsi_inform_bss_status(struct rsi_common *common,
static int rsi_eeprom_read(struct rsi_common *common)
{
struct rsi_mac_frame *mgmt_frame;
+ struct rsi_hw *adapter = common->priv;
struct sk_buff *skb;
rsi_dbg(MGMT_TX_ZONE, "%s: Sending EEPROM read req frame\n", __func__);
@@ -1183,15 +1304,16 @@ static int rsi_eeprom_read(struct rsi_common *common)
mgmt_frame = (struct rsi_mac_frame *)skb->data;
/* FrameType */
- mgmt_frame->desc_word[1] = cpu_to_le16(EEPROM_READ_TYPE);
+ mgmt_frame->desc_word[1] = cpu_to_le16(EEPROM_READ);
mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
/* Number of bytes to read */
- mgmt_frame->desc_word[3] = cpu_to_le16(ETH_ALEN +
- WLAN_MAC_MAGIC_WORD_LEN +
- WLAN_HOST_MODE_LEN +
- WLAN_FW_VERSION_LEN);
+ mgmt_frame->desc_word[3] = cpu_to_le16(adapter->eeprom.length << 4);
+ mgmt_frame->desc_word[2] |= cpu_to_le16(3 << 8);
+
/* Address to read */
- mgmt_frame->desc_word[4] = cpu_to_le16(WLAN_MAC_EEPROM_ADDR);
+ mgmt_frame->desc_word[4] = cpu_to_le16(adapter->eeprom.offset);
+ mgmt_frame->desc_word[5] = cpu_to_le16(adapter->eeprom.offset >> 16);
+ mgmt_frame->desc_word[6] = cpu_to_le16(0); //delay = 0
skb_put(skb, FRAME_DESC_SZ);
@@ -1225,13 +1347,16 @@ int rsi_send_block_unblock_frame(struct rsi_common *common, bool block_event)
mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
mgmt_frame->desc_word[1] = cpu_to_le16(BLOCK_HW_QUEUE);
+ mgmt_frame->desc_word[3] = cpu_to_le16(0x1);
if (block_event) {
rsi_dbg(INFO_ZONE, "blocking the data qs\n");
mgmt_frame->desc_word[4] = cpu_to_le16(0xf);
+ mgmt_frame->desc_word[4] |= cpu_to_le16(0xf << 4);
} else {
rsi_dbg(INFO_ZONE, "unblocking the data qs\n");
mgmt_frame->desc_word[5] = cpu_to_le16(0xf);
+ mgmt_frame->desc_word[5] |= cpu_to_le16(0xf << 4);
}
skb_put(skb, FRAME_DESC_SZ);
@@ -1262,7 +1387,7 @@ int rsi_flash_read(struct rsi_hw *adapter)
cmd_frame = (struct rsi_mac_frame *)skb->data;
/* FrameType */
- cmd_frame->desc_word[1] = cpu_to_le16(EEPROM_READ_TYPE);
+ cmd_frame->desc_word[1] = cpu_to_le16(EEPROM_READ);
/* Format of length and offset differs for
* autoflashing and swbl flashing
@@ -1300,13 +1425,36 @@ int rsi_flash_read(struct rsi_hw *adapter)
static int rsi_handle_ta_confirm_type(struct rsi_common *common,
u8 *msg)
{
+ struct rsi_hw *adapter = common->priv;
u8 sub_type = (msg[15] & 0xff);
switch (sub_type) {
+ case COMMON_DEV_CONFIG:
+ rsi_dbg(FSM_ZONE,
+ "Common Dev Config params confirm received\n");
+ if (common->fsm_state == FSM_COMMON_DEV_PARAMS_SENT) {
+ if (rsi_load_bootup_params(common)) {
+ common->fsm_state = FSM_CARD_NOT_READY;
+ goto out;
+ } else {
+ common->fsm_state = FSM_BOOT_PARAMS_SENT;
+ }
+ } else {
+ rsi_dbg(INFO_ZONE,
+ "%s: Received common dev config params cfm in %d state\n",
+ __func__, common->fsm_state);
+ return 0;
+ }
+ break;
+
case BOOTUP_PARAMS_REQUEST:
rsi_dbg(FSM_ZONE, "%s: Boot up params confirm received\n",
__func__);
if (common->fsm_state == FSM_BOOT_PARAMS_SENT) {
+ adapter->eeprom.length = (IEEE80211_ADDR_LEN +
+ WLAN_MAC_MAGIC_WORD_LEN +
+ WLAN_HOST_MODE_LEN);
+ adapter->eeprom.offset = WLAN_MAC_EEPROM_ADDR;
if (rsi_eeprom_read(common)) {
common->fsm_state = FSM_CARD_NOT_READY;
goto out;
@@ -1321,18 +1469,59 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common,
}
break;
- case EEPROM_READ_TYPE:
+ case EEPROM_READ:
+ rsi_dbg(FSM_ZONE, "EEPROM READ confirm received\n");
if (common->fsm_state == FSM_EEPROM_READ_MAC_ADDR) {
+ u32 msg_len = ((u16 *)msg)[0] & 0xfff;
+
+ if (msg_len <= 0) {
+ rsi_dbg(FSM_ZONE,
+ "%s: [EEPROM_READ] Invalid len %d\n",
+ __func__, msg_len);
+ goto out;
+ }
if (msg[16] == MAGIC_WORD) {
u8 offset = (FRAME_DESC_SZ + WLAN_HOST_MODE_LEN
+ WLAN_MAC_MAGIC_WORD_LEN);
memcpy(common->mac_addr,
&msg[offset],
ETH_ALEN);
- memcpy(&common->fw_ver,
- &msg[offset + ETH_ALEN],
- sizeof(struct version_info));
+ adapter->eeprom.length =
+ ((WLAN_MAC_MAGIC_WORD_LEN + 3) & (~3));
+ adapter->eeprom.offset =
+ WLAN_EEPROM_RFTYPE_ADDR;
+ if (rsi_eeprom_read(common)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed reading RF band\n",
+ __func__);
+ common->fsm_state = FSM_CARD_NOT_READY;
+ } else {
+ common->fsm_state =
+ FSM_EEPROM_READ_RF_TYPE;
+ }
+ } else {
+ common->fsm_state = FSM_CARD_NOT_READY;
+ break;
+ }
+ } else if (common->fsm_state == FSM_EEPROM_READ_RF_TYPE) {
+ u32 msg_len = ((u16 *)msg)[0] & 0xfff;
+ if (msg_len <= 0) {
+ rsi_dbg(FSM_ZONE,
+ "%s:[EEPROM_READ_CFM] Invalid len %d\n",
+ __func__, msg_len);
+ goto out;
+ }
+ if (msg[16] == MAGIC_WORD) {
+ if ((msg[17] & 0x3) == 0x3) {
+ rsi_dbg(INIT_ZONE,
+ "Dual band supported\n");
+ common->band = NL80211_BAND_5GHZ;
+ } else if ((msg[17] & 0x3) == 0x1) {
+ rsi_dbg(INIT_ZONE,
+ "Only 2.4Ghz band supported\n");
+ common->band = NL80211_BAND_2GHZ;
+ }
} else {
common->fsm_state = FSM_CARD_NOT_READY;
break;
@@ -1415,6 +1604,40 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common,
}
/**
+ * rsi_handle_card_ready() - This function handles the card ready
+ * indication from firmware.
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int rsi_handle_card_ready(struct rsi_common *common)
+{
+ switch (common->fsm_state) {
+ case FSM_CARD_NOT_READY:
+ rsi_set_default_parameters(common);
+ if (rsi_send_common_dev_params(common) < 0)
+ return -EINVAL;
+ common->fsm_state = FSM_COMMON_DEV_PARAMS_SENT;
+ break;
+ case FSM_COMMON_DEV_PARAMS_SENT:
+ rsi_dbg(FSM_ZONE, "Card ready indication from wlan.\n");
+ if (rsi_load_bootup_params(common)) {
+ common->fsm_state = FSM_CARD_NOT_READY;
+ return -EINVAL;
+ }
+ common->fsm_state = FSM_BOOT_PARAMS_SENT;
+ break;
+ default:
+ rsi_dbg(ERR_ZONE,
+ "%s: card ready indication in invalid state %d.\n",
+ __func__, common->fsm_state);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
* rsi_mgmt_pkt_recv() - This function processes the management packets
* recieved from the hardware.
* @common: Pointer to the driver private structure.
@@ -1426,34 +1649,26 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg)
{
s32 msg_len = (le16_to_cpu(*(__le16 *)&msg[0]) & 0x0fff);
u16 msg_type = (msg[2]);
- int ret;
rsi_dbg(FSM_ZONE, "%s: Msg Len: %d, Msg Type: %4x\n",
__func__, msg_len, msg_type);
- if (msg_type == TA_CONFIRM_TYPE) {
+ switch (msg_type) {
+ case TA_CONFIRM_TYPE:
return rsi_handle_ta_confirm_type(common, msg);
- } else if (msg_type == CARD_READY_IND) {
- rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n",
- __func__);
- if (common->fsm_state == FSM_CARD_NOT_READY) {
- rsi_set_default_parameters(common);
- ret = rsi_load_bootup_params(common);
- if (ret)
- return ret;
- else
- common->fsm_state = FSM_BOOT_PARAMS_SENT;
- } else {
- return -EINVAL;
- }
- } else if (msg_type == TX_STATUS_IND) {
+ case CARD_READY_IND:
+ return rsi_handle_card_ready(common);
+
+ case TX_STATUS_IND:
if (msg[15] == PROBEREQ_CONFIRM) {
common->mgmt_q_block = false;
rsi_dbg(FSM_ZONE, "%s: Probe confirm received\n",
__func__);
}
- } else {
+ break;
+
+ default:
return rsi_mgmt_pkt_to_core(common, msg, msg_len, msg_type);
}
return 0;
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index c54a534..ad399b5 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -74,17 +74,36 @@ static int rsi_process_pkt(struct rsi_common *common)
u8 num_blks = 0;
u32 rcv_pkt_len = 0;
int status = 0;
+ u8 value = 0;
+ u8 protocol = 0, unaggr_pkt = 0;
+
+#define COEX_PKT 0
+#define WLAN_PKT 3
+#define ZIGB_PKT 1
+#define BT_PKT 2
+ num_blks = ((adapter->interrupt_status & 1) |
+ ((adapter->interrupt_status >> 4) << 1));
+
+ if (!num_blks) {
+ status = rsi_sdio_read_register(adapter,
+ SDIO_RX_NUM_BLOCKS_REG,
+ &value);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to read pkt length from the card:\n",
+ __func__);
+ return status;
+ }
- status = rsi_sdio_read_register(adapter,
- SDIO_RX_NUM_BLOCKS_REG,
- &num_blks);
-
- if (status) {
- rsi_dbg(ERR_ZONE,
- "%s: Failed to read pkt length from the card:\n",
- __func__);
- return status;
+ protocol = value >> 5;
+ num_blks = value & 0x1f;
+ } else {
+ protocol = WLAN_PKT;
}
+
+ if (protocol == BT_PKT || protocol == ZIGB_PKT) //unaggr_pkt FIXME
+ unaggr_pkt = 1;
+
rcv_pkt_len = (num_blks * 256);
common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL);
@@ -233,6 +252,8 @@ void rsi_interrupt_handler(struct rsi_hw *adapter)
mutex_unlock(&common->tx_rxlock);
return;
}
+ adapter->interrupt_status = isr_status;
+ isr_status &= 0xE;
rsi_dbg(ISR_ZONE, "%s: Intr_status = %x %d %d\n",
__func__, isr_status, (1 << MSDU_PKT_PENDING),
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index 84ca609..63104bb 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -41,19 +41,25 @@ static struct rsi_host_intf_ops usb_host_intf_ops = {
* Return: status: 0 on success, a negative error code on failure.
*/
static int rsi_usb_card_write(struct rsi_hw *adapter,
- void *buf,
+ u8 *buf,
u16 len,
- u8 endpoint)
+ u32 endpoint)
{
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
- int status;
- s32 transfer;
+ int status = 0;
+ u8 *seg = dev->tx_buffer;
+ int transfer = 0;
+ int ep = dev->bulkout_endpoint_addr[endpoint - 1];
+
+ memset(seg, 0, len + 128);
+ memcpy(seg + 128, buf, len);
+ len += 128;
+ transfer = len;
status = usb_bulk_msg(dev->usbdev,
- usb_sndbulkpipe(dev->usbdev,
- dev->bulkout_endpoint_addr[endpoint - 1]),
- buf,
- len,
+ usb_sndbulkpipe(dev->usbdev, ep),
+ (void *)seg,
+ (int)len,
&transfer,
HZ * 5);
@@ -61,7 +67,11 @@ static int rsi_usb_card_write(struct rsi_hw *adapter,
rsi_dbg(ERR_ZONE,
"Card write failed with error code :%10d\n", status);
dev->write_fail = 1;
+ goto fail;
}
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sent Message successfully\n", __func__);
+
+fail:
return status;
}
@@ -76,27 +86,23 @@ static int rsi_usb_card_write(struct rsi_hw *adapter,
* Return: 0 on success, a negative error code on failure.
*/
static int rsi_write_multiple(struct rsi_hw *adapter,
- u8 endpoint,
+ u32 addr,
u8 *data,
u32 count)
{
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
- u8 *seg = dev->tx_buffer;
-
- if (dev->write_fail)
- return 0;
+ struct rsi_91x_usbdev *dev =
+ (struct rsi_91x_usbdev *)adapter->rsi_dev;
- if (endpoint == MGMT_EP) {
- memset(seg, 0, RSI_USB_TX_HEAD_ROOM);
- memcpy(seg + RSI_USB_TX_HEAD_ROOM, data, count);
- } else {
- seg = ((u8 *)data - RSI_USB_TX_HEAD_ROOM);
+ if (!adapter || addr == 0) {
+ rsi_dbg(INFO_ZONE,
+ "%s: Unable to write to card\n", __func__);
+ return -1;
}
- return rsi_usb_card_write(adapter,
- seg,
- count + RSI_USB_TX_HEAD_ROOM,
- endpoint);
+ if (dev->write_fail)
+ return -1;
+
+ return rsi_usb_card_write(adapter, data, count, addr);
}
/**
@@ -259,6 +265,11 @@ static void rsi_rx_done_handler(struct urb *urb)
if (urb->status)
return;
+ if (urb->actual_length <= 0) {
+ rsi_dbg(INFO_ZONE, "%s: Zero length packet\n", __func__);
+ return;
+ }
+
rsi_set_event(&dev->rx_thread.event);
}
@@ -386,15 +397,16 @@ int rsi_usb_write_register_multiple(struct rsi_hw *adapter,
rsi_dbg(ERR_ZONE,
"Reg write failed with error code :%d\n",
status);
- } else {
- count -= transfer;
- data += transfer;
- addr += transfer;
+ kfree(buf);
+ return status;
}
+ count -= transfer;
+ data += transfer;
+ addr += transfer;
}
kfree(buf);
- return 0;
+ return status;
}
/**
@@ -410,10 +422,12 @@ int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter,
u8 *pkt,
u32 len)
{
- u32 queueno = ((pkt[1] >> 4) & 0xf);
+ u32 queueno = ((pkt[1] >> 4) & 0x7);
u8 endpoint;
- endpoint = ((queueno == RSI_WIFI_MGMT_Q) ? MGMT_EP : DATA_EP);
+ endpoint = ((queueno == RSI_WIFI_MGMT_Q || queueno == RSI_COEX_Q ||
+ queueno == RSI_WIFI_DATA_Q) ?
+ MGMT_EP : DATA_EP);
return rsi_write_multiple(adapter,
endpoint,
@@ -500,7 +514,7 @@ static void rsi_deinit_usb_interface(struct rsi_hw *adapter)
rsi_kill_thread(&dev->rx_thread);
usb_free_urb(dev->rx_usb_urb[0]);
kfree(adapter->priv->rx_data_pkt);
- kfree(dev->tx_buffer);
+ kfree(dev->saved_tx_buffer);
}
/**
@@ -516,6 +530,7 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
struct rsi_91x_usbdev *rsi_dev;
struct rsi_common *common = adapter->priv;
int status;
+ u8 dword_align_bytes = 0;
rsi_dev = kzalloc(sizeof(*rsi_dev), GFP_KERNEL);
if (!rsi_dev)
@@ -530,18 +545,29 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
adapter->device = &pfunction->dev;
usb_set_intfdata(pfunction, adapter);
- common->rx_data_pkt = kmalloc(2048, GFP_KERNEL);
+ common->rx_data_pkt = kmalloc(2000 * 4, GFP_KERNEL | GFP_DMA);
if (!common->rx_data_pkt) {
rsi_dbg(ERR_ZONE, "%s: Failed to allocate memory\n",
__func__);
return -ENOMEM;
}
+ common->saved_rx_data_pkt = common->rx_data_pkt;
+ dword_align_bytes = (u32)common->rx_data_pkt & 0x3f;
+ if (dword_align_bytes)
+ common->rx_data_pkt = common->rx_data_pkt +
+ (64 - dword_align_bytes);
rsi_dev->tx_buffer = kmalloc(2048, GFP_KERNEL);
if (!rsi_dev->tx_buffer) {
status = -ENOMEM;
goto fail_tx;
}
+ rsi_dev->saved_tx_buffer = rsi_dev->tx_buffer;
+ dword_align_bytes = (u32)rsi_dev->tx_buffer & 0x3f;
+ if (dword_align_bytes)
+ rsi_dev->tx_buffer = rsi_dev->tx_buffer +
+ (64 - dword_align_bytes);
+
rsi_dev->rx_usb_urb[0] = usb_alloc_urb(0, GFP_KERNEL);
if (!rsi_dev->rx_usb_urb[0]) {
status = -ENOMEM;
@@ -549,6 +575,7 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
}
rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt;
rsi_dev->tx_blk_size = 252;
+ adapter->tx_blk_size = rsi_dev->tx_blk_size;
/* Initializing function callbacks */
adapter->rx_urb_submit = rsi_rx_urb_submit;
@@ -575,9 +602,9 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
fail_thread:
usb_free_urb(rsi_dev->rx_usb_urb[0]);
fail_rx:
- kfree(rsi_dev->tx_buffer);
+ kfree(rsi_dev->saved_tx_buffer);
fail_tx:
- kfree(common->rx_data_pkt);
+ kfree(common->saved_rx_data_pkt);
return status;
}
@@ -595,7 +622,7 @@ static int rsi_probe(struct usb_interface *pfunction,
{
struct rsi_hw *adapter;
struct rsi_91x_usbdev *dev;
- u32 fw_status;
+ u32 fw_status = 0;
int status;
rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index 752c429..49e9fdf 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -32,12 +32,14 @@
#define ISR_ZONE BIT(8) /* For Interrupt Msgs */
#define FSM_CARD_NOT_READY 0
-#define FSM_BOOT_PARAMS_SENT 1
-#define FSM_EEPROM_READ_MAC_ADDR 2
-#define FSM_RESET_MAC_SENT 3
-#define FSM_RADIO_CAPS_SENT 4
-#define FSM_BB_RF_PROG_SENT 5
-#define FSM_MAC_INIT_DONE 6
+#define FSM_COMMON_DEV_PARAMS_SENT 1
+#define FSM_BOOT_PARAMS_SENT 2
+#define FSM_EEPROM_READ_MAC_ADDR 3
+#define FSM_EEPROM_READ_RF_TYPE 4
+#define FSM_RESET_MAC_SENT 5
+#define FSM_RADIO_CAPS_SENT 6
+#define FSM_BB_RF_PROG_SENT 7
+#define FSM_MAC_INIT_DONE 8
extern u32 rsi_zone_enabled;
extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
@@ -54,12 +56,23 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
#define MAC_80211_HDR_FRAME_CONTROL 0
#define WME_NUM_AC 4
#define NUM_SOFT_QUEUES 5
-#define MAX_HW_QUEUES 8
+#define MAX_HW_QUEUES 12
#define INVALID_QUEUE 0xff
#define MAX_CONTINUOUS_VO_PKTS 8
#define MAX_CONTINUOUS_VI_PKTS 4
+#define MGMT_HW_Q 10 /* Queue No 10 is used for
+ * MGMT_QUEUE in Device FW,
+ * Hence this is Reserved
+ */
+#define BROADCAST_HW_Q 9
+#define BEACON_HW_Q 11
+#define MAX_NUM_SCAN_BGCHANS 24
/* Queue information */
+#define RSI_COEX_Q 0x0
+#define RSI_ZIGB_Q 0x1
+#define RSI_BT_Q 0x2
+#define RSI_WLAN_Q 0x3
#define RSI_WIFI_MGMT_Q 0x4
#define RSI_WIFI_DATA_Q 0x5
#define IEEE80211_MGMT_FRAME 0x00
@@ -190,6 +203,7 @@ struct rsi_common {
/* Generic */
u8 channel;
u8 *rx_data_pkt;
+ u8 *saved_rx_data_pkt;
u8 mac_id;
u8 radio_id;
u16 rate_pwr[20];
@@ -204,8 +218,27 @@ struct rsi_common {
struct cqm_info cqm_info;
bool hw_data_qs_blocked;
-
+ u8 driver_mode;
u8 coex_mode;
+ u8 oper_mode;
+ u8 ta_aggr;
+ u8 skip_fw_load;
+ u8 lp_ps_handshake_mode;
+ u8 ulp_ps_handshake_mode;
+ u8 uapsd_bitmap;
+ u8 rf_power_val;
+ u8 device_gpio_type;
+ u16 country_code;
+ u8 wlan_rf_power_mode;
+ u8 bt_rf_power_mode;
+ u8 obm_ant_sel_val;
+ u8 antenna_diversity;
+ u16 rf_pwr_mode;
+ char antenna_gain[2];
+ u8 host_wakeup_intr_enable;
+ u8 host_wakeup_intr_active_high;
+ int tx_power;
+ u8 ant_in_use;
};
enum host_intf {
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index f8823126..b0bbb5a 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -43,13 +43,32 @@
#define WLAN_HOST_MODE_LEN 0x04
#define WLAN_FW_VERSION_LEN 0x08
#define MAGIC_WORD 0x5A
+#define WLAN_EEPROM_RFTYPE_ADDR 424
/* Receive Frame Types */
-#define TA_CONFIRM_TYPE 0x01
-#define RX_DOT11_MGMT 0x02
-#define TX_STATUS_IND 0x04
+enum rx_cmd_type {
+ CARD_READY_IND = 0x0,
+ TA_CONFIRM_TYPE = 0x01,
+ RX_DOT11_MGMT = 0x02,
+ RX_DOT11_DATA = 0x03,
+ TX_STATUS_IND = 0x04,
+ PS_NOTIFY_IND = 0x05,
+ SLEEP_NOTIFY_IND = 0x06,
+ DECRYPT_ERROR_IND = 0x07,
+ BEACON_EVENT_IND = 0x08,
+ DEBUG_IND = 0x09,
+ RX_MISC_IND = 0xa,
+ UNCONNECTED_PEER = 0xb,
+ HW_BMISS_EVENT = 0xc,
+ RATE_GC_TABLE_UPDATE = 0xd,
+ RADAR_DETECTED = 0x0e,
+ TSF_SYNC_CONFIRM = 0xc0,
+ ANTENNA_SELECT = 0xf,
+};
+
+#define EAPOL4_CONFIRM 1
#define PROBEREQ_CONFIRM 2
-#define CARD_READY_IND 0x00
+#define NULLDATA_CONFIRM 3
#define RSI_DELETE_PEER 0x0
#define RSI_ADD_PEER 0x1
@@ -62,6 +81,7 @@
#define RF_RESET_ENABLE BIT(3)
#define RATE_INFO_ENABLE BIT(0)
#define RSI_BROADCAST_PKT BIT(9)
+#define RSI_DESC_11G_MODE BIT(7)
#define RSI_DESC_REQUIRE_CFM_TO_HOST BIT(10)
#define UPPER_20_ENABLE (0x2 << 12)
@@ -75,7 +95,7 @@
#define RX_BA_INDICATION 1
#define RSI_TBL_SZ 40
#define MAX_RETRIES 8
-#define RSI_IFTYPE_STATION 0
+#define RSI_IFTYPE_STATION 1
#define STD_RATE_MCS7 0x07
#define STD_RATE_MCS6 0x06
@@ -141,6 +161,44 @@
#define RSI_SUPP_FILTERS (FIF_ALLMULTI | FIF_PROBE_REQ |\
FIF_BCN_PRBRESP_PROMISC)
+
+/* Power save handshake types */
+#define NO_HAND_SHAKE 0
+#define GPIO_HAND_SHAKE 1
+#define PACKET_HAND_SHAKE 2
+#define TA_GPIO 0
+#define ULP_GPIO 1
+#define RF_POWER_3_3 1
+#define RF_POWER_1_9 0
+
+/* 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)
+
+#define RSI_TXPOWER_MAX 30
+#define RSI_TXPOWER_MIN -127
+
+#define DEEP_SLEEP 1
+#define CONNECTED_SLEEP 2
+
+#define SLEEP_REQUEST 1
+#define WAKEUP_REQUEST 2
+
+#define RSI_TXPOWER_MAX 30
+#define RSI_TXPOWER_MIN -127
+
+#define IEEE80211_MARKALL_UAPSD_QUEUES \
+ (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO | \
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
+#define IEEE80211_STA_SP_ALL_PKTS 0x00
+
enum opmode {
STA_OPMODE = 1,
AP_OPMODE = 2
@@ -160,32 +218,51 @@ enum sta_notify_events {
/* Send Frames Types */
enum cmd_frame_type {
- TX_DOT11_MGMT,
- RESET_MAC_REQ,
- RADIO_CAPABILITIES,
- BB_PROG_VALUES_REQUEST,
- RF_PROG_VALUES_REQUEST,
- WAKEUP_SLEEP_REQUEST,
- SCAN_REQUEST,
- TSF_UPDATE,
- PEER_NOTIFY,
- BLOCK_HW_QUEUE,
- SET_KEY_REQ,
- AUTO_RATE_IND,
- BOOTUP_PARAMS_REQUEST,
- VAP_CAPABILITIES,
- EEPROM_READ_TYPE ,
- EEPROM_WRITE,
- GPIO_PIN_CONFIG ,
- SET_RX_FILTER,
- AMPDU_IND,
- STATS_REQUEST_FRAME,
- BB_BUF_PROG_VALUES_REQ,
- BBP_PROG_IN_TA,
- BG_SCAN_PARAMS,
- BG_SCAN_PROBE_REQ,
- CW_MODE_REQ,
- PER_CMD_PKT
+ TX_DOT11_MGMT = 0,
+ RESET_MAC_REQ, /* 0x1 */
+ RADIO_CAPABILITIES, /* 0x2 */
+ BB_PROG_VALUES_REQUEST, /* 0x3 */
+ RF_PROG_VALUES_REQUEST, /* 0x4 */
+ WAKEUP_SLEEP_REQUEST, /* 0x5 */
+ SCAN_REQUEST, /* 0x6 */
+ TSF_UPDATE, /* 0x7 */
+ PEER_NOTIFY, /* 0x8 */
+ BLOCK_HW_QUEUE, /* 0x9 */
+ SET_KEY_REQ, /* 0xA */
+ AUTO_RATE_IND, /* 0xB */
+ BOOTUP_PARAMS_REQUEST, /* 0xC */
+ VAP_CAPABILITIES, /* 0xD */
+ EEPROM_READ, /* 0xE */
+ EEPROM_WRITE, /* 0xF */
+ GPIO_PIN_CONFIG, /* 0x10 */
+ SET_RX_FILTER, /* 0x11 */
+ AMPDU_IND, /* 0x12 */
+ STATS_REQUEST, /* 0x13 */
+ BB_BUF_PROG_VALUES_REQ, /* 0x14 */
+ BBP_PROG_IN_TA, /* 0x15 */
+ BG_SCAN_PARAMS, /* 0x16 */
+ BG_SCAN_PROBE_REQ, /* 0x17 */
+ CW_MODE_REQ, /* 0x18 */
+ PER_CMD_PKT, /* 0x19 */
+ DEV_SLEEP_REQUEST, /* 0x1A */
+ DEV_WAKEUP_CNF, /* 0x1B */
+ RF_LOOPBACK_REQ, /* 0x1C */
+ RF_LPBK_M3, /* 0x1D */
+ RF_RESET_FRAME, /* 0x1E */
+ LMAC_REG_OPS, /* 0x1F */
+ ANT_SEL_FRAME, /* 0x20 */
+ CONFIRM, /* 0x21 */
+ WLAN_DE_REGISTER, /* 0x22 */
+ DEBUG_FRAME, /* 0x23 */
+ HW_BMISS_HANDLE, /* 0x24 */
+ MULTICAST_ENABLE, /* 0x25 */
+ TX_MISC_IND, /* 0x26 */
+ VAP_DYNAMIC_UPDATE, /* 0x27 */
+ COMMON_DEV_CONFIG, /* 0x28 */
+ RADIO_PARAMS_UPDATE, /* 0x29 */
+ RADAR_REQUEST, /* 0x2A */
+ WOWLAN_CONFIG_PARAMS, /* 2B */
+ IAP_CONFIG, /* 0x2C */
};
struct rsi_mac_frame {
@@ -220,6 +297,7 @@ struct rsi_vap_caps {
__le32 default_data_rate;
__le16 beacon_interval;
__le16 dtim_period;
+ __le16 beacon_miss_threshold;
} __packed;
struct rsi_set_key {
@@ -262,6 +340,61 @@ struct rsi_radio_caps {
__le16 preamble_type;
} __packed;
+struct rsi_ulp_gpio_vals {
+ u8 motion_sensor_gpio_ulp_wakeup : 1;
+ u8 sleep_ind_from_device : 1;
+ u8 ulp_gpio_2 :1;
+ u8 push_button_ulp_wakeup : 1;
+ u8 reserved : 4;
+} __packed;
+
+struct rsi_soc_gpio_vals {
+ u32 pspi_csn_0 : 1;
+ u32 pspi_csn_1 : 1;
+ u32 host_wakeup_intr :1;
+ u32 pspi_data_0 : 1;
+ u32 pspi_data_1 : 1;
+ u32 pspi_data_2 : 1;
+ u32 pspi_data_3 : 1;
+ u32 i2c_scl :1;
+ u32 i2c_sda :1;
+ u32 uart1_rx :1;
+ u32 uart1_tx :1;
+ u32 uart1_rts_i2s_clk :1;
+ u32 uart1_cts_i2s_ws :1;
+ u32 dbg_uart_rx_i2s_din :1;
+ u32 dbg_uart_tx_i2s_dout :1;
+ u32 lp_wakeup_boot_bypass :1;
+ u32 led_0 :1;
+ u32 btcoex_wlan_active_ext_pa_ant_sel_A :1;
+ u32 btcoex_bt_priority_ext_pa_ant_sel_B :1;
+ u32 btcoex_bt_active_ext_pa_on_off :1;
+ u32 rf_reset :1;
+ u32 sleep_ind_from_device :1;
+} __packed;
+
+struct rsi_config_vals {
+ u16 desc_word[8];
+ u8 lp_ps_handshake;
+ u8 ulp_ps_handshake;
+ u8 sleep_config_params; /* 0 for no handshake,
+ * 1 for GPIO based handshake,
+ * 2 packet handshake
+ */
+ u8 unused_ulp_gpio;
+ u32 unused_soc_gpio_bitmap;
+ u8 ext_pa_or_bt_coex_en;
+ u8 opermode;
+ u8 wlan_rf_pwr_mode;
+ u8 bt_rf_pwr_mode;
+ u8 zigbee_rf_pwr_mode;
+ u8 driver_mode;
+ u8 region_code;
+ u8 antenna_sel_val;
+#define EXT_PA 1
+#define EXT_BT_COEX 2
+} __packed;
+
static inline u32 rsi_get_queueno(u8 *addr, u16 offset)
{
return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12;
diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h
index d21d40d..b20b99d 100644
--- a/drivers/net/wireless/rsi/rsi_usb.h
+++ b/drivers/net/wireless/rsi/rsi_usb.h
@@ -42,6 +42,7 @@ struct rsi_91x_usbdev {
struct usb_interface *pfunction;
struct urb *rx_usb_urb[MAX_RX_URBS];
u8 *tx_buffer;
+ u8 *saved_tx_buffer;
__le16 bulkin_size;
u8 bulkin_endpoint_addr;
__le16 bulkout_size[MAX_BULK_EP];
--
2.4.11
^ permalink raw reply related
* [PATCH 1/2] rsi: New firware loading method for RSI 91X devices
From: Prameela Rani Garnepudi @ 2016-10-21 10:09 UTC (permalink / raw)
To: linux-wireless
Cc: kvalo, johannes.berg, hofrat, xypron.glpk, prameela.garnepudi,
Prameela Rani Garnepudi
RSI deprecated the old firmware loading method and introduced
new method using soft boot loader for 9113 chipsets.
Current driver only supports 9113 device model hence firmware
loading method has been changed.
In the new method, complete RAM image and flash image are present
in the flash. Two firmwares present in the device, Boot loader firmware
and functional firmware. Boot loader firmware is fixed but functional
firmware can be changed. Before loading the functional firmware, host
issues commands to check whether existing firmware in the chip and the
firmware file content to load are same or not. If not, host issues
commands to load the RAM image and then boot loaded switches to the
functioanl firmware.
Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
---
drivers/net/wireless/rsi/Makefile | 2 +-
drivers/net/wireless/rsi/rsi_91x_hal.c | 1049 +++++++++++++++++++++++++++
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 49 ++
drivers/net/wireless/rsi/rsi_91x_pkt.c | 215 ------
drivers/net/wireless/rsi/rsi_91x_sdio.c | 231 +++++-
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 192 +----
drivers/net/wireless/rsi/rsi_91x_usb.c | 176 ++++-
drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 130 +---
drivers/net/wireless/rsi/rsi_common.h | 4 +
drivers/net/wireless/rsi/rsi_hal.h | 150 ++++
drivers/net/wireless/rsi/rsi_main.h | 68 +-
drivers/net/wireless/rsi/rsi_mgmt.h | 2 +
drivers/net/wireless/rsi/rsi_sdio.h | 18 +-
drivers/net/wireless/rsi/rsi_usb.h | 14 +-
14 files changed, 1720 insertions(+), 580 deletions(-)
create mode 100644 drivers/net/wireless/rsi/rsi_91x_hal.c
delete mode 100644 drivers/net/wireless/rsi/rsi_91x_pkt.c
create mode 100644 drivers/net/wireless/rsi/rsi_hal.h
diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile
index 25828b6..a475c81 100644
--- a/drivers/net/wireless/rsi/Makefile
+++ b/drivers/net/wireless/rsi/Makefile
@@ -2,7 +2,7 @@ rsi_91x-y += rsi_91x_main.o
rsi_91x-y += rsi_91x_core.o
rsi_91x-y += rsi_91x_mac80211.o
rsi_91x-y += rsi_91x_mgmt.o
-rsi_91x-y += rsi_91x_pkt.o
+rsi_91x-y += rsi_91x_hal.o
rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o
rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
new file mode 100644
index 0000000..178d411
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -0,0 +1,1049 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Developers
+ * Prameela Rani Garnepudi 2016 <prameela.garnepudi@redpinesignals.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/firmware.h>
+#include <linux/version.h>
+#include <linux/jiffies.h>
+#include "rsi_mgmt.h"
+#include "rsi_hal.h"
+#include "rsi_sdio.h"
+#include "rsi_common.h"
+
+/* FLASH Firmware */
+struct ta_metadata metadata_flash_content[] = {
+ {"flash_content", 0x00010000},
+ {"RS9113_WLAN_QSPI.rps", 0x00010000},
+ {"RS9113_WLAN_BT_DUAL_MODE.rps", 0x00010000},
+ {"RS9113_WLAN_ZIGBEE.rps", 0x00010000},
+ {"RS9113_AP_BT_DUAL_MODE.rps", 0x00010000},
+ {"RS9113_WLAN_QSPI.rps", 0x00010000}
+};
+
+/**
+ * rsi_send_data_pkt() - This function sends the received data packet from
+ * driver to device.
+ * @common: Pointer to the driver private structure.
+ * @skb: Pointer to the socket buffer structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_hdr *wh = NULL;
+ struct ieee80211_tx_info *info;
+ struct skb_info *tx_params;
+ struct ieee80211_bss_conf *bss = NULL;
+ int status = -EINVAL;
+ u8 ieee80211_hdr_size = MIN_802_11_HDR_LEN;
+ u8 dword_align_bytes = 0;
+ u8 header_size = 0;
+ __le16 *frame_desc;
+ struct xtended_desc *xtend_desc;
+ u16 seq_num = 0;
+
+ info = IEEE80211_SKB_CB(skb);
+ bss = &info->control.vif->bss_conf;
+ tx_params = (struct skb_info *)info->driver_data;
+
+ if (!bss->assoc)
+ goto err;
+
+ dword_align_bytes = ((uintptr_t)skb->data & 0x3f);
+ header_size = dword_align_bytes + FRAME_DESC_SZ +
+ sizeof(struct xtended_desc);
+ if (header_size > skb_headroom(skb)) {
+ rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__);
+ status = -ENOSPC;
+ goto err;
+ }
+
+ skb_push(skb, header_size);
+ frame_desc = (__le16 *)&skb->data[0];
+ xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ];
+ memset((u8 *)frame_desc, 0, header_size);
+
+ wh = (struct ieee80211_hdr *)&skb->data[header_size];
+ seq_num = (le16_to_cpu(wh->seq_ctrl) >> 4);
+
+ frame_desc[2] = cpu_to_le16(header_size - FRAME_DESC_SZ);
+ if (ieee80211_is_data_qos(wh->frame_control)) {
+ ieee80211_hdr_size += 2;
+ frame_desc[6] |= cpu_to_le16(BIT(12));
+ }
+
+ if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) &&
+ (common->secinfo.security_enable)) {
+ if (rsi_is_cipher_wep(common))
+ ieee80211_hdr_size += 4;
+ else
+ ieee80211_hdr_size += 8;
+ frame_desc[6] |= cpu_to_le16(BIT(15));
+ }
+
+ frame_desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) |
+ (RSI_WIFI_DATA_Q << 12));
+ frame_desc[2] |= cpu_to_le16(ieee80211_hdr_size << 8);
+
+ if (common->min_rate != 0xffff) {
+ /* Send fixed rate */
+ frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE);
+ frame_desc[4] = cpu_to_le16(common->min_rate);
+
+ if (conf_is_ht40(&common->priv->hw->conf))
+ frame_desc[5] = cpu_to_le16(FULL40M_ENABLE);
+
+ if ((common->vif_info[0].sgi) && (common->min_rate & 0x100)) {
+ /* Only MCS rates */
+ frame_desc[4] |= cpu_to_le16(ENABLE_SHORTGI_RATE);
+ }
+ }
+
+ if ((skb->data[header_size + 12] == 0x88) &&
+ (skb->data[header_size + 12] == 0x8e)) {
+ rsi_dbg(INFO_ZONE, "*** Tx EAPOL ***\n");
+ frame_desc[6] |= cpu_to_le16(BIT(13));
+ frame_desc[1] |= cpu_to_le16(BIT(12));
+#define EAPOL_RETRY_CNT 15
+ xtend_desc->retry_cnt = EAPOL_RETRY_CNT;
+ }
+
+ frame_desc[6] |= cpu_to_le16(seq_num & 0xfff);
+ frame_desc[7] = cpu_to_le16(((tx_params->tid & 0xf) << 4) |
+ (skb->priority & 0xf) |
+ (tx_params->sta_id << 8));
+
+ status = adapter->host_intf_ops->write_pkt(common->priv,
+ skb->data, skb->len);
+ if (status)
+ rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__);
+
+err:
+ ++common->tx_stats.total_tx_pkt_freed[skb->priority];
+ rsi_indicate_tx_status(common->priv, skb, status);
+ return status;
+}
+
+/**
+ * rsi_send_mgmt_pkt() - This functions prepares the descriptor for
+ * the given management packet and send to device.
+ * @common: Pointer to the driver private structure.
+ * @skb: Pointer to the socket buffer structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int rsi_send_mgmt_pkt(struct rsi_common *common,
+ struct sk_buff *skb)
+{
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_hdr *wh = NULL;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_bss_conf *bss = NULL;
+ struct ieee80211_hw *hw = adapter->hw;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct skb_info *tx_params;
+ int status = -E2BIG;
+ __le16 *desc = NULL;
+ struct xtended_desc *xtend_desc = NULL;
+ u8 header_size = 0;
+ u8 vap_id = 0;
+ u32 dword_align_req_bytes = 0;
+
+ info = IEEE80211_SKB_CB(skb);
+ tx_params = (struct skb_info *)info->driver_data;
+
+ if (tx_params->flags & INTERNAL_MGMT_PKT) {
+ skb->data[1] |= BIT(7); /* Immediate Wakeup bit*/
+ status = adapter->host_intf_ops->write_pkt(common->priv,
+ (u8 *)skb->data,
+ skb->len);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to write the packet\n",
+ __func__);
+ }
+ dev_kfree_skb(skb);
+ return status;
+ }
+
+ /* Update header size */
+ header_size = FRAME_DESC_SZ + sizeof(struct xtended_desc) +
+ dword_align_req_bytes;
+ if (header_size > skb_headroom(skb)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to add extended descriptor\n",
+ __func__);
+ goto err;
+ }
+ skb_push(skb, header_size);
+ memset(&skb->data[0], 0, header_size);
+
+ bss = &info->control.vif->bss_conf;
+ wh = (struct ieee80211_hdr *)&skb->data[header_size];
+
+ desc = (__le16 *)skb->data;
+ xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ];
+
+ if (skb->len > MAX_MGMT_PKT_SIZE) {
+ rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__);
+ goto err;
+ }
+
+ desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) |
+ (RSI_WIFI_MGMT_Q << 12));
+ desc[1] = cpu_to_le16(TX_DOT11_MGMT);
+ desc[2] = cpu_to_le16(MIN_802_11_HDR_LEN << 8);
+ desc[2] |= cpu_to_le16(header_size - FRAME_DESC_SZ);
+ desc[3] = cpu_to_le16(RATE_INFO_ENABLE);
+ if (wh->addr1[0] & BIT(0))
+ desc[3] |= cpu_to_le16(RSI_BROADCAST_PKT);
+ desc[6] = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4);
+
+ if (common->band == NL80211_BAND_2GHZ)
+ desc[4] = cpu_to_le16(RSI_11B_MODE);
+ else
+ desc[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE);
+
+ if (conf_is_ht40(conf)) {
+ desc[4] |= cpu_to_le16(0xB | RSI_11G_MODE);
+ desc[5] = cpu_to_le16(0x6);
+ }
+
+ /* Indicate to firmware to give cfm */
+ if (ieee80211_is_probe_req(wh->frame_control) && (!bss->assoc)) {
+ rsi_dbg(INFO_ZONE, "%s: blocking mgmt queue\n", __func__);
+ desc[1] |= cpu_to_le16(RSI_DESC_REQUIRE_CFM_TO_HOST);
+ xtend_desc->confirm_frame_type = PROBEREQ_CONFIRM;
+ common->mgmt_q_block = true;
+ }
+
+ desc[7] |= cpu_to_le16(vap_id << 8); /* Station ID */
+ desc[4] |= cpu_to_le16(vap_id << 14);
+
+ status = adapter->host_intf_ops->write_pkt(common->priv,
+ (u8 *)desc,
+ skb->len);
+ if (status) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to write the packet\n",
+ __func__);
+ }
+
+err:
+ rsi_indicate_tx_status(common->priv, skb, status);
+ return status;
+}
+
+/**
+ * bl_cmd_timeout() - This function is called when BL command timed out
+ * @priv: Pointer to the hardware structure.
+ *
+ * Return: NONE.
+ */
+static void bl_cmd_timeout(unsigned long priv)
+{
+ struct rsi_hw *adapter = (struct rsi_hw *)priv;
+
+ adapter->blcmd_timer_expired = 1;
+ del_timer(&adapter->bl_cmd_timer);
+}
+
+/**
+ * bl_start_cmd_timer() - This function starts the BL command timer
+ * @adapter: Pointer to the hardware structure.
+ * @timeout: Timeout of the command in milliseconds
+ *
+ * Return: 0 on success.
+ */
+static int bl_start_cmd_timer(struct rsi_hw *adapter, u32 timeout)
+{
+ init_timer(&adapter->bl_cmd_timer);
+ adapter->bl_cmd_timer.data = (unsigned long)adapter;
+ adapter->bl_cmd_timer.function = (void *)&bl_cmd_timeout;
+ adapter->bl_cmd_timer.expires = (msecs_to_jiffies(timeout) + jiffies);
+
+ adapter->blcmd_timer_expired = 0;
+ add_timer(&adapter->bl_cmd_timer);
+
+ return 0;
+}
+
+/**
+ * bl_stop_cmd_timer() - This function stops the BL command timer
+ * @adapter: Pointer to the hardware structure.
+ *
+ * Return: 0 on success.
+ */
+static int bl_stop_cmd_timer(struct rsi_hw *adapter)
+{
+ adapter->blcmd_timer_expired = 0;
+ if (timer_pending(&adapter->bl_cmd_timer))
+ del_timer(&adapter->bl_cmd_timer);
+
+ return 0;
+}
+
+/**
+ * bl_write_cmd() - This function writes the BL command to device
+ * @adapter: Pointer to the hardware structure.
+ * @cmd: Command to write
+ * @exp_resp: Expected Response
+ * @cmd_resp: Received Response
+ *
+ * Return: 0 on success.
+ */
+int bl_write_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, u16 *cmd_resp)
+{
+ struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
+ u32 regin_val = 0, regout_val = 0;
+ u8 output = 0;
+ u32 regin_input = 0;
+
+ regin_input = (REGIN_INPUT | adapter->priv->coex_mode);
+
+ while (!adapter->blcmd_timer_expired) {
+ regin_val = 0;
+ if (hif_ops->master_reg_read(adapter,
+ SWBL_REGIN,
+ ®in_val,
+ 2) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Command %0x REGIN reading failed..\n",
+ __func__, cmd);
+ goto fail;
+ }
+ mdelay(1);
+ if ((regin_val >> 12) != REGIN_VALID)
+ break;
+ }
+ if (adapter->blcmd_timer_expired) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Command %0x REGIN reading timed out..\n",
+ __func__, cmd);
+ goto fail;
+ }
+
+ rsi_dbg(INFO_ZONE,
+ "Issuing write to Regin regin_val:%0x sending cmd:%0x\n",
+ regin_val, (cmd | regin_input << 8));
+ if ((hif_ops->master_reg_write(adapter,
+ SWBL_REGIN,
+ (cmd | regin_input << 8),
+ 2)) < 0) {
+ goto fail;
+ }
+ mdelay(1);
+
+ if (cmd == LOAD_HOSTED_FW || cmd == JUMP_TO_ZERO_PC) {
+ /* JUMP_TO_ZERO_PC doesn't expect
+ * any response. So return from here
+ */
+ return 0;
+ }
+
+ while (!adapter->blcmd_timer_expired) {
+ regout_val = 0;
+ if (hif_ops->master_reg_read(adapter,
+ SWBL_REGOUT,
+ ®out_val,
+ 2) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Command %0x REGOUT reading failed..\n",
+ __func__, cmd);
+ goto fail;
+ }
+ mdelay(1);
+ if ((regout_val >> 8) == REGOUT_VALID)
+ break;
+ }
+ if (adapter->blcmd_timer_expired) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Command %0x REGOUT reading timed out..\n",
+ __func__, cmd);
+ goto fail;
+ }
+
+ *cmd_resp = ((u16 *)®out_val)[0] & 0xffff;
+
+ output = ((u8 *)®out_val)[0] & 0xff;
+
+ rsi_dbg(INFO_ZONE, "Invalidating regout\n");
+ if ((hif_ops->master_reg_write(adapter,
+ SWBL_REGOUT,
+ (cmd | REGOUT_INVALID << 8),
+ 2)) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Command %0x REGOUT writing failed..\n",
+ __func__, cmd);
+ goto fail;
+ }
+ mdelay(1);
+
+ if (output == exp_resp) {
+ rsi_dbg(INFO_ZONE,
+ "%s: Recvd Expected resp %x for cmd %0x\n",
+ __func__, output, cmd);
+ } else {
+ rsi_dbg(ERR_ZONE,
+ "%s: Recvd resp %x for cmd %0x\n",
+ __func__, output, cmd);
+ goto fail;
+ }
+ return 0;
+
+fail:
+ return -1;
+}
+
+/**
+ * bl_cmd() - This function initiates the BL command
+ * @adapter: Pointer to the hardware structure.
+ * @cmd: Command to write
+ * @exp_resp: Expected Response
+ * @str: Command string
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+int bl_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, char *str)
+{
+ u16 regout_val = 0;
+ u32 timeout = 0;
+
+ rsi_dbg(INFO_ZONE, "Issuing cmd: \"%s\"\n", str);
+
+ if ((cmd == EOF_REACHED) || (cmd == PING_VALID) || (cmd == PONG_VALID))
+ timeout = BL_BURN_TIMEOUT;
+ else
+ timeout = BL_CMD_TIMEOUT;
+
+ bl_start_cmd_timer(adapter, timeout);
+ if (bl_write_cmd(adapter, cmd, exp_resp, ®out_val) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Command %s (%0x) writing failed..\n",
+ __func__, str, cmd);
+ goto fail;
+ }
+ bl_stop_cmd_timer(adapter);
+ return 0;
+
+fail:
+ return -1;
+}
+
+/**
+ * bl_write_header() - This function writes the BL header
+ * @adapter: Pointer to the hardware structure.
+ * @flash_content: Flash content
+ * @content_size: Flash content size
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int bl_write_header(struct rsi_hw *adapter,
+ u8 *flash_content, u32 content_size)
+{
+ struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
+ struct bl_header bl_hdr;
+ u32 write_addr, write_len;
+
+#define CHECK_SUM_OFFSET 20
+#define LEN_OFFSET 8
+#define ADDR_OFFSET 16
+
+ bl_hdr.flags = 0;
+ bl_hdr.image_no = cpu_to_le32(adapter->priv->coex_mode);
+ bl_hdr.check_sum = cpu_to_le32(
+ *(u32 *)&flash_content[CHECK_SUM_OFFSET]);
+ bl_hdr.flash_start_address = cpu_to_le32(
+ *(u32 *)&flash_content[ADDR_OFFSET]);
+ bl_hdr.flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]);
+ write_len = sizeof(struct bl_header);
+
+ if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) {
+ write_addr = PING_BUFFER_ADDRESS;
+ if ((hif_ops->write_reg_multiple(adapter,
+ write_addr,
+ (u8 *)&bl_hdr,
+ write_len)) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to load Version/CRC structure\n",
+ __func__);
+ goto fail;
+ }
+ } else {
+ write_addr = PING_BUFFER_ADDRESS >> 16;
+ if ((hif_ops->master_access_msword(adapter, write_addr)) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word to common reg\n",
+ __func__);
+ goto fail;
+ }
+ write_addr = RSI_SD_REQUEST_MASTER |
+ (PING_BUFFER_ADDRESS & 0xFFFF);
+ if ((hif_ops->write_reg_multiple(adapter,
+ write_addr,
+ (u8 *)&bl_hdr,
+ write_len)) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to load Version/CRC structure\n",
+ __func__);
+ goto fail;
+ }
+ }
+ return 0;
+
+fail:
+ return -1;
+}
+
+/**
+ * read_flash_capacity() - This function reads the flash size from device
+ * @adapter: Pointer to the hardware structure.
+ *
+ * Return: flash capacity on success, 0 on failure.
+ */
+static u32 read_flash_capacity(struct rsi_hw *adapter)
+{
+ u32 flash_sz = 0;
+
+ if ((adapter->host_intf_ops->master_reg_read(adapter,
+ FLASH_SIZE_ADDR,
+ &flash_sz, 2)) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Flash size reading failed..\n",
+ __func__);
+ return 0;
+ }
+ rsi_dbg(INIT_ZONE, "Flash capacity: %d KiloBytes\n", flash_sz);
+
+ return (flash_sz * 1024); /* Return size in kbytes */
+}
+
+/**
+ * ping_pong_write() - This function writes the flash contents throgh ping
+ * pong buffers
+ * @adapter: Pointer to the hardware structure.
+ * @cmd: command ping/pong write
+ * @addr: address to write
+ * @size: size
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int ping_pong_write(struct rsi_hw *adapter, u8 cmd, u8 *addr, u32 size)
+{
+ struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
+ u32 block_size = 0;
+ u32 cmd_addr;
+ u16 cmd_resp = 0, cmd_req = 0;
+ u8 *str;
+
+ if (adapter->rsi_host_intf == RSI_HOST_INTF_SDIO)
+ block_size = 256;
+ else
+ block_size = 252;
+
+ if (cmd == PING_WRITE) {
+ cmd_addr = PING_BUFFER_ADDRESS;
+ cmd_resp = PONG_AVAIL;
+ cmd_req = PING_VALID;
+ str = "PING_VALID";
+ } else {
+ cmd_addr = PONG_BUFFER_ADDRESS;
+ cmd_resp = PING_AVAIL;
+ cmd_req = PONG_VALID;
+ str = "PONG_VALID";
+ }
+
+ if (hif_ops->load_data_master_write(adapter,
+ cmd_addr,
+ size,
+ block_size,
+ addr)) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to write blk at addr %0x\n",
+ __func__, *addr);
+ goto fail;
+ }
+ if (bl_cmd(adapter, cmd_req, cmd_resp, str) < 0) {
+ bl_stop_cmd_timer(adapter);
+ goto fail;
+ }
+ return 0;
+
+fail:
+ return -1;
+}
+
+/**
+ * auto_fw_upgrade() - This function loads the firmware to device
+ * @adapter: Pointer to the hardware structure.
+ * @flash_content: Firmware to load
+ * @content_size: Size of the firmware
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int auto_fw_upgrade(struct rsi_hw *adapter,
+ u8 *flash_content,
+ u32 content_size)
+{
+ u8 cmd;
+ u8 *temp_flash_content;
+ u32 temp_content_size;
+ u32 num_flash;
+ u32 index;
+ u32 flash_start_address;
+
+ temp_flash_content = flash_content;
+
+ if (content_size > MAX_FLASH_FILE_SIZE) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Flash Content size is more than 400K %u\n",
+ __func__, MAX_FLASH_FILE_SIZE);
+ goto fail;
+ }
+
+ flash_start_address = cpu_to_le32(
+ *(u32 *)&flash_content[FLASHING_START_ADDRESS]);
+ rsi_dbg(INFO_ZONE, "flash start address: %08x\n", flash_start_address);
+
+ if (flash_start_address < FW_IMAGE_MIN_ADDRESS) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Fw image Flash Start Address is less than 68K\n",
+ __func__);
+ goto fail;
+ }
+
+ if (flash_start_address % FLASH_SECTOR_SIZE) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Flash Start Address is not multiple of 4K\n",
+ __func__);
+ goto fail;
+ }
+
+ if ((flash_start_address + content_size) > adapter->flash_capacity) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Flash Content will cross max flash size\n",
+ __func__);
+ goto fail;
+ }
+
+ temp_content_size = content_size;
+ num_flash = content_size / FLASH_WRITE_CHUNK_SIZE;
+
+ rsi_dbg(INFO_ZONE, "content_size: %d\n", content_size);
+ rsi_dbg(INFO_ZONE, "num_flash: %d\n", num_flash);
+
+ for (index = 0; index <= num_flash; index++) {
+ rsi_dbg(INFO_ZONE, "flash index: %d\n", index);
+ if (index != num_flash) {
+ content_size = FLASH_WRITE_CHUNK_SIZE;
+ rsi_dbg(INFO_ZONE,
+ "QSPI content_size:%d\n",
+ content_size);
+ } else {
+ content_size =
+ temp_content_size % FLASH_WRITE_CHUNK_SIZE;
+ rsi_dbg(INFO_ZONE,
+ "Writing last sector content_size:%d\n",
+ content_size);
+ if (!content_size) {
+ rsi_dbg(INFO_ZONE, "INSTRUCTION SIZE ZERO\n");
+ break;
+ }
+ }
+
+ if (index % 2)
+ cmd = PING_WRITE;
+ else
+ cmd = PONG_WRITE;
+
+ if (ping_pong_write(adapter,
+ cmd,
+ flash_content,
+ content_size)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to load %d block\n",
+ __func__, index);
+ goto fail;
+ }
+
+ rsi_dbg(INFO_ZONE,
+ "%s: Successfully loaded %d instructions\n",
+ __func__, index);
+ flash_content += content_size;
+ }
+
+ if (bl_cmd(adapter, EOF_REACHED, FW_LOADING_SUCCESSFUL,
+ "EOF_REACHED") < 0) {
+ bl_stop_cmd_timer(adapter);
+ goto fail;
+ }
+ rsi_dbg(INFO_ZONE, "FW loading is done and FW is running..\n");
+ return 0;
+
+fail:
+ return -1;
+}
+
+/**
+ * read_flash_content() - This function reads the flash content
+ * from device
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+static int read_flash_content(struct rsi_hw *adapter,
+ u8 *temp_buf,
+ u32 address,
+ u32 len)
+{
+ struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
+
+ if (adapter->rsi_host_intf == RSI_HOST_INTF_SDIO) {
+ if (hif_ops->master_access_msword(adapter,
+ address >> 16) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word to common reg\n",
+ __func__);
+ return -1;
+ }
+ address &= 0xFFFF;
+ return hif_ops->read_reg_multiple(adapter,
+ address | RSI_SD_REQUEST_MASTER,
+ temp_buf, len);
+ } else {
+ return hif_ops->read_reg_multiple(adapter, address,
+ temp_buf, len);
+ }
+
+ return 0;
+}
+
+/**
+ * verify_flash_content() - This function verifies the loaded flash content
+ * from device
+ * @common: Pointer to the driver private structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int verify_flash_content(struct rsi_hw *adapter,
+ u8 *flash_content,
+ u32 instructions_sz,
+ u32 eeprom_offset,
+ u8 read_mode)
+{
+ u32 status = 0;
+ u32 num_loops = 0, idx;
+ u32 chunk_size = 0;
+ u8 *dest_addr = NULL;
+ u32 addr = 0;
+ u32 flash_chunk_size;
+
+ if (adapter->rsi_host_intf == RSI_HOST_INTF_USB)
+ flash_chunk_size = USB_FLASH_READ_CHUNK_SIZE;
+ else
+ flash_chunk_size = SDIO_FLASH_READ_CHUNK_SIZE;
+
+ num_loops = instructions_sz / flash_chunk_size;
+
+ if (instructions_sz % flash_chunk_size)
+ num_loops++;
+
+ if (read_mode == EEPROM_READ_MODE) {
+ dest_addr = adapter->priv->rx_data_pkt;
+ } else {
+ dest_addr = kzalloc(instructions_sz, GFP_KERNEL);
+ if (!dest_addr) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Memory allocation for dest_addr failed\n",
+ __func__);
+ return -1;
+ }
+ }
+
+ rsi_dbg(INFO_ZONE, "Number of loops required: %d\n", num_loops);
+ for (idx = 0; idx < num_loops; idx++) {
+ if (instructions_sz < flash_chunk_size)
+ chunk_size = instructions_sz;
+ else
+ chunk_size = flash_chunk_size;
+ rsi_dbg(INFO_ZONE, "idx is %d and chunk size is %d\n",
+ idx, chunk_size);
+ if (read_mode == EEPROM_READ_MODE) {
+ adapter->eeprom.offset = eeprom_offset;
+ rsi_dbg(INFO_ZONE,
+ "eeprom offset is %x\n", eeprom_offset);
+ adapter->eeprom.length = chunk_size;
+ status = rsi_flash_read(adapter);
+ if (status == 0) {
+ rsi_dbg(INFO_ZONE,
+ "%s: BLOCK/SECTOR READING SUCCESSFUL\n",
+ __func__);
+ } else {
+ rsi_dbg(ERR_ZONE,
+ "%s: READING FROM FLASH FAILED\n",
+ __func__);
+ return -1;
+ }
+ } else {
+ memset(dest_addr, 0, chunk_size);
+ addr = SOC_FLASH_ADDR + eeprom_offset;
+ rsi_dbg(INFO_ZONE,
+ "Reading flash addr 0x%0x\n", addr);
+ if (read_flash_content(adapter, dest_addr, addr,
+ flash_chunk_size) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s:Failed to read calib data\n",
+ __func__);
+ kfree(dest_addr);
+ return -1;
+ }
+ }
+ if (memcmp(&flash_content[idx * flash_chunk_size],
+ dest_addr,
+ chunk_size)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: VERIFICATION OF FLASH CHUNK FAILED\n",
+ __func__);
+ return -1;
+ }
+ eeprom_offset += chunk_size;
+ instructions_sz -= chunk_size;
+ }
+ return 0;
+}
+
+/**
+ * rsi_load_9113_firmware () - This function loads the TA firmware for 9113
+ * device.
+ * @adapter: Pointer to the rsi hw.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int rsi_load_9113_firmware(struct rsi_hw *adapter)
+{
+ struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
+ const struct firmware *fw_entry = NULL;
+ u32 regout_val = 0;
+ u16 tmp_regout_val = 0;
+ u8 *flash_content = NULL;
+ u32 content_size = 0;
+ struct ta_metadata *metadata_p;
+
+ bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT);
+ while (!adapter->blcmd_timer_expired) {
+ if ((hif_ops->master_reg_read(adapter,
+ SWBL_REGOUT,
+ ®out_val,
+ 2)) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: REGOUT read failed\n", __func__);
+ goto fail;
+ }
+ mdelay(1);
+ if ((regout_val >> 8) == REGOUT_VALID)
+ break;
+ }
+ if (adapter->blcmd_timer_expired) {
+ rsi_dbg(ERR_ZONE, "%s: REGOUT read timedout\n", __func__);
+ rsi_dbg(ERR_ZONE,
+ "%s: Soft boot loader not present\n", __func__);
+ goto fail;
+ }
+ bl_stop_cmd_timer(adapter);
+
+ rsi_dbg(INFO_ZONE, "Received Board Version Number: %x\n",
+ (regout_val & 0xff));
+
+ if ((hif_ops->master_reg_write(adapter,
+ SWBL_REGOUT,
+ (REGOUT_INVALID | REGOUT_INVALID << 8),
+ 2)) < 0) {
+ rsi_dbg(ERR_ZONE, "%s: REGOUT writing failed..\n", __func__);
+ goto fail;
+ }
+ mdelay(1);
+
+ if ((bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS,
+ "AUTO_READ_CMD")) < 0)
+ goto fail;
+
+ adapter->flash_capacity = read_flash_capacity(adapter);
+ if (adapter->flash_capacity <= 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to read flash size from EEPROM\n",
+ __func__);
+ goto fail;
+ }
+
+ metadata_p = &metadata_flash_content[adapter->priv->coex_mode];
+
+ rsi_dbg(INIT_ZONE, "%s: loading file %s\n", __func__, metadata_p->name);
+
+ if ((request_firmware(&fw_entry, metadata_p->name,
+ adapter->device)) < 0) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n",
+ __func__, metadata_p->name);
+ goto fail;
+ }
+ flash_content = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+ if (!flash_content) {
+ rsi_dbg(ERR_ZONE, "%s: Failed to copy firmware\n", __func__);
+ goto fail;
+ }
+ content_size = fw_entry->size;
+
+ if (bl_write_header(adapter, flash_content, content_size)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: RPS Image header loading failed\n",
+ __func__);
+ goto fail;
+ }
+
+ bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT);
+ if (bl_write_cmd(adapter, CHECK_CRC, CMD_PASS, &tmp_regout_val) < 0) {
+ bl_stop_cmd_timer(adapter);
+ rsi_dbg(ERR_ZONE,
+ "%s: CHECK_CRC Command writing failed..\n",
+ __func__);
+ if ((tmp_regout_val & 0xff) == CMD_FAIL) {
+ rsi_dbg(ERR_ZONE,
+ "CRC Fail.. Proceeding to Upgrade mode\n");
+ goto fw_upgrade;
+ }
+ }
+ bl_stop_cmd_timer(adapter);
+
+ if (bl_cmd(adapter, POLLING_MODE, CMD_PASS, "POLLING_MODE") < 0)
+ goto fail;
+
+load_image_cmd:
+ if ((bl_cmd(adapter,
+ LOAD_HOSTED_FW,
+ LOADING_INITIATED,
+ "LOAD_HOSTED_FW")) < 0)
+ goto fail;
+ rsi_dbg(INFO_ZONE, "Load Image command passed..\n");
+ goto success;
+
+fw_upgrade:
+ /* After burning the RPS header, firmware has to be
+ * burned using the below steps
+ */
+ if (bl_cmd(adapter, BURN_HOSTED_FW, SEND_RPS_FILE, "FW_UPGRADE") < 0)
+ goto fail;
+
+ rsi_dbg(INFO_ZONE, "Burn Command Pass.. Upgrading the firmware\n");
+
+ if (auto_fw_upgrade(adapter, flash_content, content_size) == 0) {
+ rsi_dbg(ERR_ZONE, "Auto firmware successful\n");
+ goto load_image_cmd;
+ }
+
+ if (bl_cmd(adapter, CONFIG_AUTO_READ_MODE,
+ CMD_PASS, "AUTO_READ_MODE") < 0)
+ goto fail;
+
+ rsi_dbg(INFO_ZONE, "Starting Flash Verification Process\n");
+
+ if ((verify_flash_content(adapter,
+ adapter->calib_data,
+ EEPROM_DATA_SIZE,
+ 0,
+ MASTER_READ_MODE)) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s: FLASHING SBL failed in Calib VERIFICATION phase\n",
+ __func__);
+ goto fail;
+ }
+ if ((verify_flash_content(adapter,
+ flash_content + BL_HEADER,
+ (content_size - BL_HEADER),
+ EEPROM_DATA_SIZE,
+ MASTER_READ_MODE)) < 0) {
+ rsi_dbg(ERR_ZONE,
+ "%s:FLASHING SBL failed in SBL VERIFICATION phase\n",
+ __func__);
+ goto fail;
+ }
+ rsi_dbg(INFO_ZONE,
+ "Flash Verification Process Completed Successfully\n");
+ rsi_dbg(INFO_ZONE, "SWBL FLASHING THROUGH SWBL PASSED...\n");
+
+success:
+ kfree(flash_content);
+ release_firmware(fw_entry);
+ return 0;
+
+fail:
+ kfree(flash_content);
+ release_firmware(fw_entry);
+ return -1;
+}
+
+/**
+ * rsi_hal_device_init() - This function initializes the Device
+ * @adapter: Pointer to the hardware structure
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int rsi_hal_device_init(struct rsi_hw *adapter)
+{
+ struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
+
+#ifdef CONFIG_RSI_COEX
+ adapter->priv->coex_mode = 4;
+#else
+ adapter->priv->coex_mode = 1;
+#endif
+ adapter->device_model = RSI_DEV_9113; /* TODO: Get from module param */
+ switch (adapter->device_model) {
+ case RSI_DEV_9110:
+ /* TODO: Add code for 9110 */
+ break;
+ case RSI_DEV_9113:
+ if (rsi_load_9113_firmware(adapter)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Failed to load TA instructions\n",
+ __func__);
+ return -1;
+ }
+ break;
+ case RSI_DEV_9116:
+ /* TODO: Add code for 9116 */
+ break;
+ default:
+ return -1;
+ }
+ if (adapter->rsi_host_intf == RSI_HOST_INTF_SDIO) {
+ if (hif_ops->master_access_msword(adapter,
+ MISC_CFG_BASE_ADDR)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word reg\n",
+ __func__);
+ return -1;
+ }
+ rsi_dbg(INIT_ZONE,
+ "%s: Setting ms word to 0x41050000\n",
+ __func__);
+ }
+ adapter->common_hal_fsm = COMMAN_HAL_WAIT_FOR_CARD_READY;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rsi_hal_device_init);
+
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 35c14cc..7aec45a 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1240,6 +1240,55 @@ int rsi_send_block_unblock_frame(struct rsi_common *common, bool block_event)
}
+/**
+ * rsi_flash_read() - This function sends the frash read frame to device
+ * @adapter: Pointer to the hardware structure.
+ *
+ * Return: status: 0 on success, -1 on failure.
+ */
+int rsi_flash_read(struct rsi_hw *adapter)
+{
+ struct rsi_common *common = adapter->priv;
+ struct rsi_mac_frame *cmd_frame = NULL;
+ struct sk_buff *skb;
+
+ rsi_dbg(MGMT_TX_ZONE, "%s: Sending flash read frame\n", __func__);
+
+ skb = dev_alloc_skb(FRAME_DESC_SZ);
+ if (!skb)
+ return -ENOMEM;
+
+ memset(skb->data, 0, FRAME_DESC_SZ);
+ cmd_frame = (struct rsi_mac_frame *)skb->data;
+
+ /* FrameType */
+ cmd_frame->desc_word[1] = cpu_to_le16(EEPROM_READ_TYPE);
+
+ /* Format of length and offset differs for
+ * autoflashing and swbl flashing
+ */
+ cmd_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+
+ /* Number of bytes to read */
+ rsi_dbg(INFO_ZONE, " eeprom length 0x%x, %d\n",
+ adapter->eeprom.length, adapter->eeprom.length);
+ cmd_frame->desc_word[3] = cpu_to_le16(adapter->eeprom.length << 4);
+
+ cmd_frame->desc_word[2] |= cpu_to_le16(3 << 8);
+ if (adapter->eeprom_init) {
+ rsi_dbg(INFO_ZONE, "spi init sent");
+ cmd_frame->desc_word[2] |= cpu_to_le16(BIT(13));
+ }
+
+ /* Address to read */
+ cmd_frame->desc_word[4] = cpu_to_le16(adapter->eeprom.offset);
+ cmd_frame->desc_word[5] = cpu_to_le16(adapter->eeprom.offset >> 16);
+ cmd_frame->desc_word[6] = cpu_to_le16(0); //delay = 0
+
+ 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_91x_pkt.c b/drivers/net/wireless/rsi/rsi_91x_pkt.c
deleted file mode 100644
index 02920c9..0000000
--- a/drivers/net/wireless/rsi/rsi_91x_pkt.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * Copyright (c) 2014 Redpine Signals Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "rsi_mgmt.h"
-
-/**
- * rsi_send_data_pkt() - This function sends the recieved data packet from
- * driver to device.
- * @common: Pointer to the driver private structure.
- * @skb: Pointer to the socket buffer structure.
- *
- * Return: status: 0 on success, -1 on failure.
- */
-int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
-{
- struct rsi_hw *adapter = common->priv;
- struct ieee80211_hdr *tmp_hdr;
- struct ieee80211_tx_info *info;
- struct skb_info *tx_params;
- struct ieee80211_bss_conf *bss;
- int status;
- u8 ieee80211_size = MIN_802_11_HDR_LEN;
- u8 extnd_size;
- __le16 *frame_desc;
- u16 seq_num;
-
- info = IEEE80211_SKB_CB(skb);
- bss = &info->control.vif->bss_conf;
- tx_params = (struct skb_info *)info->driver_data;
-
- if (!bss->assoc) {
- status = -EINVAL;
- goto err;
- }
-
- tmp_hdr = (struct ieee80211_hdr *)&skb->data[0];
- seq_num = (le16_to_cpu(tmp_hdr->seq_ctrl) >> 4);
-
- extnd_size = ((uintptr_t)skb->data & 0x3);
-
- if ((FRAME_DESC_SZ + extnd_size) > skb_headroom(skb)) {
- rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__);
- status = -ENOSPC;
- goto err;
- }
-
- skb_push(skb, (FRAME_DESC_SZ + extnd_size));
- frame_desc = (__le16 *)&skb->data[0];
- memset((u8 *)frame_desc, 0, FRAME_DESC_SZ);
-
- if (ieee80211_is_data_qos(tmp_hdr->frame_control)) {
- ieee80211_size += 2;
- frame_desc[6] |= cpu_to_le16(BIT(12));
- }
-
- if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) &&
- (common->secinfo.security_enable)) {
- if (rsi_is_cipher_wep(common))
- ieee80211_size += 4;
- else
- ieee80211_size += 8;
- frame_desc[6] |= cpu_to_le16(BIT(15));
- }
-
- frame_desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) |
- (RSI_WIFI_DATA_Q << 12));
- frame_desc[2] = cpu_to_le16((extnd_size) | (ieee80211_size) << 8);
-
- if (common->min_rate != 0xffff) {
- /* Send fixed rate */
- frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE);
- frame_desc[4] = cpu_to_le16(common->min_rate);
-
- if (conf_is_ht40(&common->priv->hw->conf))
- frame_desc[5] = cpu_to_le16(FULL40M_ENABLE);
-
- if (common->vif_info[0].sgi) {
- if (common->min_rate & 0x100) /* Only MCS rates */
- frame_desc[4] |=
- cpu_to_le16(ENABLE_SHORTGI_RATE);
- }
-
- }
-
- frame_desc[6] |= cpu_to_le16(seq_num & 0xfff);
- frame_desc[7] = cpu_to_le16(((tx_params->tid & 0xf) << 4) |
- (skb->priority & 0xf) |
- (tx_params->sta_id << 8));
-
- status = adapter->host_intf_write_pkt(common->priv,
- skb->data,
- skb->len);
- if (status)
- rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n",
- __func__);
-
-err:
- ++common->tx_stats.total_tx_pkt_freed[skb->priority];
- rsi_indicate_tx_status(common->priv, skb, status);
- return status;
-}
-
-/**
- * rsi_send_mgmt_pkt() - This functions sends the received management packet
- * from driver to device.
- * @common: Pointer to the driver private structure.
- * @skb: Pointer to the socket buffer structure.
- *
- * Return: status: 0 on success, -1 on failure.
- */
-int rsi_send_mgmt_pkt(struct rsi_common *common,
- struct sk_buff *skb)
-{
- struct rsi_hw *adapter = common->priv;
- struct ieee80211_hdr *wh;
- struct ieee80211_tx_info *info;
- struct ieee80211_bss_conf *bss;
- struct ieee80211_hw *hw = adapter->hw;
- struct ieee80211_conf *conf = &hw->conf;
- struct skb_info *tx_params;
- int status = -E2BIG;
- __le16 *msg;
- u8 extnd_size;
- u8 vap_id = 0;
-
- info = IEEE80211_SKB_CB(skb);
- tx_params = (struct skb_info *)info->driver_data;
- extnd_size = ((uintptr_t)skb->data & 0x3);
-
- if (tx_params->flags & INTERNAL_MGMT_PKT) {
- if ((extnd_size) > skb_headroom(skb)) {
- rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__);
- dev_kfree_skb(skb);
- return -ENOSPC;
- }
- skb_push(skb, extnd_size);
- skb->data[extnd_size + 4] = extnd_size;
- status = adapter->host_intf_write_pkt(common->priv,
- (u8 *)skb->data,
- skb->len);
- if (status) {
- rsi_dbg(ERR_ZONE,
- "%s: Failed to write the packet\n", __func__);
- }
- dev_kfree_skb(skb);
- return status;
- }
-
- bss = &info->control.vif->bss_conf;
- wh = (struct ieee80211_hdr *)&skb->data[0];
-
- if (FRAME_DESC_SZ > skb_headroom(skb))
- goto err;
-
- skb_push(skb, FRAME_DESC_SZ);
- memset(skb->data, 0, FRAME_DESC_SZ);
- msg = (__le16 *)skb->data;
-
- if (skb->len > MAX_MGMT_PKT_SIZE) {
- rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__);
- goto err;
- }
-
- msg[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) |
- (RSI_WIFI_MGMT_Q << 12));
- msg[1] = cpu_to_le16(TX_DOT11_MGMT);
- msg[2] = cpu_to_le16(MIN_802_11_HDR_LEN << 8);
- msg[3] = cpu_to_le16(RATE_INFO_ENABLE);
- msg[6] = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4);
-
- if (wh->addr1[0] & BIT(0))
- msg[3] |= cpu_to_le16(RSI_BROADCAST_PKT);
-
- if (common->band == NL80211_BAND_2GHZ)
- msg[4] = cpu_to_le16(RSI_11B_MODE);
- else
- msg[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE);
-
- if (conf_is_ht40(conf)) {
- msg[4] = cpu_to_le16(0xB | RSI_11G_MODE);
- msg[5] = cpu_to_le16(0x6);
- }
-
- /* Indicate to firmware to give cfm */
- if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) {
- msg[1] |= cpu_to_le16(BIT(10));
- msg[7] = cpu_to_le16(PROBEREQ_CONFIRM);
- common->mgmt_q_block = true;
- }
-
- msg[7] |= cpu_to_le16(vap_id << 8);
-
- status = adapter->host_intf_write_pkt(common->priv,
- (u8 *)msg,
- skb->len);
- if (status)
- rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__);
-
-err:
- rsi_indicate_tx_status(common->priv, skb, status);
- return status;
-}
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 8428858..6f02600 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -1,6 +1,8 @@
/**
* Copyright (c) 2014 Redpine Signals Inc.
*
+ * Developers:
+ * Fariya Fathima 2014 <fariya.f@redpinesignals.com>
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
@@ -18,6 +20,7 @@
#include <linux/module.h>
#include "rsi_sdio.h"
#include "rsi_common.h"
+#include "rsi_hal.h"
/**
* rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg.
@@ -386,6 +389,7 @@ static int rsi_setupcard(struct rsi_hw *adapter)
rsi_setclock(adapter, 50000);
dev->tx_blk_size = 256;
+ adapter->tx_blk_size = dev->tx_blk_size;
status = rsi_setblocklength(adapter, dev->tx_blk_size);
if (status)
rsi_dbg(ERR_ZONE,
@@ -473,8 +477,6 @@ void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit)
rsi_dbg(ERR_ZONE, "%s: unable to send ack\n", __func__);
}
-
-
/**
* rsi_sdio_read_register_multiple() - This function read multiple bytes of
* information from the SD card.
@@ -485,10 +487,10 @@ void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit)
*
* Return: 0 on success, -1 on failure.
*/
-static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter,
- u32 addr,
- u32 count,
- u8 *data)
+int rsi_sdio_read_register_multiple(struct rsi_hw *adapter,
+ u32 addr,
+ u8 *data,
+ u16 count)
{
struct rsi_91x_sdiodev *dev =
(struct rsi_91x_sdiodev *)adapter->rsi_dev;
@@ -518,7 +520,7 @@ static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter,
int rsi_sdio_write_register_multiple(struct rsi_hw *adapter,
u32 addr,
u8 *data,
- u32 count)
+ u16 count)
{
struct rsi_91x_sdiodev *dev =
(struct rsi_91x_sdiodev *)adapter->rsi_dev;
@@ -552,6 +554,178 @@ int rsi_sdio_write_register_multiple(struct rsi_hw *adapter,
return status;
}
+int rsi_sdio_load_data_master_write(struct rsi_hw *adapter,
+ u32 base_address,
+ u32 instructions_sz,
+ u16 block_size,
+ u8 *ta_firmware)
+{
+ u32 num_blocks;
+ u16 msb_address;
+ u32 offset, ii;
+ u8 temp_buf[256];
+ u16 lsb_address;
+
+ num_blocks = instructions_sz / block_size;
+ msb_address = base_address >> 16;
+
+ rsi_dbg(INFO_ZONE, "num_blocks: %d\n", num_blocks);
+
+ /* Loading DM ms word in the sdio slave */
+ if (rsi_sdio_master_access_msword(adapter, msb_address)) {
+ rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__);
+ return -1;
+ }
+
+ for (offset = 0, ii = 0; ii < num_blocks; ii++, offset += block_size) {
+ memset(temp_buf, 0, block_size);
+ memcpy(temp_buf, ta_firmware + offset, block_size);
+ lsb_address = (u16)base_address;
+ if (rsi_sdio_write_register_multiple(adapter,
+ lsb_address | RSI_SD_REQUEST_MASTER,
+ (u8 *)temp_buf, block_size)) {
+ rsi_dbg(ERR_ZONE, "%s: failed to write\n", __func__);
+ return -1;
+ }
+ rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, ii);
+ base_address += block_size;
+ base_address += block_size;
+
+ if ((base_address >> 16) != msb_address) {
+ msb_address += 1;
+
+ /* Loading DM ms word in the sdio slave */
+ if (rsi_sdio_master_access_msword(adapter,
+ msb_address)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word reg\n",
+ __func__);
+ return -1;
+ }
+ }
+ }
+
+ if (instructions_sz % block_size) {
+ memset(temp_buf, 0, block_size);
+ memcpy(temp_buf,
+ ta_firmware + offset,
+ instructions_sz % block_size);
+ lsb_address = (u16)base_address;
+ if (rsi_sdio_write_register_multiple(adapter,
+ lsb_address | RSI_SD_REQUEST_MASTER,
+ (u8 *)(temp_buf),
+ instructions_sz % block_size)) {
+ return -1;
+ }
+ rsi_dbg(INFO_ZONE,
+ "Written Last Block in Address 0x%x Successfully\n",
+ offset | RSI_SD_REQUEST_MASTER);
+ }
+ return 0;
+}
+
+#define align_address(a) ((unsigned long)(a) & ~0x7)
+
+int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
+ u32 *read_buf, u16 size)
+{
+ u32 *data = NULL;
+ u16 ms_addr = 0;
+ u32 align[2] = {};
+ u32 addr_on_bus;
+
+ data = (u32 *)align_address(&align[1]);
+
+ ms_addr = (addr >> 16);
+ if (rsi_sdio_master_access_msword(adapter, ms_addr)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word to common reg\n",
+ __func__);
+ return -1;
+ }
+ addr = addr & 0xFFFF;
+
+ addr_on_bus = (addr & 0xFF000000);
+ if ((addr_on_bus == (FLASH_SIZE_ADDR & 0xFF000000)) ||
+ (addr_on_bus == 0x0)) {
+ addr_on_bus = (addr & ~(0x3));
+ } else
+ addr_on_bus = addr;
+
+ /* Bringing TA out of reset */
+ if (rsi_sdio_read_register_multiple(adapter,
+ (addr_on_bus | RSI_SD_REQUEST_MASTER),
+ (u8 *)data, 4)) {
+ rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__);
+ return -1;
+ }
+ if (size == 2) {
+ if ((addr & 0x3) == 0)
+ *read_buf = *data;
+ else
+ *read_buf = ((*data >> 16));
+ *read_buf = (*read_buf & 0xFFFF);
+ } else if (size == 1) {
+ if ((addr & 0x3) == 0)
+ *read_buf = *data;
+ else if ((addr & 0x3) == 1)
+ *read_buf = (*data >> 8);
+ else if ((addr & 0x3) == 2)
+ *read_buf = (*data >> 16);
+ else
+ *read_buf = (*data >> 24);
+ *read_buf = (*read_buf & 0xFF);
+ } else { /*size is 4 */
+ *read_buf = *data;
+ }
+
+ return 0;
+}
+
+int rsi_sdio_master_reg_write(struct rsi_hw *adapter,
+ unsigned long addr,
+ unsigned long data,
+ u16 size)
+{
+ unsigned long data1[2];
+ unsigned long *data_alligned;
+
+ data_alligned = (unsigned long *)align_address(&data1[1]);
+
+ if (size == 2) {
+ *data_alligned = ((data << 16) | (data & 0xFFFF));
+ } else if (size == 1) {
+ u32 temp_data;
+
+ temp_data = (data & 0xFF);
+ *data_alligned = ((temp_data << 24) |
+ (temp_data << 16) |
+ (temp_data << 8) |
+ (temp_data));
+ } else {
+ *data_alligned = data;
+ }
+ size = 4;
+
+ if (rsi_sdio_master_access_msword(adapter, (addr >> 16))) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to set ms word to common reg\n",
+ __func__);
+ return -1;
+ }
+ addr = addr & 0xFFFF;
+
+ /* Bringing TA out of reset */
+ if (rsi_sdio_write_register_multiple(adapter,
+ (addr | RSI_SD_REQUEST_MASTER),
+ (u8 *)data_alligned, size)) {
+ rsi_dbg(ERR_ZONE,
+ "%s: Unable to do AHB reg write\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
/**
* rsi_sdio_host_intf_write_pkt() - This function writes the packet to device.
* @adapter: Pointer to the adapter structure.
@@ -560,9 +734,9 @@ int rsi_sdio_write_register_multiple(struct rsi_hw *adapter,
*
* Return: 0 on success, -1 on failure.
*/
-static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter,
- u8 *pkt,
- u32 len)
+int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter,
+ u8 *pkt,
+ u32 len)
{
struct rsi_91x_sdiodev *dev =
(struct rsi_91x_sdiodev *)adapter->rsi_dev;
@@ -585,7 +759,7 @@ static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter,
address,
(u8 *)pkt,
length);
- if (status)
+ if (status < 0)
rsi_dbg(ERR_ZONE, "%s: Unable to write onto the card: %d\n",
__func__, status);
rsi_dbg(DATA_TX_ZONE, "%s: Successfully written onto card\n", __func__);
@@ -614,8 +788,8 @@ int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter,
status = rsi_sdio_read_register_multiple(adapter,
length,
- length, /*num of bytes*/
- (u8 *)pkt);
+ (u8 *)pkt,
+ length);
if (status)
rsi_dbg(ERR_ZONE, "%s: Failed to read frame: %d\n", __func__,
@@ -676,8 +850,6 @@ static int rsi_init_sdio_interface(struct rsi_hw *adapter,
}
sdio_release_host(pfunction);
- adapter->host_intf_write_pkt = rsi_sdio_host_intf_write_pkt;
- adapter->host_intf_read_pkt = rsi_sdio_host_intf_read_pkt;
adapter->determine_event_timeout = rsi_sdio_determine_event_timeout;
adapter->check_hw_queue_status = rsi_sdio_read_buffer_status_register;
@@ -691,6 +863,17 @@ static int rsi_init_sdio_interface(struct rsi_hw *adapter,
return status;
}
+static struct rsi_host_intf_ops sdio_host_intf_ops = {
+ .write_pkt = rsi_sdio_host_intf_write_pkt,
+ .read_pkt = rsi_sdio_host_intf_read_pkt,
+ .master_access_msword = rsi_sdio_master_access_msword,
+ .master_reg_read = rsi_sdio_master_reg_read,
+ .master_reg_write = rsi_sdio_master_reg_write,
+ .read_reg_multiple = rsi_sdio_read_register_multiple,
+ .write_reg_multiple = rsi_sdio_write_register_multiple,
+ .load_data_master_write = rsi_sdio_load_data_master_write,
+};
+
/**
* rsi_probe() - This function is called by kernel when the driver provided
* Vendor and device IDs are matched. All the initialization
@@ -713,6 +896,8 @@ static int rsi_probe(struct sdio_func *pfunction,
__func__);
return 1;
}
+ adapter->rsi_host_intf = RSI_HOST_INTF_SDIO;
+ adapter->host_intf_ops = &sdio_host_intf_ops;
if (rsi_init_sdio_interface(adapter, pfunction)) {
rsi_dbg(ERR_ZONE, "%s: Failed to init sdio interface\n",
@@ -720,14 +905,6 @@ static int rsi_probe(struct sdio_func *pfunction,
goto fail;
}
- if (rsi_sdio_device_init(adapter->priv)) {
- rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__);
- sdio_claim_host(pfunction);
- sdio_disable_func(pfunction);
- sdio_release_host(pfunction);
- goto fail;
- }
-
sdio_claim_host(pfunction);
if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) {
rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__);
@@ -738,6 +915,14 @@ static int rsi_probe(struct sdio_func *pfunction,
sdio_release_host(pfunction);
rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__);
+ if (rsi_hal_device_init(adapter)) {
+ rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__);
+ sdio_claim_host(pfunction);
+ sdio_disable_func(pfunction);
+ sdio_release_host(pfunction);
+ goto fail;
+ }
+
return 0;
fail:
rsi_91x_deinit(adapter);
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 40d7231..c54a534 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -18,6 +18,7 @@
#include <linux/firmware.h>
#include "rsi_sdio.h"
#include "rsi_common.h"
+#include "rsi_hal.h"
/**
* rsi_sdio_master_access_msword() - This function sets the AHB master access
@@ -27,8 +28,8 @@
*
* Return: status: 0 on success, -1 on failure.
*/
-static int rsi_sdio_master_access_msword(struct rsi_hw *adapter,
- u16 ms_word)
+int rsi_sdio_master_access_msword(struct rsi_hw *adapter,
+ u16 ms_word)
{
u8 byte;
u8 function = 0;
@@ -61,171 +62,6 @@ static int rsi_sdio_master_access_msword(struct rsi_hw *adapter,
}
/**
- * rsi_copy_to_card() - This function includes the actual funtionality of
- * copying the TA firmware to the card.Basically this
- * function includes opening the TA file,reading the
- * TA file and writing their values in blocks of data.
- * @common: Pointer to the driver private structure.
- * @fw: Pointer to the firmware value to be written.
- * @len: length of firmware file.
- * @num_blocks: Number of blocks to be written to the card.
- *
- * Return: 0 on success and -1 on failure.
- */
-static int rsi_copy_to_card(struct rsi_common *common,
- const u8 *fw,
- u32 len,
- u32 num_blocks)
-{
- struct rsi_hw *adapter = common->priv;
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
- u32 indx, ii;
- u32 block_size = dev->tx_blk_size;
- u32 lsb_address;
- __le32 data[] = { TA_HOLD_THREAD_VALUE, TA_SOFT_RST_CLR,
- TA_PC_ZERO, TA_RELEASE_THREAD_VALUE };
- u32 address[] = { TA_HOLD_THREAD_REG, TA_SOFT_RESET_REG,
- TA_TH0_PC_REG, TA_RELEASE_THREAD_REG };
- u32 base_address;
- u16 msb_address;
-
- base_address = TA_LOAD_ADDRESS;
- msb_address = base_address >> 16;
-
- for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) {
- lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER);
- if (rsi_sdio_write_register_multiple(adapter,
- lsb_address,
- (u8 *)(fw + indx),
- block_size)) {
- rsi_dbg(ERR_ZONE,
- "%s: Unable to load %s blk\n", __func__,
- FIRMWARE_RSI9113);
- return -1;
- }
- rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii);
- base_address += block_size;
- if ((base_address >> 16) != msb_address) {
- msb_address += 1;
- if (rsi_sdio_master_access_msword(adapter,
- msb_address)) {
- rsi_dbg(ERR_ZONE,
- "%s: Unable to set ms word reg\n",
- __func__);
- return -1;
- }
- }
- }
-
- if (len % block_size) {
- lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER);
- if (rsi_sdio_write_register_multiple(adapter,
- lsb_address,
- (u8 *)(fw + indx),
- len % block_size)) {
- rsi_dbg(ERR_ZONE,
- "%s: Unable to load f/w\n", __func__);
- return -1;
- }
- }
- rsi_dbg(INIT_ZONE,
- "%s: Succesfully loaded TA instructions\n", __func__);
-
- if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) {
- rsi_dbg(ERR_ZONE,
- "%s: Unable to set ms word to common reg\n",
- __func__);
- return -1;
- }
-
- for (ii = 0; ii < ARRAY_SIZE(data); ii++) {
- /* Bringing TA out of reset */
- if (rsi_sdio_write_register_multiple(adapter,
- (address[ii] |
- RSI_SD_REQUEST_MASTER),
- (u8 *)&data[ii],
- 4)) {
- rsi_dbg(ERR_ZONE,
- "%s: Unable to hold TA threads\n", __func__);
- return -1;
- }
- }
-
- rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__);
- return 0;
-}
-
-/**
- * rsi_load_ta_instructions() - This function includes the actual funtionality
- * of loading the TA firmware.This function also
- * includes opening the TA file,reading the TA
- * file and writing their value in blocks of data.
- * @common: Pointer to the driver private structure.
- *
- * Return: status: 0 on success, -1 on failure.
- */
-static int rsi_load_ta_instructions(struct rsi_common *common)
-{
- struct rsi_hw *adapter = common->priv;
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
- u32 len;
- u32 num_blocks;
- const u8 *fw;
- const struct firmware *fw_entry = NULL;
- u32 block_size = dev->tx_blk_size;
- int status = 0;
- u32 base_address;
- u16 msb_address;
-
- if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) {
- rsi_dbg(ERR_ZONE,
- "%s: Unable to set ms word to common reg\n",
- __func__);
- return -1;
- }
- base_address = TA_LOAD_ADDRESS;
- msb_address = (base_address >> 16);
-
- if (rsi_sdio_master_access_msword(adapter, msb_address)) {
- rsi_dbg(ERR_ZONE,
- "%s: Unable to set ms word reg\n", __func__);
- return -1;
- }
-
- status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device);
- if (status < 0) {
- rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n",
- __func__, FIRMWARE_RSI9113);
- return status;
- }
-
- /* Copy firmware into DMA-accessible memory */
- fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
- if (!fw) {
- status = -ENOMEM;
- goto out;
- }
- len = fw_entry->size;
-
- if (len % 4)
- len += (4 - (len % 4));
-
- num_blocks = (len / block_size);
-
- rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);
- rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
-
- status = rsi_copy_to_card(common, fw, len, num_blocks);
- kfree(fw);
-
-out:
- release_firmware(fw_entry);
- return status;
-}
-
-/**
* rsi_process_pkt() - This Function reads rx_blocks register and figures out
* the size of the rx pkt.
* @common: Pointer to the driver private structure.
@@ -472,28 +308,6 @@ void rsi_interrupt_handler(struct rsi_hw *adapter)
}
/**
- * rsi_device_init() - This Function Initializes The HAL.
- * @common: Pointer to the driver private structure.
- *
- * Return: 0 on success, -1 on failure.
- */
-int rsi_sdio_device_init(struct rsi_common *common)
-{
- if (rsi_load_ta_instructions(common))
- return -1;
-
- if (rsi_sdio_master_access_msword(common->priv, MISC_CFG_BASE_ADDR)) {
- rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n",
- __func__);
- return -1;
- }
- rsi_dbg(INIT_ZONE,
- "%s: Setting ms word to 0x41050000\n", __func__);
-
- return 0;
-}
-
-/**
* rsi_sdio_read_buffer_status_register() - This function is used to the read
* buffer status register and set
* relevant fields in
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index ef5d394..84ca609 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -1,6 +1,9 @@
/**
* Copyright (c) 2014 Redpine Signals Inc.
*
+ * Developers:
+ * Prameela Rani Garnepudi 2016 <prameela.garnepudi@redpinesignals.com>
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
@@ -17,6 +20,16 @@
#include <linux/module.h>
#include "rsi_usb.h"
+#include "rsi_hal.h"
+
+static struct rsi_host_intf_ops usb_host_intf_ops = {
+ .write_pkt = rsi_usb_host_intf_write_pkt,
+ .master_reg_read = rsi_usb_master_reg_read,
+ .master_reg_write = rsi_usb_master_reg_write,
+ .read_reg_multiple = rsi_usb_read_register_multiple,
+ .write_reg_multiple = rsi_usb_write_register_multiple,
+ .load_data_master_write = rsi_usb_load_data_master_write,
+};
/**
* rsi_usb_card_write() - This function writes to the USB Card.
@@ -141,6 +154,9 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface,
return 0;
}
+#define RSI_USB_REQ_OUT (USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE)
+#define RSI_USB_REQ_IN (USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE)
+
/* rsi_usb_reg_read() - This function reads data from given register address.
* @usbdev: Pointer to the usb_device structure.
* @reg: Address of the register to be read.
@@ -151,7 +167,7 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface,
*/
static int rsi_usb_reg_read(struct usb_device *usbdev,
u32 reg,
- u16 *value,
+ u32 *value,
u16 len)
{
u8 *buf;
@@ -161,10 +177,11 @@ static int rsi_usb_reg_read(struct usb_device *usbdev,
if (!buf)
return status;
+ len = 2;
status = usb_control_msg(usbdev,
usb_rcvctrlpipe(usbdev, 0),
USB_VENDOR_REGISTER_READ,
- USB_TYPE_VENDOR,
+ RSI_USB_REQ_IN,
((reg & 0xffff0000) >> 16), (reg & 0xffff),
(void *)buf,
len,
@@ -193,7 +210,7 @@ static int rsi_usb_reg_read(struct usb_device *usbdev,
*/
static int rsi_usb_reg_write(struct usb_device *usbdev,
u32 reg,
- u16 value,
+ u32 value,
u16 len)
{
u8 *usb_reg_buf;
@@ -211,7 +228,7 @@ static int rsi_usb_reg_write(struct usb_device *usbdev,
status = usb_control_msg(usbdev,
usb_sndctrlpipe(usbdev, 0),
USB_VENDOR_REGISTER_WRITE,
- USB_TYPE_VENDOR,
+ RSI_USB_REQ_OUT,
((reg & 0xffff0000) >> 16),
(reg & 0xffff),
(void *)usb_reg_buf,
@@ -274,6 +291,62 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter)
}
/**
+ * rsi_usb_read_register_multiple() - This function reads multiple
+ * bytes of data from the address.
+ * @adapter: Pointer to the adapter structure.
+ * @addr: Address of the register.
+ * @data: Read data.
+ * @len: Number of bytes to read.
+ *
+ * Return: status: 0 on success, a negative error code on failure.
+ */
+int rsi_usb_read_register_multiple(struct rsi_hw *adapter,
+ u32 addr,
+ u8 *data,
+ u16 count)
+{
+ struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ u8 *buf;
+ u16 transfer;
+ int status = 0;
+
+ if (addr == 0)
+ return -EINVAL;
+
+ buf = kzalloc(4096, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ while (count) {
+ transfer = min_t(int, count, 4096);
+ status = usb_control_msg(dev->usbdev,
+ usb_rcvctrlpipe(dev->usbdev, 0),
+ USB_VENDOR_REGISTER_READ,
+ USB_TYPE_VENDOR,
+ ((addr & 0xffff0000) >> 16),
+ (addr & 0xffff),
+ (void *)buf,
+ transfer,
+ HZ * 5);
+ if (status < 0) {
+ rsi_dbg(ERR_ZONE,
+ "Reg read failed with error code :%d\n",
+ status);
+ kfree(buf);
+ return status;
+
+ } else {
+ memcpy(data, buf, transfer);
+ count -= transfer;
+ data += transfer;
+ addr += transfer;
+ }
+ }
+ kfree(buf);
+ return status;
+}
+
+/**
* rsi_usb_write_register_multiple() - This function writes multiple bytes of
* information to multiple registers.
* @adapter: Pointer to the adapter structure.
@@ -286,7 +359,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter)
int rsi_usb_write_register_multiple(struct rsi_hw *adapter,
u32 addr,
u8 *data,
- u32 count)
+ u16 count)
{
struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
u8 *buf;
@@ -333,9 +406,9 @@ int rsi_usb_write_register_multiple(struct rsi_hw *adapter,
*
* Return: 0 on success, a negative error code on failure.
*/
-static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter,
- u8 *pkt,
- u32 len)
+int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter,
+ u8 *pkt,
+ u32 len)
{
u32 queueno = ((pkt[1] >> 4) & 0xf);
u8 endpoint;
@@ -344,10 +417,76 @@ static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter,
return rsi_write_multiple(adapter,
endpoint,
- (u8 *)pkt,
+ pkt,
len);
}
+int rsi_usb_master_reg_read(struct rsi_hw *adapter,
+ u32 reg,
+ u32 *value,
+ u16 len)
+{
+ struct usb_device *usbdev =
+ ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev;
+
+ return rsi_usb_reg_read(usbdev, reg, value, len);
+}
+
+int rsi_usb_master_reg_write(struct rsi_hw *adapter,
+ unsigned long reg,
+ unsigned long value,
+ u16 len)
+{
+ struct usb_device *usbdev =
+ ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev;
+
+ return rsi_usb_reg_write(usbdev, reg, value, len);
+}
+
+int rsi_usb_load_data_master_write(struct rsi_hw *adapter,
+ u32 base_address,
+ u32 instructions_sz,
+ u16 block_size,
+ u8 *ta_firmware)
+{
+ u16 num_blocks;
+ u32 cur_indx, ii;
+ u8 temp_buf[256];
+
+ num_blocks = instructions_sz / block_size;
+ rsi_dbg(INFO_ZONE, "num_blocks: %d\n", num_blocks);
+
+ for (cur_indx = 0, ii = 0;
+ ii < num_blocks;
+ ii++, cur_indx += block_size) {
+ memset(temp_buf, 0, block_size);
+ memcpy(temp_buf, ta_firmware + cur_indx, block_size);
+ if ((rsi_usb_write_register_multiple(adapter,
+ base_address,
+ (u8 *)(temp_buf),
+ block_size)) < 0)
+ return -1;
+
+ rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, ii);
+ base_address += block_size;
+ }
+
+ if (instructions_sz % block_size) {
+ memset(temp_buf, 0, block_size);
+ memcpy(temp_buf, ta_firmware + cur_indx,
+ instructions_sz % block_size);
+ if ((rsi_usb_write_register_multiple(adapter,
+ base_address,
+ (u8 *)temp_buf,
+ instructions_sz % block_size)) < 0)
+ return -1;
+ rsi_dbg(INFO_ZONE,
+ "Written Last Block in Address 0x%x Successfully\n",
+ cur_indx);
+ }
+ return 0;
+}
+
/**
* rsi_deinit_usb_interface() - This function deinitializes the usb interface.
* @adapter: Pointer to the adapter structure.
@@ -413,9 +552,9 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
/* Initializing function callbacks */
adapter->rx_urb_submit = rsi_rx_urb_submit;
- adapter->host_intf_write_pkt = rsi_usb_host_intf_write_pkt;
adapter->check_hw_queue_status = rsi_usb_check_queue_status;
adapter->determine_event_timeout = rsi_usb_event_timeout;
+ adapter->host_intf_ops = &usb_host_intf_ops;
rsi_init_event(&rsi_dev->rx_thread.event);
status = rsi_create_kthread(common, &rsi_dev->rx_thread,
@@ -456,7 +595,7 @@ static int rsi_probe(struct usb_interface *pfunction,
{
struct rsi_hw *adapter;
struct rsi_91x_usbdev *dev;
- u16 fw_status;
+ u32 fw_status;
int status;
rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);
@@ -467,6 +606,7 @@ static int rsi_probe(struct usb_interface *pfunction,
__func__);
return -ENOMEM;
}
+ adapter->rsi_host_intf = RSI_HOST_INTF_USB;
status = rsi_init_usb_interface(adapter, pfunction);
if (status) {
@@ -480,25 +620,20 @@ static int rsi_probe(struct usb_interface *pfunction,
dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
status = rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2);
- if (status)
+ if (status < 0)
goto err1;
else
fw_status &= 1;
if (!fw_status) {
- status = rsi_usb_device_init(adapter->priv);
+ rsi_dbg(INIT_ZONE, "Loading firmware...\n");
+ status = rsi_hal_device_init(adapter);
if (status) {
rsi_dbg(ERR_ZONE, "%s: Failed in device init\n",
__func__);
goto err1;
}
-
- status = rsi_usb_reg_write(dev->usbdev,
- USB_INTERNAL_REG_1,
- RSI_USB_READY_MAGIC_NUM, 1);
- if (status)
- goto err1;
- rsi_dbg(INIT_ZONE, "%s: Performed device init\n", __func__);
+ rsi_dbg(INIT_ZONE, "%s: Device Init Done\n", __func__);
}
status = rsi_rx_urb_submit(adapter);
@@ -554,6 +689,7 @@ static const struct usb_device_id rsi_dev_table[] = {
{ USB_DEVICE(0x041B, 0x0301) },
{ USB_DEVICE(0x041B, 0x0201) },
{ USB_DEVICE(0x041B, 0x9330) },
+ { USB_DEVICE(0x1618, 0x9113) },
{ /* Blank */},
};
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
index de49008..949b572 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
@@ -19,67 +19,6 @@
#include "rsi_usb.h"
/**
- * rsi_copy_to_card() - This function includes the actual funtionality of
- * copying the TA firmware to the card.Basically this
- * function includes opening the TA file,reading the TA
- * file and writing their values in blocks of data.
- * @common: Pointer to the driver private structure.
- * @fw: Pointer to the firmware value to be written.
- * @len: length of firmware file.
- * @num_blocks: Number of blocks to be written to the card.
- *
- * Return: 0 on success and -1 on failure.
- */
-static int rsi_copy_to_card(struct rsi_common *common,
- const u8 *fw,
- u32 len,
- u32 num_blocks)
-{
- struct rsi_hw *adapter = common->priv;
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
- u32 indx, ii;
- u32 block_size = dev->tx_blk_size;
- u32 lsb_address;
- u32 base_address;
-
- base_address = TA_LOAD_ADDRESS;
-
- for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) {
- lsb_address = base_address;
- if (rsi_usb_write_register_multiple(adapter,
- lsb_address,
- (u8 *)(fw + indx),
- block_size)) {
- rsi_dbg(ERR_ZONE,
- "%s: Unable to load %s blk\n", __func__,
- FIRMWARE_RSI9113);
- return -EIO;
- }
- rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii);
- base_address += block_size;
- }
-
- if (len % block_size) {
- lsb_address = base_address;
- if (rsi_usb_write_register_multiple(adapter,
- lsb_address,
- (u8 *)(fw + indx),
- len % block_size)) {
- rsi_dbg(ERR_ZONE,
- "%s: Unable to load %s blk\n", __func__,
- FIRMWARE_RSI9113);
- return -EIO;
- }
- }
- rsi_dbg(INIT_ZONE,
- "%s: Succesfully loaded %s instructions\n", __func__,
- FIRMWARE_RSI9113);
-
- rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__);
- return 0;
-}
-
-/**
* rsi_usb_rx_thread() - This is a kernel thread to receive the packets from
* the USB device.
* @common: Pointer to the driver private structure.
@@ -103,83 +42,20 @@ void rsi_usb_rx_thread(struct rsi_common *common)
if (status) {
rsi_dbg(ERR_ZONE, "%s: Failed To read data", __func__);
mutex_unlock(&common->tx_rxlock);
- return;
+ break;
}
mutex_unlock(&common->tx_rxlock);
rsi_reset_event(&dev->rx_thread.event);
if (adapter->rx_urb_submit(adapter)) {
rsi_dbg(ERR_ZONE,
"%s: Failed in urb submission", __func__);
- return;
+ break;
}
} while (1);
out:
rsi_dbg(INFO_ZONE, "%s: Terminated thread\n", __func__);
+ atomic_inc(&dev->rx_thread.thread_done);
complete_and_exit(&dev->rx_thread.completion, 0);
}
-
-/**
- * rsi_load_ta_instructions() - This function includes the actual funtionality
- * of loading the TA firmware.This function also
- * includes opening the TA file,reading the TA
- * file and writing their value in blocks of data.
- * @common: Pointer to the driver private structure.
- *
- * Return: status: 0 on success, -1 on failure.
- */
-static int rsi_load_ta_instructions(struct rsi_common *common)
-{
- struct rsi_hw *adapter = common->priv;
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
- const struct firmware *fw_entry = NULL;
- u32 block_size = dev->tx_blk_size;
- const u8 *fw;
- u32 num_blocks, len;
- int status = 0;
-
- status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device);
- if (status < 0) {
- rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n",
- __func__, FIRMWARE_RSI9113);
- return status;
- }
-
- /* Copy firmware into DMA-accessible memory */
- fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
- if (!fw) {
- status = -ENOMEM;
- goto out;
- }
- len = fw_entry->size;
-
- if (len % 4)
- len += (4 - (len % 4));
-
- num_blocks = (len / block_size);
-
- rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);
- rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
-
- status = rsi_copy_to_card(common, fw, len, num_blocks);
- kfree(fw);
-
-out:
- release_firmware(fw_entry);
- return status;
-}
-
-/**
- * rsi_device_init() - This Function Initializes The HAL.
- * @common: Pointer to the driver private structure.
- *
- * Return: 0 on success, -1 on failure.
- */
-int rsi_usb_device_init(struct rsi_common *common)
-{
- if (rsi_load_ta_instructions(common))
- return -EIO;
-
- return 0;
- }
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index d3fbe33..8c8cad4 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -63,6 +63,7 @@ static inline int rsi_create_kthread(struct rsi_common *common,
u8 *name)
{
init_completion(&thread->completion);
+ atomic_set(&thread->thread_done, 0);
thread->task = kthread_run(func_ptr, common, "%s", name);
if (IS_ERR(thread->task))
return (int)PTR_ERR(thread->task);
@@ -72,6 +73,9 @@ static inline int rsi_create_kthread(struct rsi_common *common,
static inline int rsi_kill_thread(struct rsi_thread *handle)
{
+ if (atomic_read(&handle->thread_done) > 0)
+ return 0;
+
atomic_inc(&handle->thread_done);
rsi_set_event(&handle->event);
diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h
new file mode 100644
index 0000000..f9e0fe3
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_hal.h
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2014 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_HAL_H__
+#define __RSI_HAL_H__
+
+#define TA_LOAD_ADDRESS 0x00
+#define FIRMWARE_RSI9113 "rsi_91x.fw"
+#define FLASH_WRITE_CHUNK_SIZE (4 * 1024)
+#define USB_FLASH_READ_CHUNK_SIZE ((2 * 1024) - 4)
+#define SDIO_FLASH_READ_CHUNK_SIZE (2 * 1024)
+#define FLASH_SECTOR_SIZE (4 * 1024)
+#define STARTING_BLOCK_INDEX 0
+#define FLASH_BLOCK_SIZE (32 * 1024)
+
+#define FLASH_SIZE_ADDR 0x04000016
+#define PING_BUFFER_ADDRESS 0x19000
+#define PONG_BUFFER_ADDRESS 0x1a000
+#define SWBL_REGIN 0x41050034
+#define SWBL_REGOUT 0x4105003c
+#define PING_WRITE 0x1
+#define PONG_WRITE 0x2
+
+#define BL_CMD_TIMEOUT 500
+#define BL_BURN_TIMEOUT (40 * 1000)
+
+#define MASTER_READ_MODE 1
+#define EEPROM_READ_MODE 2
+
+#define REGIN_VALID 0xA
+#define REGIN_INPUT 0xA0
+#define REGOUT_VALID 0xAB
+#define REGOUT_INVALID (~0xAB)
+#define CMD_PASS 0xAA
+#define CMD_FAIL 0xCC
+#define INVALID_ADDR 0x4C
+
+#define BURN_BL 0x23
+#define LOAD_HOSTED_FW 'A'
+#define BURN_HOSTED_FW 'B'
+#define PING_VALID 'I'
+#define PONG_VALID 'O'
+#define PING_AVAIL 'I'
+#define PONG_AVAIL 'O'
+#define EOF_REACHED 'E'
+#define CHECK_CRC 'K'
+#define POLLING_MODE 'P'
+#define CONFIG_AUTO_READ_MODE 'R'
+#define JUMP_TO_ZERO_PC 'J'
+#define FW_LOADING_SUCCESSFUL 'S'
+#define LOADING_INITIATED '1'
+
+/* Boot loader commands */
+#define HOST_INTF_REG_OUT 0x4105003C
+#define HOST_INTF_REG_IN 0x41050034
+#define BOARD_READY 0xABCD
+#define REG_READ 0xD1
+#define REG_WRITE 0xD2
+#define SEND_RPS_FILE '2'
+#define BOOTUP_OPTIONS_LAST_CONFIG_NOT_SAVED 0xF1
+#define BOOTUP_OPTIONS_CHECKSUM_FAIL 0xF2
+#define INVALID_OPTION 0xF3
+#define CHECKSUM_SUCCESS 0xAA
+#define CHECKSUM_FAILURE 0xCC
+#define CHECKSUM_INVALID_ADDRESS 0x4C
+
+#define EEPROM_VERSION_OFFSET 77
+#define CALIB_CRC_OFFSET 4092
+#define MAGIC_WORD 0x5A
+#define MAGIC_WORD_OFFSET_1 40
+#define MAGIC_WORD_OFFSET_2 424
+#define FW_IMAGE_MIN_ADDRESS (68 * 1024)
+#define FLASH_MAX_ADDRESS (4 * 1024 * 1024) //4MB
+#define MAX_FLASH_FILE_SIZE (400 * 1024) //400K
+#define FLASHING_START_ADDRESS 16
+#define CALIB_VALUES_START_ADDR 16
+#define SOC_FLASH_ADDR 0x04000000
+#define EEPROM_DATA_SIZE 4096
+#define CALIB_DATA_SIZE (EEPROM_DATA_SIZE - CALIB_VALUES_START_ADDR)
+#define BL_HEADER 32
+
+#define BT_CARD_READY_IND 0x89
+#define WLAN_CARD_READY_IND 0x0
+#define COMMON_HAL_CARD_READY_IND 0x0
+#define ZIGB_CARD_READY_IND 0xff
+
+#define COMMAN_HAL_WAIT_FOR_CARD_READY 1
+#define COMMON_HAL_SEND_CONFIG_PARAMS 2
+#define COMMON_HAL_TX_ACCESS 3
+#define COMMON_HAL_WAIT_FOR_PROTO_CARD_READY 4
+#define HEX_FILE 1
+#define BIN_FILE 0
+#define UNIX_FILE_TYPE 8
+#define DOS_FILE_TYPE 9
+#define LMAC_INSTRUCTIONS_SIZE (16 * 1024) /* 16Kbytes */
+
+#define ULP_RESET_REG 0x161
+#define WATCH_DOG_TIMER_1 0x16c
+#define WATCH_DOG_TIMER_2 0x16d
+#define WATCH_DOG_DELAY_TIMER_1 0x16e
+#define WATCH_DOG_DELAY_TIMER_2 0x16f
+#define WATCH_DOG_TIMER_ENABLE 0x170
+
+#define RESTART_WDT BIT(11)
+#define BYPASS_ULP_ON_WDT BIT(1)
+
+#define RF_SPI_PROG_REG_BASE_ADDR 0x40080000
+
+#define GSPI_CTRL_REG0 (RF_SPI_PROG_REG_BASE_ADDR)
+#define GSPI_CTRL_REG1 (RF_SPI_PROG_REG_BASE_ADDR + 0x2)
+#define GSPI_DATA_REG0 (RF_SPI_PROG_REG_BASE_ADDR + 0x4)
+#define GSPI_DATA_REG1 (RF_SPI_PROG_REG_BASE_ADDR + 0x6)
+#define GSPI_DATA_REG2 (RF_SPI_PROG_REG_BASE_ADDR + 0x8)
+
+#define GSPI_DMA_MODE BIT(13)
+
+#define GSPI_2_ULP BIT(12)
+#define GSPI_TRIG BIT(7)
+#define GSPI_READ BIT(6)
+#define GSPI_RF_SPI_ACTIVE BIT(8)
+
+struct bl_header {
+ u32 flags;
+ u32 image_no;
+ u32 check_sum;
+ u32 flash_start_address;
+ u32 flash_len;
+} __packed;
+
+struct ta_metadata {
+ char *name;
+ unsigned int address;
+};
+
+int rsi_hal_device_init(struct rsi_hw *adapter);
+
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index dcd0957..752c429 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -204,10 +204,43 @@ struct rsi_common {
struct cqm_info cqm_info;
bool hw_data_qs_blocked;
+
+ u8 coex_mode;
+};
+
+enum host_intf {
+ RSI_HOST_INTF_SDIO = 0,
+ RSI_HOST_INTF_USB
+};
+
+enum rsi_dev_model {
+ RSI_DEV_9110 = 0,
+ RSI_DEV_9113,
+ RSI_DEV_9116
+};
+
+struct eepromrw_info {
+ u32 offset;
+ u32 length;
+ u8 write;
+ u16 eeprom_erase;
+ u8 data[480];
+};
+
+struct eeprom_read {
+ u16 length;
+ u16 off_set;
+};
+
+struct xtended_desc {
+ u8 confirm_frame_type;
+ u8 retry_cnt;
+ u16 reserved;
};
struct rsi_hw {
struct rsi_common *priv;
+ enum rsi_dev_model device_model;
struct ieee80211_hw *hw;
struct ieee80211_vif *vifs[RSI_MAX_VIFS];
struct ieee80211_tx_queue_params edca_params[NUM_EDCA_QUEUES];
@@ -215,16 +248,47 @@ struct rsi_hw {
struct device *device;
u8 sc_nvifs;
+ enum host_intf rsi_host_intf;
#ifdef CONFIG_RSI_DEBUGFS
struct rsi_debugfs *dfsentry;
u8 num_debugfs_entries;
#endif
+
+ struct timer_list bl_cmd_timer;
+ u8 blcmd_timer_expired;
+ u32 flash_capacity;
+ u32 tx_blk_size;
+ u32 common_hal_fsm;
+ u8 eeprom_init;
+ struct eepromrw_info eeprom;
+ u8 *calib_data;
+ u32 interrupt_status;
+
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);
+
+ struct rsi_host_intf_ops *host_intf_ops;
int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num);
int (*rx_urb_submit)(struct rsi_hw *adapter);
int (*determine_event_timeout)(struct rsi_hw *adapter);
};
+
+struct rsi_host_intf_ops {
+ int (*read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len);
+ int (*write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len);
+ int (*master_access_msword)(struct rsi_hw *adapter, u16 ms_word);
+ int (*read_reg_multiple)(struct rsi_hw *adapter, u32 addr,
+ u8 *data, u16 count);
+ int (*write_reg_multiple)(struct rsi_hw *adapter, u32 addr,
+ u8 *data, u16 count);
+ int (*master_reg_read)(struct rsi_hw *adapter, u32 addr,
+ u32 *read_buf, u16 size);
+ int (*master_reg_write)(struct rsi_hw *adapter,
+ unsigned long addr, unsigned long data,
+ u16 size);
+ int (*load_data_master_write)(struct rsi_hw *adapter, u32 addr,
+ u32 instructions_size, u16 block_size,
+ u8 *fw);
+};
+
#endif
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index 3741173..f8823126 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -62,6 +62,7 @@
#define RF_RESET_ENABLE BIT(3)
#define RATE_INFO_ENABLE BIT(0)
#define RSI_BROADCAST_PKT BIT(9)
+#define RSI_DESC_REQUIRE_CFM_TO_HOST BIT(10)
#define UPPER_20_ENABLE (0x2 << 12)
#define LOWER_20_ENABLE (0x4 << 12)
@@ -306,4 +307,5 @@ 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_flash_read(struct rsi_hw *adapter);
#endif
diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h
index c7e8f2b..6a747c5 100644
--- a/drivers/net/wireless/rsi/rsi_sdio.h
+++ b/drivers/net/wireless/rsi/rsi_sdio.h
@@ -118,11 +118,25 @@ void rsi_interrupt_handler(struct rsi_hw *adapter);
int rsi_init_sdio_slave_regs(struct rsi_hw *adapter);
int rsi_sdio_device_init(struct rsi_common *common);
int rsi_sdio_read_register(struct rsi_hw *adapter, u32 addr, u8 *data);
-int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, u8 *pkt, u32 length);
int rsi_sdio_write_register(struct rsi_hw *adapter, u8 function,
u32 addr, u8 *data);
+int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, u8 *pkt, u32 length);
+int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter, u8 *pkt, u32 len);
+int rsi_sdio_read_register_multiple(struct rsi_hw *adapter, u32 addr,
+ u8 *data, u16 count);
int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr,
- u8 *data, u32 count);
+ u8 *data, u16 count);
+int rsi_sdio_master_access_msword(struct rsi_hw *adapter,
+ u16 ms_word);
+int rsi_sdio_load_data_master_write(struct rsi_hw *adapter,
+ u32 base_address, u32 instructions_sz,
+ u16 block_size, u8 *ta_firmware);
+int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
+ u32 *read_buf, u16 size);
+int rsi_sdio_master_reg_write(struct rsi_hw *adapter,
+ unsigned long addr,
+ unsigned long data,
+ u16 size);
void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit);
int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter);
int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num);
diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h
index ebea0c4..d21d40d 100644
--- a/drivers/net/wireless/rsi/rsi_usb.h
+++ b/drivers/net/wireless/rsi/rsi_usb.h
@@ -62,7 +62,19 @@ static inline int rsi_usb_event_timeout(struct rsi_hw *adapter)
}
int rsi_usb_device_init(struct rsi_common *common);
+int rsi_usb_read_register_multiple(struct rsi_hw *adapter, u32 addr,
+ u8 *data, u16 count);
int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr,
- u8 *data, u32 count);
+ u8 *data, u16 count);
void rsi_usb_rx_thread(struct rsi_common *common);
+
+int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter, u8 *pkt, u32 len);
+int rsi_usb_master_reg_read(struct rsi_hw *adapter, u32 reg,
+ u32 *value, u16 len);
+int rsi_usb_master_reg_write(struct rsi_hw *adapter, unsigned long reg,
+ unsigned long value, u16 len);
+int rsi_usb_load_data_master_write(struct rsi_hw *adapter, u32 base_address,
+ u32 instructions_sz,
+ u16 block_size,
+ u8 *ta_firmware);
#endif
--
2.4.11
^ permalink raw reply related
* Re: [PATCH][RFC] nl80211/mac80211: Rounded RSSI reporting
From: Johannes Berg @ 2016-10-21 8:30 UTC (permalink / raw)
To: Andrew Zaborowski, linux-wireless
In-Reply-To: <1477010947-6207-1-git-send-email-andrew.zaborowski@intel.com>
Hi,
> Userspace tends to display a wifi icon with the rssi shown as a
> number of "signal bars", usually 4, 5, or 6.
It's actually not clear to me that this is really how it should be.
There's a point to be made that taking a more holistic "link quality"
would be a better choice. That's related, but maybe can be a separate
discussion.
> and a hysteresis value to be used in the same way as with the
> NL80211_ATTR_CQM_RSSI_THOLD attribute, or even modify it to allow
> multiple thresholds to be given but that would need a problematic
> driver api change. What would be the best way to do that?
So ... I don't think there's a good way to do this at all.
The problem is that you really want this to be offloaded to the device,
*especially* if you care about low power usage, because you absolutely
don't want to be processing each beacon (which is typically what we
derive the data from today) in the host CPU - you want those to be
filtered by the device so you don't wake up the host CPU every ~102ms.
Without offloading to the device, your patch is actually fairly much
pointless, because you've already woken up the host CPU, at which point
punting to userspace probably isn't all that much more expensive over
the cost of waking up the CPU in the first place.
Looking at the code, it seems like only a single driver could support
this in a pseudo-offloaded fashion (iwlmvm), where all the others that
offload it today would not be able to support this API at all, unless
they fall back to complete software processing which, as I wrote above,
will have far worse power consumption consequences.
Therefore, adding this API just for mac80211 seems pretty pointless,
especially since you're targeting this for IoT, where I expect people
will be using full-MAC chips rather than soft-MAC, with the consequence
of not even using mac80211-based drivers. Oops.
> The assumption is that you can't simulate the same behavior with just
> the current NL80211_ATTR_CQM_RSSI_THOLD attribute.
Is that true? Technically, it seems that perhaps if you wanted to have
a few ranges, you could always pick one that's currently active, and
program that into the driver/device, with a hysteresis big enough to
extend to the edges of the next range, or something?
Let's say you're currently sitting at -50dBm, and want your ranges to
be -100..-80..-60..-40..-20. Then you could program -50dBm with
hysteresis of 10dBm, and it'd tell you when you move below/above?
This probably won't really work, the hysteresis probably won't be
honoured precisely enough by all drivers. Or we can just fix the
drivers, I guess. However, if you're just at the edge of your range,
e.g. when your current signal strength is -60dBm, you'd still flip-flop
in and out of that range continuously, although userspace could just
program a different threshold/hysteresis for those cases as well.
Anyway, not sure this can be made to work, and drivers would play ball.
Nevertheless, somewhere along these lines we could probably make things
work better than hard-coding the kind of assumptions you have in your
patch. Perhaps by extending this to know about low/medium/high, which a
number of drivers seem to support, so that you can program -60,-40
(with some appropriate hysteresis) and then get a signal when you move
out of that range towards low or towards high. When that's stable
enough, you can then dynamically reconfigure to the next range.
johannes
^ permalink raw reply
* Re: [PATCH] cfg80211: add generic helper to check interface is running
From: Johannes Berg @ 2016-10-21 7:55 UTC (permalink / raw)
To: Arend van Spriel; +Cc: linux-wireless
In-Reply-To: <1476990502-32472-1-git-send-email-arend.vanspriel@broadcom.com>
On Thu, 2016-10-20 at 20:08 +0100, Arend van Spriel wrote:
> Adding a helper using wdev to check if interface is running. This
> deals with both non-netdev and netdev interfaces. In struct
> wireless_dev replacing 'p2p_started' and 'nan_started' by
> 'is_running' as those are mutual exclusive anyway.
Applied, thanks.
I renamed the helper to just wdev_running() because we also have
sdata_running() in mac80211.
johannes
^ permalink raw reply
* Re: [PATCH] cfg80211: allow vendor commands to be sent to nan interface
From: Arend Van Spriel @ 2016-10-21 7:50 UTC (permalink / raw)
To: Johannes Berg, Luca Coelho
Cc: linux-wireless, Andrei Otcheretianski, Luca Coelho
In-Reply-To: <1476967536.4929.23.camel@sipsolutions.net>
On 20-10-2016 14:45, Johannes Berg wrote:
> On Thu, 2016-10-20 at 14:44 +0200, Arend Van Spriel wrote:
>>
>> Sure. On top of this patch or will you deal with those conflicts?
>>
>
> I already applied this, so on top please (i.e. just resend what you
> just had, with a commit message?)
Yup. Did not check/realize/whatever. I send it out yesterday [1].
Regards,
Arend
[1] https://patchwork.kernel.org/patch/9387467/
^ permalink raw reply
* Re: [PATCH v4] mwifiex: parse device tree node for PCIe
From: Brian Norris @ 2016-10-21 2:06 UTC (permalink / raw)
To: Rajat Jain
Cc: linux-wireless, devicetree, Xinming Hu, Amitkumar Karwar,
Brian Norris, Kalle Valo, Rob Herring, rajatxjain
In-Reply-To: <1477009812-95032-1-git-send-email-rajatja@google.com>
On Thu, Oct 20, 2016 at 05:30:12PM -0700, Rajat Jain wrote:
> From: Xinming Hu <huxm@marvell.com>
>
> This patch derives device tree node from pcie bus layer framework.
> Device tree bindings file has been renamed(marvell-sd8xxx.txt ->
> marvell-8xxx.txt) to accomodate PCIe changes.
>
> Signed-off-by: Xinming Hu <huxm@marvell.com>
> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> Signed-off-by: Rajat Jain <rajatja@google.com>
> ---
> Since I need this patch and haven't seen updates, I thought I'll take a stab.
>
> v2: Included vendor and product IDs in compatible strings for PCIe
> chipsets(Rob Herring)
> v3: Patch is created using -M option so that it will only include diff of
> original and renamed files(Rob Herring)
> Resend v3: Resending the patch because I missed to include device tree mailing
> while sending v3.
> v4: Fix error handling, also move-on even if no device tree node is present.
>
> .../{marvell-sd8xxx.txt => marvell-8xxx.txt} | 8 +++--
> drivers/net/wireless/marvell/mwifiex/pcie.c | 39 +++++++++++++++++++---
> drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 3 +-
> 3 files changed, 42 insertions(+), 8 deletions(-)
> rename Documentation/devicetree/bindings/net/wireless/{marvell-sd8xxx.txt => marvell-8xxx.txt} (91%)
Patch looks better to me (esp. the error handling):
Reviewed-by: Brian Norris <briannorris@chromium.org>
> diff --git a/Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt b/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
> similarity index 91%
> rename from Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt
> rename to Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
> index c421aba..dfe5f8e 100644
> --- a/Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt
> +++ b/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
> @@ -1,8 +1,8 @@
> -Marvell 8897/8997 (sd8897/sd8997) SDIO devices
> +Marvell 8897/8997 (sd8897/sd8997/pcie8997) SDIO/PCIE devices
> ------
>
> -This node provides properties for controlling the marvell sdio wireless device.
> -The node is expected to be specified as a child node to the SDIO controller that
> +This node provides properties for controlling the marvell sdio/pcie wireless device.
> +The node is expected to be specified as a child node to the SDIO/PCIE controller that
> connects the device to the system.
>
> Required properties:
> @@ -10,6 +10,8 @@ Required properties:
> - compatible : should be one of the following:
> * "marvell,sd8897"
> * "marvell,sd8997"
> + * "pci11ab,2b42"
> + * "pci1b4b,2b42"
>
> Optional properties:
>
> diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
> index 3c3c4f1..b3e6f06 100644
> --- a/drivers/net/wireless/marvell/mwifiex/pcie.c
> +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
> @@ -37,6 +37,22 @@ static struct mwifiex_if_ops pcie_ops;
>
> static struct semaphore add_remove_card_sem;
>
> +static const struct of_device_id mwifiex_pcie_of_match_table[] = {
> + { .compatible = "pci11ab,2b42" },
> + { .compatible = "pci1b4b,2b42" },
> + { }
> +};
> +
> +static int mwifiex_pcie_probe_of(struct device *dev)
> +{
> + if (!of_match_node(mwifiex_pcie_of_match_table, dev->of_node)) {
> + pr_err("pcie device node not available");
> + return -1;
Not a big fan of these '-1' error codes, instead or proper error codes.
But that's preexisting. (Or at least, this matches the sdio.c version.)
> + }
> +
> + return 0;
> +}
> +
> static int
> mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
> size_t size, int flags)
> @@ -178,6 +194,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
> const struct pci_device_id *ent)
> {
> struct pcie_service_card *card;
> + int ret;
>
> pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
> pdev->vendor, pdev->device, pdev->revision);
> @@ -199,13 +216,27 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
> card->pcie.can_ext_scan = data->can_ext_scan;
> }
>
> - if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
> - MWIFIEX_PCIE)) {
> - pr_err("%s failed\n", __func__);
> - return -1;
> + /* device tree node parsing and platform specific configuration*/
> + if (pdev->dev.of_node) {
> + ret = mwifiex_pcie_probe_of(&pdev->dev);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "required compatible string missing\n");
> + goto err_free;
> + }
> }
>
> + ret = mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
> + MWIFIEX_PCIE);
> + if (ret) {
> + pr_err("%s failed\n", __func__);
> + goto err_free;
> + }
> return 0;
> +
> +err_free:
> + kfree(card);
Is it just me, or does this fix a memory leak too? Not a big deal IMO,
but maybe worth noting.
Brian
> + return ret;
> }
>
> /*
> diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
> index 2a162c3..c8dccf5 100644
> --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
> +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
> @@ -2218,7 +2218,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
> * The cal-data can be read from device tree and/or
> * a configuration file and downloaded to firmware.
> */
> - if (priv->adapter->iface_type == MWIFIEX_SDIO &&
> + if ((priv->adapter->iface_type == MWIFIEX_SDIO ||
> + priv->adapter->iface_type == MWIFIEX_PCIE) &&
> adapter->dev->of_node) {
> adapter->dt_node = adapter->dev->of_node;
> if (of_property_read_u32(adapter->dt_node,
> --
> 2.8.0.rc3.226.g39d4020
>
^ permalink raw reply
* [PATCH][RFC] nl80211/mac80211: Rounded RSSI reporting
From: Andrew Zaborowski @ 2016-10-21 0:49 UTC (permalink / raw)
To: linux-wireless
Hi,
I'm looking for a way to enable userspace to receive RSSI updates
without polling and waking up only as often as needed, for use in a
wifi daemon oriented for low power. Userspace tends to display a wifi
icon with the rssi shown as a number of "signal bars", usually 4, 5,
or 6. This patch adds an nl80211 CQM command and an event to report
exactly this information and nothing more. The
NL80211_ATTR_CQM_ROUNDED_RSSI_STEPS attribute is used to set how many
bars are used and assumes -100dbm to be the minimum. It's not very
flexible. It may be better, for example to accept a list of thresholds
and a hysteresis value to be used in the same way as with the
NL80211_ATTR_CQM_RSSI_THOLD attribute, or even modify it to allow
multiple thresholds to be given but that would need a problematic
driver api change. What would be the best way to do that?
The assumption is that you can't simulate the same behavior with just
the current NL80211_ATTR_CQM_RSSI_THOLD attribute.
Best regards
---
include/net/cfg80211.h | 21 ++++++++++++++++++
include/net/mac80211.h | 4 ++++
include/uapi/linux/nl80211.h | 10 +++++++++
net/mac80211/cfg.c | 18 +++++++++++++++
net/mac80211/ieee80211_i.h | 11 ++++++++--
net/mac80211/mlme.c | 27 +++++++++++++++++++++++
net/wireless/nl80211.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
net/wireless/rdev-ops.h | 11 ++++++++++
net/wireless/trace.h | 33 ++++++++++++++++++++++++++++
9 files changed, 185 insertions(+), 2 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bd19faa..3487b3f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2606,6 +2606,10 @@ struct cfg80211_nan_func {
* disabled.)
* @set_cqm_txe_config: Configure connection quality monitor TX error
* thresholds.
+ * @set_cqm_rssi_steps: Configure number of RSSI levels for the connection
+ * quality monitor to use in deciding when to send rounded RSSI change
+ * events. After configuration, the driver should (soon) send an event
+ * indicating the current level out of the number of levels set.
* @sched_scan_start: Tell the driver to start a scheduled scan.
* @sched_scan_stop: Tell the driver to stop an ongoing scheduled scan. This
* call must stop the scheduled scan and be ready for starting a new one
@@ -2891,6 +2895,9 @@ struct cfg80211_ops {
struct net_device *dev,
u32 rate, u32 pkts, u32 intvl);
+ int (*set_cqm_rssi_steps)(struct wiphy *wiphy,
+ struct net_device *dev, u32 steps);
+
void (*mgmt_frame_register)(struct wiphy *wiphy,
struct wireless_dev *wdev,
u16 frame_type, bool reg);
@@ -5213,6 +5220,20 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer,
void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp);
/**
+ * cfg80211_cqm_rounded_rssi_notify - connection quality monitoring rssi event
+ * @dev: network device
+ * @signal_level: the signal level in the range of 0 to (steps - 1)
+ * @gfp: context flags
+ *
+ * This function is called when the RSSI level, rounded to the resolution
+ * set by cfg80211_ops::set_cqm_rssi_steps, has changed. In other words
+ * the RSSI value has gone from one of the equally sized intervals, covering
+ * the range of -100dBm to 0, to another.
+ */
+void cfg80211_cqm_rounded_rssi_notify(struct net_device *dev,
+ u32 signal_level, gfp_t gfp);
+
+/**
* cfg80211_radar_event - radar detection event
* @wiphy: the wiphy
* @chandef: chandef for the current channel
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a810dfc..5fbe275 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -503,6 +503,9 @@ struct ieee80211_mu_group_data {
* cause an event to be sent indicating where the current value is in
* relation to the newly configured threshold.
* @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
+ * @cqm_rssi_steps: Connection quality monitor's number of RSSI levels to
+ * use when sending rounded RSSI change events. A zero value implies this
+ * event is disabled.
* @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
* may filter ARP queries targeted for other addresses than listed here.
* The driver must allow ARP queries targeted for all address listed here
@@ -554,6 +557,7 @@ struct ieee80211_bss_conf {
u16 ht_operation_mode;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
+ u32 cqm_rssi_steps;
struct cfg80211_chan_def chandef;
struct ieee80211_mu_group_data mu_group;
__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 56368e9..a2c8817 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3859,6 +3859,14 @@ enum nl80211_ps_state {
* %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
* @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
* loss event
+ * @NL80211_ATTR_CQM_ROUNDED_RSSI_STEPS: number of evenly spaced RSSI ranges
+ * to be distinguished between -100 dBm and 0. %NL80211_CMD_NOTIFY_CQM
+ * events will be sent when the RSSI value crosses from one range of
+ * values to another. Set to 0 to disable
+ * %NL80211_ATTR_CQM_ROUNDED_RSSI_EVENT reporting.
+ * @NL80211_ATTR_CQM_ROUNDED_RSSI_EVENT: the RSSI level with range reduced to
+ * 0 to steps - 1 as configured in %NL80211_ATTR_CQM_ROUNDED_RSSI_STEPS
+ * value.
* @__NL80211_ATTR_CQM_AFTER_LAST: internal
* @NL80211_ATTR_CQM_MAX: highest key attribute
*/
@@ -3872,6 +3880,8 @@ enum nl80211_attr_cqm {
NL80211_ATTR_CQM_TXE_PKTS,
NL80211_ATTR_CQM_TXE_INTVL,
NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
+ NL80211_ATTR_CQM_ROUNDED_RSSI_STEPS,
+ NL80211_ATTR_CQM_ROUNDED_RSSI_EVENT,
/* keep last */
__NL80211_ATTR_CQM_AFTER_LAST,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fd6541f..73550a7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2657,6 +2657,23 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
return 0;
}
+static int ieee80211_set_cqm_rssi_steps(struct wiphy *wiphy,
+ struct net_device *dev,
+ u32 steps)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_vif *vif = &sdata->vif;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+ if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
+ return -EOPNOTSUPP;
+
+ bss_conf->cqm_rssi_steps = steps;
+ sdata->u.mgd.last_cqm_event_rounded_rssi = 0;
+
+ return 0;
+}
+
static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
struct net_device *dev,
const u8 *addr,
@@ -3645,6 +3662,7 @@ const struct cfg80211_ops mac80211_config_ops = {
.mgmt_tx = ieee80211_mgmt_tx,
.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
+ .set_cqm_rssi_steps = ieee80211_set_cqm_rssi_steps,
.mgmt_frame_register = ieee80211_mgmt_frame_register,
.set_antenna = ieee80211_set_antenna,
.get_antenna = ieee80211_get_antenna,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 34c2add..1c04c21 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -507,12 +507,19 @@ struct ieee80211_if_managed {
/*
* Last Beacon frame signal strength average (ave_beacon_signal / 16)
- * that triggered a cqm event. 0 indicates that no event has been
- * generated for the current association.
+ * that triggered a cqm RSSI threshold-crossed event. 0 indicates
+ * that no event has been generated for the current association.
*/
int last_cqm_event_signal;
/*
+ * Last Beacon frame signal strength average (ave_beacon_signal / 16)
+ * that triggered a cqm rounded RSSI level event. 0 indicates that no
+ * event has been generated for the current association.
+ */
+ int last_cqm_event_rounded_rssi;
+
+ /*
* State variables for keeping track of RSSI of the AP currently
* connected to and informing driver when RSSI has gone
* below/above a certain threshold.
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7486f2d..a87422b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3253,6 +3253,14 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
ieee80211_reset_ap_probe(sdata);
}
+static void ieee80211_cqm_rounded_rssi_notify(struct ieee80211_vif *vif,
+ u32 signal_level, gfp_t gfp)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ cfg80211_cqm_rounded_rssi_notify(sdata->dev, signal_level, gfp);
+}
+
/*
* This is the canonical list of information elements we care about,
* the filter code also gives us all changes to the Microsoft OUI
@@ -3416,6 +3424,25 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}
}
+ if (bss_conf->cqm_rssi_steps &&
+ ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
+ int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
+ int last_event = ifmgd->last_cqm_event_rounded_rssi;
+ int steps = bss_conf->cqm_rssi_steps;
+ int last_level = (last_event + 100) * steps / 100;
+ int cur_level = (sig + 100) * steps / 100;
+ /* Use a threshold of 1/4th of the step size (100dBm / steps) */
+ int thold = 25 / steps;
+
+ if (last_event == 0 ||
+ (cur_level < last_level && sig < last_event - thold) ||
+ (cur_level > last_level && sig > last_event + thold)) {
+ ifmgd->last_cqm_event_rounded_rssi = sig;
+ ieee80211_cqm_rounded_rssi_notify(
+ &sdata->vif, cur_level, GFP_KERNEL);
+ }
+ }
+
if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
mlme_dbg_ratelimited(sdata,
"cancelling AP probe due to a received beacon\n");
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c510810..5bfc853 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9278,6 +9278,8 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
[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_ROUNDED_RSSI_STEPS] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_ROUNDED_RSSI_EVENT] = { .type = NLA_U32 },
};
static int nl80211_set_cqm_txe(struct genl_info *info,
@@ -9324,6 +9326,25 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
}
+static int nl80211_set_cqm_rounded_rssi_steps(struct genl_info *info, u32 steps)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (steps == 1)
+ return -EINVAL;
+
+ if (!rdev->ops->set_cqm_rssi_steps)
+ return -EOPNOTSUPP;
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
+
+ return rdev_set_cqm_rssi_steps(rdev, dev, steps);
+}
+
static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
@@ -9357,6 +9378,13 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
return nl80211_set_cqm_txe(info, rate, pkts, intvl);
}
+ if (attrs[NL80211_ATTR_CQM_ROUNDED_RSSI_STEPS]) {
+ u32 steps = nla_get_u32(
+ attrs[NL80211_ATTR_CQM_ROUNDED_RSSI_STEPS]);
+
+ return nl80211_set_cqm_rounded_rssi_steps(info, steps);
+ }
+
return -EINVAL;
}
@@ -13832,6 +13860,30 @@ void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
}
EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
+void cfg80211_cqm_rounded_rssi_notify(struct net_device *dev,
+ u32 signal_level, gfp_t gfp)
+{
+ struct sk_buff *msg;
+
+ trace_cfg80211_cqm_rounded_rssi_notify(dev, signal_level);
+
+ msg = cfg80211_prepare_cqm(dev, NULL, gfp);
+ if (!msg)
+ return;
+
+ if (nla_put_u32(msg, NL80211_ATTR_CQM_ROUNDED_RSSI_EVENT,
+ signal_level))
+ goto nla_put_failure;
+
+ cfg80211_send_cqm(msg, gfp);
+
+ return;
+
+ nla_put_failure:
+ nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_cqm_rounded_rssi_notify);
+
static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid,
const u8 *replay_ctr, gfp_t gfp)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 11cf83c..3521a2f 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -737,6 +737,17 @@ rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
return ret;
}
+static inline int
+rdev_set_cqm_rssi_steps(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, u32 steps)
+{
+ int ret;
+ trace_rdev_set_cqm_rssi_steps(&rdev->wiphy, dev, steps);
+ ret = rdev->ops->set_cqm_rssi_steps(&rdev->wiphy, dev, steps);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
static inline void
rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u16 frame_type, bool reg)
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index a3d0a91..dbc2450 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1327,6 +1327,24 @@ TRACE_EVENT(rdev_set_cqm_txe_config,
__entry->intvl)
);
+TRACE_EVENT(rdev_set_cqm_rssi_steps,
+ TP_PROTO(struct wiphy *wiphy,
+ struct net_device *netdev, u32 steps),
+ TP_ARGS(wiphy, netdev, steps),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __field(u32, steps)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ __entry->steps = steps;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", steps: %u ",
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->steps)
+);
+
TRACE_EVENT(rdev_disconnect,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
u16 reason_code),
@@ -2486,6 +2504,21 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
NETDEV_PR_ARG, __entry->rssi_event)
);
+TRACE_EVENT(cfg80211_cqm_rounded_rssi_notify,
+ TP_PROTO(struct net_device *netdev, u32 signal_level),
+ TP_ARGS(netdev, signal_level),
+ TP_STRUCT__entry(
+ NETDEV_ENTRY
+ __field(u32 signal_level)
+ ),
+ TP_fast_assign(
+ NETDEV_ASSIGN;
+ __entry->signal_level = signal_level;
+ ),
+ TP_printk(NETDEV_PR_FMT ", signal_level: %d",
+ NETDEV_PR_ARG, __entry->signal_level)
+);
+
TRACE_EVENT(cfg80211_reg_can_beacon,
TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
enum nl80211_iftype iftype, bool check_no_ir),
--
2.7.4
^ permalink raw reply related
* [PATCH v4] mwifiex: parse device tree node for PCIe
From: Rajat Jain @ 2016-10-21 0:30 UTC (permalink / raw)
To: linux-wireless, devicetree, Xinming Hu, Amitkumar Karwar,
Brian Norris, Kalle Valo, Rob Herring
Cc: rajatxjain, Rajat Jain
In-Reply-To: <20161005194827.GA14626@localhost>
From: Xinming Hu <huxm@marvell.com>
This patch derives device tree node from pcie bus layer framework.
Device tree bindings file has been renamed(marvell-sd8xxx.txt ->
marvell-8xxx.txt) to accomodate PCIe changes.
Signed-off-by: Xinming Hu <huxm@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Rajat Jain <rajatja@google.com>
---
Since I need this patch and haven't seen updates, I thought I'll take a stab.
v2: Included vendor and product IDs in compatible strings for PCIe
chipsets(Rob Herring)
v3: Patch is created using -M option so that it will only include diff of
original and renamed files(Rob Herring)
Resend v3: Resending the patch because I missed to include device tree mailing
while sending v3.
v4: Fix error handling, also move-on even if no device tree node is present.
.../{marvell-sd8xxx.txt => marvell-8xxx.txt} | 8 +++--
drivers/net/wireless/marvell/mwifiex/pcie.c | 39 +++++++++++++++++++---
drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 3 +-
3 files changed, 42 insertions(+), 8 deletions(-)
rename Documentation/devicetree/bindings/net/wireless/{marvell-sd8xxx.txt => marvell-8xxx.txt} (91%)
diff --git a/Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt b/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
similarity index 91%
rename from Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt
rename to Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
index c421aba..dfe5f8e 100644
--- a/Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt
+++ b/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
@@ -1,8 +1,8 @@
-Marvell 8897/8997 (sd8897/sd8997) SDIO devices
+Marvell 8897/8997 (sd8897/sd8997/pcie8997) SDIO/PCIE devices
------
-This node provides properties for controlling the marvell sdio wireless device.
-The node is expected to be specified as a child node to the SDIO controller that
+This node provides properties for controlling the marvell sdio/pcie wireless device.
+The node is expected to be specified as a child node to the SDIO/PCIE controller that
connects the device to the system.
Required properties:
@@ -10,6 +10,8 @@ Required properties:
- compatible : should be one of the following:
* "marvell,sd8897"
* "marvell,sd8997"
+ * "pci11ab,2b42"
+ * "pci1b4b,2b42"
Optional properties:
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 3c3c4f1..b3e6f06 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -37,6 +37,22 @@ static struct mwifiex_if_ops pcie_ops;
static struct semaphore add_remove_card_sem;
+static const struct of_device_id mwifiex_pcie_of_match_table[] = {
+ { .compatible = "pci11ab,2b42" },
+ { .compatible = "pci1b4b,2b42" },
+ { }
+};
+
+static int mwifiex_pcie_probe_of(struct device *dev)
+{
+ if (!of_match_node(mwifiex_pcie_of_match_table, dev->of_node)) {
+ pr_err("pcie device node not available");
+ return -1;
+ }
+
+ return 0;
+}
+
static int
mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
size_t size, int flags)
@@ -178,6 +194,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct pcie_service_card *card;
+ int ret;
pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
pdev->vendor, pdev->device, pdev->revision);
@@ -199,13 +216,27 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
card->pcie.can_ext_scan = data->can_ext_scan;
}
- if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
- MWIFIEX_PCIE)) {
- pr_err("%s failed\n", __func__);
- return -1;
+ /* device tree node parsing and platform specific configuration*/
+ if (pdev->dev.of_node) {
+ ret = mwifiex_pcie_probe_of(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "required compatible string missing\n");
+ goto err_free;
+ }
}
+ ret = mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
+ MWIFIEX_PCIE);
+ if (ret) {
+ pr_err("%s failed\n", __func__);
+ goto err_free;
+ }
return 0;
+
+err_free:
+ kfree(card);
+ return ret;
}
/*
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
index 2a162c3..c8dccf5 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
@@ -2218,7 +2218,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
* The cal-data can be read from device tree and/or
* a configuration file and downloaded to firmware.
*/
- if (priv->adapter->iface_type == MWIFIEX_SDIO &&
+ if ((priv->adapter->iface_type == MWIFIEX_SDIO ||
+ priv->adapter->iface_type == MWIFIEX_PCIE) &&
adapter->dev->of_node) {
adapter->dt_node = adapter->dev->of_node;
if (of_property_read_u32(adapter->dt_node,
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH] cfg80211: add generic helper to check interface is running
From: Arend van Spriel @ 2016-10-20 19:08 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
Adding a helper using wdev to check if interface is running. This
deals with both non-netdev and netdev interfaces. In struct
wireless_dev replacing 'p2p_started' and 'nan_started' by
'is_running' as those are mutual exclusive anyway.
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
include/net/cfg80211.h | 13 +++++++++---
net/wireless/core.c | 8 ++++----
net/wireless/nl80211.c | 54 +++++++++++++++-----------------------------------
3 files changed, 30 insertions(+), 45 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2bbbcc3..0010e5a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3781,8 +3781,8 @@ static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops,
* @beacon_interval: beacon interval used on this device for transmitting
* beacons, 0 when not valid
* @address: The address for this device, valid only if @netdev is %NULL
- * @p2p_started: true if this is a P2P Device that has been started
- * @nan_started: true if this is a NAN interface that has been started
+ * @is_running: true if this is a non-netdev device that has been started, eg.
+ * like the P2P Device.
* @cac_started: true if DFS channel availability check has been started
* @cac_start_time: timestamp (jiffies) when the dfs state was entered.
* @cac_time_ms: CAC time in ms
@@ -3814,7 +3814,7 @@ struct wireless_dev {
struct mutex mtx;
- bool use_4addr, p2p_started, nan_started;
+ bool use_4addr, is_running;
u8 address[ETH_ALEN] __aligned(sizeof(u16));
@@ -3871,6 +3871,13 @@ static inline u8 *wdev_address(struct wireless_dev *wdev)
return wdev->address;
}
+static inline bool wdev_is_running(struct wireless_dev *wdev)
+{
+ if (wdev->netdev)
+ return netif_running(wdev->netdev);
+ return wdev->is_running;
+}
+
/**
* wdev_priv - return wiphy priv from wireless_dev
*
diff --git a/net/wireless/core.c b/net/wireless/core.c
index f433f15..088ba44 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -210,11 +210,11 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
return;
- if (!wdev->p2p_started)
+ if (!wdev_is_running(wdev))
return;
rdev_stop_p2p_device(rdev, wdev);
- wdev->p2p_started = false;
+ wdev->is_running = false;
rdev->opencount--;
@@ -233,11 +233,11 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN))
return;
- if (!wdev->nan_started)
+ if (!wdev_is_running(wdev))
return;
rdev_stop_nan(rdev, wdev);
- wdev->nan_started = false;
+ wdev->is_running = false;
rdev->opencount--;
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fcf5b4f..e37801e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10528,7 +10528,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
return -EOPNOTSUPP;
- if (wdev->p2p_started)
+ if (wdev_is_running(wdev))
return 0;
if (rfkill_blocked(rdev->rfkill))
@@ -10538,7 +10538,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
- wdev->p2p_started = true;
+ wdev->is_running = true;
rdev->opencount++;
return 0;
@@ -10570,7 +10570,7 @@ static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
if (wdev->iftype != NL80211_IFTYPE_NAN)
return -EOPNOTSUPP;
- if (wdev->nan_started)
+ if (!wdev_is_running(wdev))
return -EEXIST;
if (rfkill_blocked(rdev->rfkill))
@@ -10593,7 +10593,7 @@ static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
- wdev->nan_started = true;
+ wdev->is_running = true;
rdev->opencount++;
return 0;
@@ -10678,7 +10678,7 @@ static int nl80211_nan_add_func(struct sk_buff *skb,
if (wdev->iftype != NL80211_IFTYPE_NAN)
return -EOPNOTSUPP;
- if (!wdev->nan_started)
+ if (!wdev_is_running(wdev))
return -ENOTCONN;
if (!info->attrs[NL80211_ATTR_NAN_FUNC])
@@ -10915,7 +10915,7 @@ static int nl80211_nan_del_func(struct sk_buff *skb,
if (wdev->iftype != NL80211_IFTYPE_NAN)
return -EOPNOTSUPP;
- if (!wdev->nan_started)
+ if (!wdev_is_running(wdev))
return -ENOTCONN;
if (!info->attrs[NL80211_ATTR_COOKIE])
@@ -10943,7 +10943,7 @@ static int nl80211_nan_change_config(struct sk_buff *skb,
if (wdev->iftype != NL80211_IFTYPE_NAN)
return -EOPNOTSUPP;
- if (!wdev->nan_started)
+ if (!wdev_is_running(wdev))
return -ENOTCONN;
if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
@@ -11255,11 +11255,7 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
- if (wdev->netdev &&
- !netif_running(wdev->netdev))
- return -ENETDOWN;
- if (!wdev->netdev && !wdev->p2p_started &&
- !wdev->nan_started)
+ if (!wdev_is_running(wdev))
return -ENETDOWN;
}
@@ -11422,10 +11418,7 @@ static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
return -EINVAL;
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
- if (wdev->netdev &&
- !netif_running(wdev->netdev))
- return -ENETDOWN;
- if (!wdev->netdev && !wdev->p2p_started)
+ if (!wdev_is_running(wdev))
return -ENETDOWN;
}
}
@@ -11796,29 +11789,14 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
info->user_ptr[1] = wdev;
}
- if (dev) {
- if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
- !netif_running(dev)) {
- if (rtnl)
- rtnl_unlock();
- return -ENETDOWN;
- }
-
- dev_hold(dev);
- } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) {
- if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
- !wdev->p2p_started) {
- if (rtnl)
- rtnl_unlock();
- return -ENETDOWN;
- }
- if (wdev->iftype == NL80211_IFTYPE_NAN &&
- !wdev->nan_started) {
- if (rtnl)
- rtnl_unlock();
- return -ENETDOWN;
- }
+ if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
+ !wdev_is_running(wdev)) {
+ if (rtnl)
+ rtnl_unlock();
+ return -ENETDOWN;
}
+ if (dev)
+ dev_hold(dev);
info->user_ptr[0] = rdev;
}
--
1.9.1
^ permalink raw reply related
* Re: cfg80211: race problem between suspend and disconnect event
From: Johannes Berg @ 2016-10-20 18:45 UTC (permalink / raw)
To: Amitkumar Karwar
Cc: Kalle Valo, Brian Norris, Nishant Sarmukadam, Cathy Luo,
linux-wireless@vger.kernel.org, Ganapathi Bhat
In-Reply-To: <67400d1c5c2141b3af75bdce9ec43840@SC-EXCH04.marvell.com>
Hi,
> Mwifiex driver rejects del_key() requests from cfg80211 during
> suspend. They came very late when driver's cfg80211_suspend handler
> is already executed and driver is in the middle of SDIO's suspend
> handler.
Interesting. Rejecting those calls is probably perfectly reasonable,
and in fact it's not clear to me why we even try to delete the keys
after we've disconnected - any driver implementation should have
removed them already anyway? You probably don't actually care about the
key removal either?
That said though, there's also the critical protocol stop and the
set_qos_map(NULL) call, which removes the QoS mapping. It doesn't look
like you support this right now in your driver, but in any case it'd be
pretty strange to have that happen after or during suspend.
> Please let us know if you have any suggestions to resolves this with
> cfg80211/driver change.
For cfg80211 we could do something like this:
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -104,13 +104,16 @@ static int wiphy_suspend(struct device *dev)
rtnl_lock();
if (rdev->wiphy.registered) {
- if (!rdev->wiphy.wowlan_config)
+ if (!rdev->wiphy.wowlan_config) {
cfg80211_leave_all(rdev);
+ cfg80211_process_rdev_events(rdev);
+ }
if (rdev->ops->suspend)
ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config);
if (ret == 1) {
/* Driver refuse to configure wowlan */
cfg80211_leave_all(rdev);
+ cfg80211_process_rdev_events(rdev);
ret = rdev_suspend(rdev, NULL);
}
}
However, that assumes that you actually cfg80211_disconnected()
synchronously while being asked to disconnect, which doesn't seem to be
true from looking at mwifiex, if HostCmd_CMD_802_11_DEAUTHENTICATE
command can be sent to the firmware then you wait for EVENT_LINK_LOST,
EVENT_DEAUTHENTICATED or EVENT_DISASSOCIATED to come back from the
firmware, so this cfg80211 change won't help.
So somehow you'd have to synchronize with the firmware as well, to
process all those things before suspend, I guess?
We could then export cfg80211_process_rdev_events() as
cfg80211_process_wiphy_events() or so, so that you can call that at an
appropriate place from your suspend handler, after having synchronized
with the firmware?
johannes
^ permalink raw reply
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