* RE: [ath9k]: Beaconing process in ad-hoc mode
From: Jónatan Muñoz @ 2010-08-06 10:48 UTC (permalink / raw)
To: 'John W. Linville'; +Cc: linux-wireless
In-Reply-To: <20100805134531.GA2779@tuxdriver.com>
Dear John,
Thanks for your help. I am looking in net/mac80211/ibss.c.
I see the ieee80211_rx_mgmt_beacon function but I don't find anything about
beacon tx, or about tsf update. I am still lost.
static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee80211_rx_status *rx_status)
{
size_t baselen;
struct ieee802_11_elems elems;
/* Process beacon from the current BSS */
baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
if (baselen > len)
return;
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
&elems);
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
}
Any tip more, please?
Thank you in advance
John
------------------------------------------
Jónatan Muñoz
Email: jmunoz@umh.es
Ubiquitous Wireless Communications Research Laboratory
Uwicore, http://www.uwicore.umh.es
Signal Theory and Communications Division
University Miguel Hernández of Elche
Avenida de la Universidad s/n
Edificio Quorum V P2 012
03202, Elche (Alicante)
Spain
Tel: +34 96522 2031 /+34 669256708
Fax: +34 96665 8903
------------------------------------------
> -----Mensaje original-----
> De: linux-wireless-owner@vger.kernel.org [mailto:linux-wireless-
> owner@vger.kernel.org] En nombre de John W. Linville
> Enviado el: jueves, 05 de agosto de 2010 15:46
> Para: Jónatan Muñoz
> CC: linux-wireless@vger.kernel.org
> Asunto: Re: [ath9k]: Beaconing process in ad-hoc mode
>
> On Thu, Aug 05, 2010 at 01:55:05PM +0200, Jónatan Muñoz wrote:
> > Dear All,
> >
> > I am working in a project where I need to modified the currently
> beaconing
> > system for adhoc mode in ath9k, what I want to achieve is that each
> station
> > in an adhoc network send periodically a beacon. As I know, when a
> station in
> > the network receives a beacon before sending its own beacon, cancels
> the
> > transmission, updates its hw tsf based on the received beacon and
> waits for
> > a chance to send the beacon during next TBTT.
> >
> > For my goal, I think that I should comment the part where the
> transmission
> > of the beacon is cancelled. In this way, each station will send a
> beacon
> > each 100TU (~100 ms). I know that this mean a increased traffic load
> on the
> > network, but it is so much important for the project to obtain a
> beacon for
> > each station each 100ms.
> >
> > Right now, I am looking at the source code of ath9k, I am trying to
> modify
> > the file beacon.c, but I dont find the way to get my purpose. Could
> anyone
> > help me to find the right place at the code that I have to modify? I
> am a
> > bit lost and any help would be greatly appreciated.
> >
> > Thanks in advance.
> >
> > PD: Please excuse my poor English
> >
> > John
>
> I think you should be looking in net/mac80211/ibss.c.
>
> Hth!
>
> John
> --
> John W. Linville Someday the world will need a hero, and you
> linville@tuxdriver.com might be all we have. Be
ready.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-
> wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 3/8] iwlwifi: separate thermal throttling function
From: Johannes Berg @ 2010-08-06 13:14 UTC (permalink / raw)
To: Wey-Yi Guy; +Cc: linville, linux-wireless, ipw3945-devel
In-Reply-To: <1280590452-10655-4-git-send-email-wey-yi.w.guy@intel.com>
> @@ -325,9 +283,15 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
> else if (priv->cfg->supports_idle &&
> priv->hw->conf.flags & IEEE80211_CONF_IDLE)
> iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
> - else if (tt->state >= IWL_TI_1)
> - iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
> - else if (!enabled)
> + else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
> + priv->cfg->ops->lib->tt_ops.tt_power_mode) {
> + if (priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
> + /* in thermal throttling low power state */
> + iwl_static_sleep_cmd(priv, &cmd,
> + priv->cfg->ops->lib->tt_ops.tt_power_mode(priv),
> + dtimper);
> + }
> + } else if (!enabled)
> iwl_power_sleep_cam_cmd(priv, &cmd);
> else if (priv->power_data.debug_sleep_level_override >= 0)
> iwl_static_sleep_cmd(priv, &cmd,
This is very very broken because it adds an often-used code path that
will not initialise "cmd" at all. It needs to be
...
else if (priv->...lower_power_detection &&
priv->...tt_power_mode &&
priv->...lower_power_detection(priv))
iwl_static_sleep_cmd(...)
else if (!enabled)
...
johannes
^ permalink raw reply
* Re: Odd BUG on wireless-testing master-2010-08-05
From: John W. Linville @ 2010-08-06 13:50 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linux-wireless
In-Reply-To: <AANLkTinwbLXVHmC9eUczoe-ntT=adyFFx6C6Q=GcBc79@mail.gmail.com>
On Thu, Aug 05, 2010 at 03:31:06PM -0700, Luis R. Rodriguez wrote:
> I just ran into this. My first load of master-2010-08-05 was fine but
> I started getting a lot of disconnects on AR9003 hardware after a
> period of RX'ing data over an encrypted legacy network. Instead of
> checking dmesg I just rebooted though. After that I connected to the
> same AP again, started Rx'ing for a while and then shortly got this:
>
>
> [ 818.749585] BUG: unable to handle kernel paging request at 00003f3f00000000
> [ 818.749594] IP: [<ffffffff814ee0d8>] unix_stream_recvmsg+0x3f8/0x790
> After a reboot I got a hard hang which I could not capture any logs
> for. I rebooted and am up now but not seeing these issues yet. John,
> does this smell like what you were seeing or is this different?
Yeah, I'm seeing that too. There is some netdev stuff in
wireless-testing at the moment that I suspect was undercooked...
Sorry for the inconvenience while this gets sorted-out!
John
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
^ permalink raw reply
* [PATCH 2.6.36] iwlwifi: fix TX tracer
From: Johannes Berg @ 2010-08-06 14:00 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Wey-Yi W Guy, Zhao, Shanyu
From: Johannes Berg <johannes.berg@intel.com>
The TX tracing code copies with the wrong length,
which will typically copy too little data. Fix
this by using the correct length variable.
Cc: stable@kernel.org [2.6.32+]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
drivers/net/wireless/iwlwifi/iwl-devtrace.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-devtrace.h 2010-08-06 15:58:10.000000000 +0200
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-devtrace.h 2010-08-06 15:58:20.000000000 +0200
@@ -193,7 +193,7 @@ TRACE_EVENT(iwlwifi_dev_tx,
__entry->framelen = buf0_len + buf1_len;
memcpy(__get_dynamic_array(tfd), tfd, tfdlen);
memcpy(__get_dynamic_array(buf0), buf0, buf0_len);
- memcpy(__get_dynamic_array(buf1), buf1, buf0_len);
+ memcpy(__get_dynamic_array(buf1), buf1, buf1_len);
),
TP_printk("[%p] TX %.2x (%zu bytes)",
__entry->priv,
^ permalink raw reply
* [PATCH 2.6.36] iwlwifi: fix locking assertions
From: Johannes Berg @ 2010-08-06 14:17 UTC (permalink / raw)
To: John Linville; +Cc: Thomas Meyer, linux-wireless, Wey-Yi W Guy, Zhao, Shanyu
From: Johannes Berg <johannes.berg@intel.com>
spin_is_locked() can return zero on some (UP?)
configurations because locks don't exist, and
that causes an endless amount of warnings. Use
lockdep_assert_held() instead, which has two
advantages:
1) it verifies the current task is holding
the lock or mutex
2) it compiles away completely when lockdep
is not enabled
Cc: stable@kernel.org [2.6.34+, maybe only parts of patch]
Reported-by: Thomas Meyer <thomas@m3y3r.de>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-scan.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-sta.c | 6 +++---
4 files changed, 6 insertions(+), 6 deletions(-)
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-agn-lib.c 2010-07-27 09:50:28.000000000 +0200
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-agn-lib.c 2010-08-06 16:12:24.000000000 +0200
@@ -1429,7 +1429,7 @@ int iwlagn_manage_ibss_station(struct iw
void iwl_free_tfds_in_queue(struct iwl_priv *priv,
int sta_id, int tid, int freed)
{
- WARN_ON(!spin_is_locked(&priv->sta_lock));
+ lockdep_assert_held(&priv->sta_lock);
if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-agn-tx.c 2010-08-05 23:30:25.000000000 +0200
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-agn-tx.c 2010-08-06 16:12:24.000000000 +0200
@@ -1117,7 +1117,7 @@ int iwlagn_txq_check_empty(struct iwl_pr
u8 *addr = priv->stations[sta_id].sta.sta.addr;
struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
- WARN_ON(!spin_is_locked(&priv->sta_lock));
+ lockdep_assert_held(&priv->sta_lock);
switch (priv->stations[sta_id].tid[tid].agg.state) {
case IWL_EMPTYING_HW_QUEUE_DELBA:
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-scan.c 2010-07-30 08:43:30.000000000 +0200
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-scan.c 2010-08-06 16:12:24.000000000 +0200
@@ -298,7 +298,7 @@ EXPORT_SYMBOL(iwl_init_scan_params);
static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
- WARN_ON(!mutex_is_locked(&priv->mutex));
+ lockdep_assert_held(&priv->mutex);
IWL_DEBUG_INFO(priv, "Starting scan...\n");
set_bit(STATUS_SCANNING, &priv->status);
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-sta.c 2010-08-05 23:30:25.000000000 +0200
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-sta.c 2010-08-06 16:12:24.000000000 +0200
@@ -773,7 +773,7 @@ static int iwl_send_static_wepkey_cmd(st
int iwl_restore_default_wep_keys(struct iwl_priv *priv)
{
- WARN_ON(!mutex_is_locked(&priv->mutex));
+ lockdep_assert_held(&priv->mutex);
return iwl_send_static_wepkey_cmd(priv, 0);
}
@@ -784,7 +784,7 @@ int iwl_remove_default_wep_key(struct iw
{
int ret;
- WARN_ON(!mutex_is_locked(&priv->mutex));
+ lockdep_assert_held(&priv->mutex);
IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
keyconf->keyidx);
@@ -808,7 +808,7 @@ int iwl_set_default_wep_key(struct iwl_p
{
int ret;
- WARN_ON(!mutex_is_locked(&priv->mutex));
+ lockdep_assert_held(&priv->mutex);
if (keyconf->keylen != WEP_KEY_LEN_128 &&
keyconf->keylen != WEP_KEY_LEN_64) {
^ permalink raw reply
* Re: [PATCH v2 03/20] mmc: support embedded data field in mmc_host
From: Russell King - ARM Linux @ 2010-08-06 14:46 UTC (permalink / raw)
To: Ohad Ben-Cohen
Cc: Linus Walleij, Vitaly Wool, Kalle Valo, Pandita Vikram,
Nicolas Pitre, Tony Lindgren, linux-wireless, Roger Quadros,
linux-mmc, San Mehat, Chikkature Rajashekar Madhusudhan,
Luciano Coelho, linux-omap, akpm, linux-arm-kernel, Ido Yariv
In-Reply-To: <AANLkTim6Yuor4CAEmQPs3zPVz1svEbckzO0HHeFWGmjy@mail.gmail.com>
On Fri, Aug 06, 2010 at 01:02:24PM +0300, Ohad Ben-Cohen wrote:
> We have Russell's suggestion which is nice and simple, but it has the
> 1 device limitation.
You could make it generic by doing something like this:
#define set_device_data(name, type, index, data) \
({ \
extern void __set_device_data(const char *, int, void *, size_t); \
BUILD_BUG_ON(!__same_type(type, *data)); \
__set_device_data(name ":" #type, index, data, sizeof(type)); \
})
#define get_device_data(name, type, index) ({ \
extern void *__get_device_data(const char *, int); \
type *__ptr = __get_device_data(name ":" #type, index); \
__ptr; })
And now we have something that takes a string and index to use as a lookup
key in some kind of list - and it's typesafe (because the lookup key is
dependent on the stringified type.)
But... at this point I feel that we're getting too complicated, and will
get shouted at to use something like DT which already solves this problem.
^ permalink raw reply
* Re: [PATCH 3/8] iwlwifi: separate thermal throttling function
From: Guy, Wey-Yi @ 2010-08-06 14:51 UTC (permalink / raw)
To: linville@tuxdriver.com
Cc: Johannes Berg, linux-wireless@vger.kernel.org,
ipw3945-devel@lists.sourceforge.net
In-Reply-To: <1281100480.3853.424.camel@jlt3.sipsolutions.net>
Hi Johannes,
Thanks very much to catch this bug.
John, please do not take the "thermal throttling" patch, I will fix it
up and re-submit.
Thanks
On Fri, 2010-08-06 at 06:14 -0700, Johannes Berg wrote:
> > @@ -325,9 +283,15 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
> > else if (priv->cfg->supports_idle &&
> > priv->hw->conf.flags & IEEE80211_CONF_IDLE)
> > iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
> > - else if (tt->state >= IWL_TI_1)
> > - iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
> > - else if (!enabled)
> > + else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
> > + priv->cfg->ops->lib->tt_ops.tt_power_mode) {
> > + if (priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
> > + /* in thermal throttling low power state */
> > + iwl_static_sleep_cmd(priv, &cmd,
> > + priv->cfg->ops->lib->tt_ops.tt_power_mode(priv),
> > + dtimper);
> > + }
> > + } else if (!enabled)
> > iwl_power_sleep_cam_cmd(priv, &cmd);
> > else if (priv->power_data.debug_sleep_level_override >= 0)
> > iwl_static_sleep_cmd(priv, &cmd,
>
> This is very very broken because it adds an often-used code path that
> will not initialise "cmd" at all. It needs to be
>
> ...
> else if (priv->...lower_power_detection &&
> priv->...tt_power_mode &&
> priv->...lower_power_detection(priv))
> iwl_static_sleep_cmd(...)
> else if (!enabled)
> ...
>
> johannes
>
^ permalink raw reply
* Re: [PATCH 2.6.36] iwlwifi: fix locking assertions
From: Thomas Meyer @ 2010-08-06 15:12 UTC (permalink / raw)
To: Johannes Berg; +Cc: John Linville, linux-wireless, Wey-Yi W Guy, Zhao, Shanyu
In-Reply-To: <1281104273.3853.504.camel@jlt3.sipsolutions.net>
On Friday 06 August 2010 16:17:53 Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> spin_is_locked() can return zero on some (UP?)
Yes, this is an UP config.
> configurations because locks don't exist, and
> that causes an endless amount of warnings. Use
> lockdep_assert_held() instead, which has two
> advantages:
> 1) it verifies the current task is holding
> the lock or mutex
> 2) it compiles away completely when lockdep
> is not enabled
>
After applying your patch the warnings in the kernel log are gone.
Thanks for the quick fix.
kind regards
thomas
^ permalink raw reply
* Re: Interesting development regarding b43 DMA ERROR
From: Rafał Miłecki @ 2010-08-06 16:31 UTC (permalink / raw)
To: Larry Finger; +Cc: b43-dev, wireless
In-Reply-To: <4C5B27BE.8010708@lwfinger.net>
2010/8/5 Larry Finger <Larry.Finger@lwfinger.net>:
> Yesterday, I had to go back to kernel 2.6.34 for a test of code to avoid ssb
> load freezeups on my HP Mini 110 Netbook, which has the SPROM at offset 0x0800,
> not 0x1000. As I had been using b43 for this BCM4312 (14e4:4315) card in DMA
> mode without any problems, I was quite surprised to see the dreaded DMA errors.
> I had attributed the lack of errors with wireless testing to be due to the AMI,
> not Phoenix, BIOS in this machine. When I switched to mainline ('git describe'
> reports it as v2.6.35-3370-gcdd854b), again it works.
>
> AFAIK, none of any fixes that were put into wt to try to solve this problem had
> any affect, yet the device now works here.
>
> Is anyone else that had/has the DMA problem running 2.6.35 + updates from the
> linux-2.6.git tree? If so, does your BCM4312 now work with b43, or is my box
> special?
Interesting. It means some patch that gone mainline fixed it and it
was submitted using other tree than w-t, right?
Would you care to bisect this?
--
Rafał
^ permalink raw reply
* Re: [PATCH v2 03/20] mmc: support embedded data field in mmc_host
From: Nicolas Pitre @ 2010-08-06 16:53 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: Ohad Ben-Cohen, Linus Walleij, Vitaly Wool, Kalle Valo,
Pandita Vikram, Tony Lindgren, linux-wireless, Roger Quadros,
linux-mmc, San Mehat, Chikkature Rajashekar Madhusudhan,
Luciano Coelho, linux-omap, akpm, linux-arm-kernel, Ido Yariv
In-Reply-To: <20100806144605.GA21015@n2100.arm.linux.org.uk>
On Fri, 6 Aug 2010, Russell King - ARM Linux wrote:
> On Fri, Aug 06, 2010 at 01:02:24PM +0300, Ohad Ben-Cohen wrote:
> > We have Russell's suggestion which is nice and simple, but it has the
> > 1 device limitation.
>
> You could make it generic by doing something like this:
>
> #define set_device_data(name, type, index, data) \
> ({ \
> extern void __set_device_data(const char *, int, void *, size_t); \
> BUILD_BUG_ON(!__same_type(type, *data)); \
> __set_device_data(name ":" #type, index, data, sizeof(type)); \
> })
>
> #define get_device_data(name, type, index) ({ \
> extern void *__get_device_data(const char *, int); \
> type *__ptr = __get_device_data(name ":" #type, index); \
> __ptr; })
>
> And now we have something that takes a string and index to use as a lookup
> key in some kind of list - and it's typesafe (because the lookup key is
> dependent on the stringified type.)
>
> But... at this point I feel that we're getting too complicated, and will
> get shouted at to use something like DT which already solves this problem.
DT is not generally available yet. A simple interim solution would
still be worth it.
Nicolas
^ permalink raw reply
* Re: Interesting development regarding b43 DMA ERROR
From: Larry Finger @ 2010-08-06 17:37 UTC (permalink / raw)
To: Rafał Miłecki; +Cc: b43-dev, wireless
In-Reply-To: <AANLkTi=-Jc9XjD-gqwtUyUnM768wvv3GzzwhJNtkwYKK@mail.gmail.com>
On 08/06/2010 11:31 AM, Rafał Miłecki wrote:
>
> Interesting. It means some patch that gone mainline fixed it and it
> was submitted using other tree than w-t, right?
>
> Would you care to bisect this?
It won't be fun as this is a 1.6 GHz Atom and a kernel build is quite slow. In
addition, this one has the relocated SPROM that requires patching to be able to
boot. In the interests of the community, I will do it.
Larry
^ permalink raw reply
* Multiple station interfaces with one wifi card
From: Hakan Coskun @ 2010-08-06 18:47 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <7CE373CC-7FCB-41A0-AC81-06E9893D8BC8@cs.tu-berlin.de>
Hi,
we are doing research in order to study the behaviour of virtual wifi interfaces with channel switching. After a simulative study, we started to perform some real world experiments with ath9k, which is able to run multiple wiphys on top of a card. This is working quite good. Of course there are several restrictions and performance problems, we are working on some scheduling algorithms to improve the operation.
But now to take it a step further, we plan to go for a mac80211 based virtualization, meaning to run multiple vifs in parallel in station mode. The first step is to run them on the same channel, but as expected this is not working, yet. We can create several interfaces with iw, there is no problem. Even scanning is working, but as soon as we want to connect to an open AP we get into trouble. Authentication and association are not working.
mac80211 needs to be extended with additional functionality like ath9k, to cope with multiple associations and channel switching, etc.. The internals of ath9k are clear to us, since the virtualization code is not big, and the patches well documented. We want to adapt them to mac80211, in order allow vifs to connect to APs simultaneously.
How can we track the sequence of operations during the runtime in order to get a better understanding of the mac80211. At the moment, we enabled tracing and debug messages for mac80211, this helps but is not sufficient to follow the functions step by step. We can put a lot of debugging messages into the files, but are there any "best practices" we should follow.
Thanks,
Hakan
^ permalink raw reply
* Re: [ath9k-devel] Multiple interfaces with one card
From: Luis R. Rodriguez @ 2010-08-06 18:48 UTC (permalink / raw)
To: Hakan Coskun; +Cc: ath9k-devel@lists.ath9k.org, linux-wireless
In-Reply-To: <F980642C-09A1-41C9-95D2-ABA6C7ED3F98@cs.tu-berlin.de>
On Fri, Aug 06, 2010 at 03:32:20AM -0700, Hakan Coskun wrote:
> Hi,
>
> we are doing research in order to study the behaviour of virtual wifi interfaces with channel switching. After a simulative study, we started to perform some real world experiments with ath9k. Running multiple wiphys on top of a card is working quite good. Of course there are several restrictions and performance problems, we are working on some scheduling algorithms to improve the operation.
> But now to take it a step further, we plan to go for a mac80211 based virtualization, meaning to run multiple vifs in parallel in station mode. The first step is to run them on the same channel, but as expected this is not working. We can create several interfaces with iw, there is no problem. Even scanning is working, but as soon as we want to connect to an open AP we get into trouble. The authentication is not working.
>
> Sure, the mac80211 needs some additional functionality like ath9k, to cope with multiple associations and channel switching, etc.. How can we track the sequence of operations during the runtime in order to get a better understanding of the mac80211. At the moment, we enabled tracing and debug messages for mac80211, this helps but is not sufficient to follow the functions step by step. We can put a lot of debugging messages into the files, but are there any "best practices" we should follow.
>
Hakan, I recommend you use the linux-wireless mailing list for this
and also always use wireless-testing.git for your development.
Can you post patches of what you have done to mac80211 / cfg80211?
Luis
^ permalink raw reply
* [PATCH 0/7] rt2x00 update
From: Ivo van Doorn @ 2010-08-06 18:45 UTC (permalink / raw)
To: John W. Linville; +Cc: users, linux-wireless
Hi John,
Here is a fresh update for rt2x00 for 2.6.37, most notable
change is the move of TX/RX handling to a workqueue, but
more importantly the more accurate TX status reporting
for rt2800usb
Helmut Schaa (2):
rt2x00: Set MIMO PS flag in tx descriptor for STAs in dynamic SMPS mode
rt2x00: Update comments regarding TXWI and TX_STA_FIFO
Ivo van Doorn (5):
rt2x00: Move USB tx/rx done handling to workqueue
rt2x00: Add helper function for reporting tx status
rt2x00: Request TXWI pointer from driver
rt2x00: Implement TX status reporting for rt2800usb
rt2x00: Remove ieee80211_rx_status from rt2x00_dev
Ivo
^ permalink raw reply
* [PATCH 1/7] rt2x00: Move USB tx/rx done handling to workqueue
From: Ivo van Doorn @ 2010-08-06 18:45 UTC (permalink / raw)
To: John W. Linville; +Cc: users, linux-wireless
In-Reply-To: <201008062045.05288.IvDoorn@gmail.com>
Move all TX and RX completion handling into a work structure,
which is handeled on the mac80211 workqueue. This simplifies
the code in rt2x00lib since it no longer needs to check if the
device is USB or PCI to decide which mac80211 function should be used.
In the watchdog some changes are needed since it can no longer rely
on the TX completion function to be run while looping through the
entries. (Both functions now work on the same workqueue, so this
would deadlock). So the watchdog now waits for the URB to return,
and handle the TX status report directly.
As a side-effect, the debugfs entry for the RX queue now correctly
displays the positions of the INDEX and INDEX_DONE counters. This
also implies that it is not possible to perform checks like queue_empty()
and queue_full() on the RX queue.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt2x00.h | 9 ++-
drivers/net/wireless/rt2x00/rt2x00dev.c | 35 +++-----
drivers/net/wireless/rt2x00/rt2x00queue.c | 7 +-
drivers/net/wireless/rt2x00/rt2x00queue.h | 6 +-
drivers/net/wireless/rt2x00/rt2x00usb.c | 133 +++++++++++++++++++++--------
5 files changed, 128 insertions(+), 62 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index c21af38..5276c19 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
@@ -862,6 +863,12 @@ struct rt2x00_dev {
*/
struct work_struct intf_work;
+ /**
+ * Scheduled work for TX/RX done handling (USB devices)
+ */
+ struct work_struct rxdone_work;
+ struct work_struct txdone_work;
+
/*
* Data queue arrays for RX, TX and Beacon.
* The Beacon array also contains the Atim queue
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 585e816..94621bd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@@ -383,15 +384,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* send the status report back.
*/
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
- /*
- * Only PCI and SOC devices process the tx status in process
- * context. Hence use ieee80211_tx_status for PCI and SOC
- * devices and stick to ieee80211_tx_status_irqsafe for USB.
- */
- if (rt2x00_is_usb(rt2x00dev))
- ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
- else
- ieee80211_tx_status(rt2x00dev->hw, entry->skb);
+ ieee80211_tx_status(rt2x00dev->hw, entry->skb);
else
dev_kfree_skb_any(entry->skb);
@@ -403,7 +396,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00dev->ops->lib->clear_entry(entry);
- clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
/*
@@ -463,6 +455,10 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
unsigned int header_length;
int rate_idx;
+
+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+ goto submit_entry;
+
/*
* Allocate a new sk_buffer. If no new buffer available, drop the
* received frame and reuse the existing buffer.
@@ -540,26 +536,17 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
-
- /*
- * Currently only PCI and SOC devices handle rx interrupts in process
- * context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni
- * for PCI and SOC devices.
- */
- if (rt2x00_is_usb(rt2x00dev))
- ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
- else
- ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
+ ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
/*
* Replace the skb with the freshly allocated one.
*/
entry->skb = skb;
- entry->flags = 0;
+submit_entry:
rt2x00dev->ops->lib->clear_entry(entry);
-
rt2x00queue_index_inc(entry->queue, Q_INDEX);
+ rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
@@ -1017,6 +1004,8 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
* Stop all work.
*/
cancel_work_sync(&rt2x00dev->intf_work);
+ cancel_work_sync(&rt2x00dev->rxdone_work);
+ cancel_work_sync(&rt2x00dev->txdone_work);
/*
* Uninitialize device.
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index a3401d3..1822095 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
@@ -730,9 +731,9 @@ void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00queue_reset(queue);
for (i = 0; i < queue->limit; i++) {
- queue->entries[i].flags = 0;
-
rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
+ if (queue->qid == QID_RX)
+ rt2x00queue_index_inc(queue, Q_INDEX);
}
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 191e777..38b47919 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@@ -363,12 +363,16 @@ struct txentry_desc {
* the device has signaled it is done with it.
* @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting
* for the signal to start sending.
+ * @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured
+ * while transfering the data to the hardware. No TX status report will
+ * be expected from the hardware.
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_OWNER_DEVICE_DATA,
ENTRY_OWNER_DEVICE_CRYPTO,
ENTRY_DATA_PENDING,
+ ENTRY_DATA_IO_FAILED
};
/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index ff3a366..3f13101 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@@ -167,19 +168,12 @@ EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
/*
* TX data handlers.
*/
-static void rt2x00usb_interrupt_txdone(struct urb *urb)
+static void rt2x00usb_work_txdone_entry(struct queue_entry *entry)
{
- struct queue_entry *entry = (struct queue_entry *)urb->context;
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct txdone_entry_desc txdesc;
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
- !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
- return;
-
/*
- * Obtain the status about this packet.
- * Note that when the status is 0 it does not mean the
+ * If the transfer to hardware succeeded, it does not mean the
* frame was send out correctly. It only means the frame
* was succesfully pushed to the hardware, we have no
* way to determine the transmission status right now.
@@ -187,15 +181,56 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
* in the register).
*/
txdesc.flags = 0;
- if (!urb->status)
- __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
- else
+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
__set_bit(TXDONE_FAILURE, &txdesc.flags);
+ else
+ __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
txdesc.retry = 0;
rt2x00lib_txdone(entry, &txdesc);
}
+static void rt2x00usb_work_txdone(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, txdone_work);
+ struct data_queue *queue;
+ struct queue_entry *entry;
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ while (!rt2x00queue_empty(queue)) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ break;
+
+ rt2x00usb_work_txdone_entry(entry);
+ }
+ }
+}
+
+static void rt2x00usb_interrupt_txdone(struct urb *urb)
+{
+ struct queue_entry *entry = (struct queue_entry *)urb->context;
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
+ !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ return;
+
+ /*
+ * Check if the frame was correctly uploaded
+ */
+ if (urb->status)
+ __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+
+ /*
+ * Schedule the delayed work for reading the TX status
+ * from the device.
+ */
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
+}
+
static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -294,6 +329,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
{
+ struct queue_entry *entry;
struct queue_entry_priv_usb *entry_priv;
unsigned short threshold = queue->threshold;
@@ -313,14 +349,22 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
* Reset all currently uploaded TX frames.
*/
while (!rt2x00queue_empty(queue)) {
- entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data;
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ entry_priv = entry->priv_data;
usb_kill_urb(entry_priv->urb);
/*
* We need a short delay here to wait for
- * the URB to be canceled and invoked the tx_done handler.
+ * the URB to be canceled
*/
- udelay(200);
+ do {
+ udelay(100);
+ } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags));
+
+ /*
+ * Invoke the TX done handler
+ */
+ rt2x00usb_work_txdone_entry(entry);
}
/*
@@ -345,15 +389,41 @@ EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
/*
* RX data handlers.
*/
+static void rt2x00usb_work_rxdone(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, rxdone_work);
+ struct queue_entry *entry;
+ struct skb_frame_desc *skbdesc;
+ u8 rxd[32];
+
+ while (!rt2x00queue_empty(rt2x00dev->rx)) {
+ entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);
+
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ break;
+
+ /*
+ * Fill in desc fields of the skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(entry->skb);
+ skbdesc->desc = rxd;
+ skbdesc->desc_len = entry->queue->desc_size;
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(rt2x00dev, entry);
+ }
+}
+
static void rt2x00usb_interrupt_rxdone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- u8 rxd[32];
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
- !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
/*
@@ -361,22 +431,14 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
* to be actually valid, or if the urb is signaling
* a problem.
*/
- if (urb->actual_length < entry->queue->desc_size || urb->status) {
- set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- usb_submit_urb(urb, GFP_ATOMIC);
- return;
- }
-
- /*
- * Fill in desc fields of the skb descriptor
- */
- skbdesc->desc = rxd;
- skbdesc->desc_len = entry->queue->desc_size;
+ if (urb->actual_length < entry->queue->desc_size || urb->status)
+ __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
/*
- * Send the frame to rt2x00lib for further processing.
+ * Schedule the delayed work for reading the RX status
+ * from the device.
*/
- rt2x00lib_rxdone(rt2x00dev, entry);
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
}
/*
@@ -405,6 +467,8 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
int pipe;
+ entry->flags = 0;
+
if (entry->queue->qid == QID_RX) {
pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
@@ -413,8 +477,6 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
- } else {
- entry->flags = 0;
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
@@ -659,6 +721,9 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
+ INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
+ INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);
+
retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;
--
1.7.2
^ permalink raw reply related
* [PATCH 2/7] rt2x00: Set MIMO PS flag in tx descriptor for STAs in dynamic SMPS mode
From: Ivo van Doorn @ 2010-08-06 18:46 UTC (permalink / raw)
To: John W. Linville; +Cc: users, linux-wireless
In-Reply-To: <201008062045.39547.IvDoorn@gmail.com>
Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt2800lib.c | 3 ++-
drivers/net/wireless/rt2x00/rt2x00ht.c | 10 ++++++++++
drivers/net/wireless/rt2x00/rt2x00queue.h | 2 ++
3 files changed, 14 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index b66e0fd..833b157 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -437,7 +437,8 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
rt2x00_desc_read(txwi, 0, &word);
rt2x00_set_field32(&word, TXWI_W0_FRAG,
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
- rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
+ rt2x00_set_field32(&word, TXWI_W0_MIMO_PS,
+ test_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
rt2x00_set_field32(&word, TXWI_W0_TS,
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
index c004cd3..ad3c7ff 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ b/drivers/net/wireless/rt2x00/rt2x00ht.c
@@ -54,6 +54,16 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
*/
if (txrate->flags & IEEE80211_TX_RC_MCS) {
txdesc->mcs = txrate->idx;
+
+ /*
+ * MIMO PS should be set to 1 for STA's using dynamic SM PS
+ * when using more then one tx stream (>MCS7).
+ */
+ if (tx_info->control.sta && txdesc->mcs > 7 &&
+ (tx_info->control.sta->ht_cap.cap &
+ (WLAN_HT_CAP_SM_PS_DYNAMIC <<
+ IEEE80211_HT_CAP_SM_PS_SHIFT)))
+ __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
} else {
txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 38b47919..2d3bf84 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -268,6 +268,7 @@ struct txdone_entry_desc {
* @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU.
* @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth.
* @ENTRY_TXD_HT_SHORT_GI: Use short GI.
+ * @ENTRY_TXD_HT_MIMO_PS: The receiving STA is in dynamic SM PS mode.
*/
enum txentry_desc_flags {
ENTRY_TXD_RTS_FRAME,
@@ -286,6 +287,7 @@ enum txentry_desc_flags {
ENTRY_TXD_HT_AMPDU,
ENTRY_TXD_HT_BW_40,
ENTRY_TXD_HT_SHORT_GI,
+ ENTRY_TXD_HT_MIMO_PS,
};
/**
--
1.7.2
^ permalink raw reply related
* [PATCH 3/7] rt2x00: Add helper function for reporting tx status
From: Ivo van Doorn @ 2010-08-06 18:46 UTC (permalink / raw)
To: John W. Linville; +Cc: users, linux-wireless
In-Reply-To: <201008062046.19946.IvDoorn@gmail.com>
At some points, some drivers can't report the full TX status
information. This can happen for the UNKNOWN state, or the
FAILURE state (in case the URB failed).
Add a wrapper function to simplify reporting the
empty TX information.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Helmut Schaa <helmut.schaa@googlemail.com>
---
drivers/net/wireless/rt2x00/rt2x00.h | 1 +
drivers/net/wireless/rt2x00/rt2x00dev.c | 12 ++++++++++++
drivers/net/wireless/rt2x00/rt2x00usb.c | 10 ++--------
drivers/net/wireless/rt2x00/rt61pci.c | 6 +-----
4 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 5276c19..edfc2b7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -1078,6 +1078,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
+void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status);
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 94621bd..6499cc4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -408,6 +408,18 @@ void rt2x00lib_txdone(struct queue_entry *entry,
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
+void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status)
+{
+ struct txdone_entry_desc txdesc;
+
+ txdesc.flags = 0;
+ __set_bit(status, &txdesc.flags);
+ txdesc.retry = 0;
+
+ rt2x00lib_txdone(entry, &txdesc);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo);
+
static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 3f13101..f76014f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -170,8 +170,6 @@ EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
*/
static void rt2x00usb_work_txdone_entry(struct queue_entry *entry)
{
- struct txdone_entry_desc txdesc;
-
/*
* If the transfer to hardware succeeded, it does not mean the
* frame was send out correctly. It only means the frame
@@ -180,14 +178,10 @@ static void rt2x00usb_work_txdone_entry(struct queue_entry *entry)
* (Only indirectly by looking at the failed TX counters
* in the register).
*/
- txdesc.flags = 0;
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
- __set_bit(TXDONE_FAILURE, &txdesc.flags);
+ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
else
- __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
- txdesc.retry = 0;
-
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
}
static void rt2x00usb_work_txdone(struct work_struct *work)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index e539c6c..dc6f3eb 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2107,11 +2107,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
"TX status report missed for entry %d\n",
entry_done->entry_idx);
- txdesc.flags = 0;
- __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
- txdesc.retry = 0;
-
- rt2x00lib_txdone(entry_done, &txdesc);
+ rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
}
--
1.7.2
^ permalink raw reply related
* [PATCH 4/7] rt2x00: Request TXWI pointer from driver
From: Ivo van Doorn @ 2010-08-06 18:47 UTC (permalink / raw)
To: John W. Linville; +Cc: users, linux-wireless
In-Reply-To: <201008062046.54483.IvDoorn@gmail.com>
The only reason why the write_tx_data callback function
is needed inside the driver, is because the location of
the TXWI descriptor is different on PCI and USB hardware.
Except for the beacon, where the TXWI is always at the
start of the SKB buffer.
In both cases the drivers write_tx_data function only
wrap around the function rt2800_write_txwi. Move write_tx_data
completely into the rt2800lib library, and add a callback
function to obtain the TXWI pointer.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Helmut Schaa <helmut.schaa@googlemail.com>
---
drivers/net/wireless/rt2x00/rt2800lib.c | 8 +++++---
drivers/net/wireless/rt2x00/rt2800lib.h | 11 ++++++++++-
drivers/net/wireless/rt2x00/rt2800pci.c | 11 ++++-------
drivers/net/wireless/rt2x00/rt2800usb.c | 14 +++++++-------
4 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 833b157..6f1eb58 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -427,8 +427,10 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2800_load_firmware);
-void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
+void rt2800_write_tx_data(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
+ __le32 *txwi = rt2800_drv_get_txwi(entry);
u32 word;
/*
@@ -479,7 +481,7 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
_rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
_rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
}
-EXPORT_SYMBOL_GPL(rt2800_write_txwi);
+EXPORT_SYMBOL_GPL(rt2800_write_tx_data);
static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
{
@@ -601,7 +603,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
/*
* Add the TXWI for the beacon to the skb.
*/
- rt2800_write_txwi((__le32 *)entry->skb->data, txdesc);
+ rt2800_write_tx_data(entry, txdesc);
/*
* Dump beacon to userspace through debugfs.
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 091641e..8f97518 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -44,6 +44,7 @@ struct rt2800_ops {
int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
+ __le32 *(*drv_get_txwi)(struct queue_entry *entry);
};
static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
@@ -126,6 +127,13 @@ static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev)
return rt2800ops->drv_init_registers(rt2x00dev);
}
+static inline __le32 *rt2800_drv_get_txwi(struct queue_entry *entry)
+{
+ const struct rt2800_ops *rt2800ops = entry->queue->rt2x00dev->ops->drv;
+
+ return rt2800ops->drv_get_txwi(entry);
+}
+
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
@@ -135,7 +143,8 @@ int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
const u8 *data, const size_t len);
-void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
+void rt2800_write_tx_data(struct queue_entry *entry,
+ struct txentry_desc *txdesc);
void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 39b3846..f415f6d 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -566,15 +566,11 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static void rt2800pci_write_tx_data(struct queue_entry* entry,
- struct txentry_desc *txdesc)
+static __le32 *rt2800pci_get_txwi(struct queue_entry *entry)
{
- __le32 *txwi = (__le32 *) entry->skb->data;
-
- rt2800_write_txwi(txwi, txdesc);
+ return (__le32 *) entry->skb->data;
}
-
static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct txentry_desc *txdesc)
@@ -1011,6 +1007,7 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
.regbusy_read = rt2x00pci_regbusy_read,
.drv_write_firmware = rt2800pci_write_firmware,
.drv_init_registers = rt2800pci_init_registers,
+ .drv_get_txwi = rt2800pci_get_txwi,
};
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
@@ -1030,7 +1027,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.write_tx_desc = rt2800pci_write_tx_desc,
- .write_tx_data = rt2800pci_write_tx_data,
+ .write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
.kick_tx_queue = rt2800pci_kick_tx_queue,
.kill_tx_queue = rt2800pci_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 5a2dfe8..9084b9a 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -320,15 +320,14 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static void rt2800usb_write_tx_data(struct queue_entry* entry,
- struct txentry_desc *txdesc)
+static __le32 *rt2800usb_get_txwi(struct queue_entry *entry)
{
- __le32 *txwi = (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
-
- rt2800_write_txwi(txwi, txdesc);
+ if (entry->queue->qid == QID_BEACON)
+ return (__le32 *) (entry->skb->data);
+ else
+ return (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
}
-
static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct txentry_desc *txdesc)
@@ -549,6 +548,7 @@ static const struct rt2800_ops rt2800usb_rt2800_ops = {
.regbusy_read = rt2x00usb_regbusy_read,
.drv_write_firmware = rt2800usb_write_firmware,
.drv_init_registers = rt2800usb_init_registers,
+ .drv_get_txwi = rt2800usb_get_txwi,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
@@ -566,7 +566,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.watchdog = rt2x00usb_watchdog,
.write_tx_desc = rt2800usb_write_tx_desc,
- .write_tx_data = rt2800usb_write_tx_data,
+ .write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
.get_tx_data_len = rt2800usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
--
1.7.2
^ permalink raw reply related
* [PATCH 5/7] rt2x00: Implement TX status reporting for rt2800usb
From: Ivo van Doorn @ 2010-08-06 18:47 UTC (permalink / raw)
To: John W. Linville; +Cc: users, linux-wireless
In-Reply-To: <201008062047.21710.IvDoorn@gmail.com>
The TX_STA_FIFO register which is used for per-frame TX frame
status reporting is also valid on rt2800usb. We can move the
rt2800pci_txdone function into rt2800lib where it can also
be used by rt2800usb.
rt2800usb needs to overwrite the txdone work handler to
a different function.
Both rt2800usb as rt2800_txdone need to take into account
that IO failures can occur while uploading the URB, which
means that when obtaining the new entry the IO status must
be checked.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt2800lib.c | 117 +++++++++++++++++++++++++++++++
drivers/net/wireless/rt2x00/rt2800lib.h | 4 +
drivers/net/wireless/rt2x00/rt2800pci.c | 108 +----------------------------
drivers/net/wireless/rt2x00/rt2800usb.c | 40 ++++++++++-
4 files changed, 162 insertions(+), 107 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 6f1eb58..827a258 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1,4 +1,5 @@
/*
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>
@@ -572,6 +573,122 @@ void rt2800_process_rxwi(struct queue_entry *entry,
}
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
+void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ struct queue_entry *entry;
+ __le32 *txwi;
+ struct txdone_entry_desc txdesc;
+ u32 word;
+ u32 reg;
+ int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
+ u16 mcs, real_mcs;
+ int i;
+
+ /*
+ * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
+ * at most X times and also stop processing once the TX_STA_FIFO_VALID
+ * flag is not set anymore.
+ *
+ * The legacy drivers use X=TX_RING_SIZE but state in a comment
+ * that the TX_STA_FIFO stack has a size of 16. We stick to our
+ * tx ring size for now.
+ */
+ for (i = 0; i < TX_ENTRIES; i++) {
+ rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®);
+ if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
+ break;
+
+ wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
+ ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
+ pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
+
+ /*
+ * Skip this entry when it contains an invalid
+ * queue identication number.
+ */
+ if (pid <= 0 || pid > QID_RX)
+ continue;
+
+ queue = rt2x00queue_get_queue(rt2x00dev, pid - 1);
+ if (unlikely(!queue))
+ continue;
+
+ /*
+ * Inside each queue, we process each entry in a chronological
+ * order. We first check that the queue is not empty.
+ */
+ entry = NULL;
+ while (!rt2x00queue_empty(queue)) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ if (!test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+ break;
+
+ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+ }
+
+ if (!entry || rt2x00queue_empty(queue))
+ break;
+
+ /*
+ * Check if we got a match by looking at WCID/ACK/PID
+ * fields
+ */
+ txwi = rt2800_drv_get_txwi(entry);
+
+ rt2x00_desc_read(txwi, 1, &word);
+ tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
+ tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
+ tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
+
+ if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid))
+ WARNING(rt2x00dev, "invalid TX_STA_FIFO content");
+
+ /*
+ * Obtain the status about this packet.
+ */
+ txdesc.flags = 0;
+ rt2x00_desc_read(txwi, 0, &word);
+ mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
+ mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
+ real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
+
+ /*
+ * Ralink has a retry mechanism using a global fallback
+ * table. We setup this fallback table to try the immediate
+ * lower rate for all rates. In the TX_STA_FIFO, the MCS field
+ * always contains the MCS used for the last transmission, be
+ * it successful or not.
+ */
+ if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) {
+ /*
+ * Transmission succeeded. The number of retries is
+ * mcs - real_mcs
+ */
+ __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+ txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
+ } else {
+ /*
+ * Transmission failed. The number of retries is
+ * always 7 in this case (for a total number of 8
+ * frames sent).
+ */
+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
+ txdesc.retry = rt2x00dev->long_retry;
+ }
+
+ /*
+ * the frame was retried at least once
+ * -> hw used fallback rates
+ */
+ if (txdesc.retry)
+ __set_bit(TXDONE_FALLBACK, &txdesc.flags);
+
+ rt2x00lib_txdone(entry, &txdesc);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2800_txdone);
+
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 8f97518..3b572c6 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -1,4 +1,6 @@
/*
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Bartlomiej Zolnierkiewicz
This program is free software; you can redistribute it and/or modify
@@ -147,6 +149,8 @@ void rt2800_write_tx_data(struct queue_entry *entry,
struct txentry_desc *txdesc);
void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
+void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
+
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
extern const struct rt2x00debug rt2800_rt2x00debug;
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index f415f6d..4390f2b 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
@@ -724,110 +724,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
/*
* Interrupt functions.
*/
-static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
- struct queue_entry *entry;
- __le32 *txwi;
- struct txdone_entry_desc txdesc;
- u32 word;
- u32 reg;
- int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
- u16 mcs, real_mcs;
- int i;
-
- /*
- * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
- * at most X times and also stop processing once the TX_STA_FIFO_VALID
- * flag is not set anymore.
- *
- * The legacy drivers use X=TX_RING_SIZE but state in a comment
- * that the TX_STA_FIFO stack has a size of 16. We stick to our
- * tx ring size for now.
- */
- for (i = 0; i < TX_ENTRIES; i++) {
- rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®);
- if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
- break;
-
- wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
- ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
- pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
-
- /*
- * Skip this entry when it contains an invalid
- * queue identication number.
- */
- if (pid <= 0 || pid > QID_RX)
- continue;
-
- queue = rt2x00queue_get_queue(rt2x00dev, pid - 1);
- if (unlikely(!queue))
- continue;
-
- /*
- * Inside each queue, we process each entry in a chronological
- * order. We first check that the queue is not empty.
- */
- if (rt2x00queue_empty(queue))
- continue;
- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-
- /* Check if we got a match by looking at WCID/ACK/PID
- * fields */
- txwi = (__le32 *) entry->skb->data;
-
- rt2x00_desc_read(txwi, 1, &word);
- tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
- tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
- tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
-
- if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid))
- WARNING(rt2x00dev, "invalid TX_STA_FIFO content\n");
-
- /*
- * Obtain the status about this packet.
- */
- txdesc.flags = 0;
- rt2x00_desc_read(txwi, 0, &word);
- mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
- real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
-
- /*
- * Ralink has a retry mechanism using a global fallback
- * table. We setup this fallback table to try the immediate
- * lower rate for all rates. In the TX_STA_FIFO, the MCS field
- * always contains the MCS used for the last transmission, be
- * it successful or not.
- */
- if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) {
- /*
- * Transmission succeeded. The number of retries is
- * mcs - real_mcs
- */
- __set_bit(TXDONE_SUCCESS, &txdesc.flags);
- txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
- } else {
- /*
- * Transmission failed. The number of retries is
- * always 7 in this case (for a total number of 8
- * frames sent).
- */
- __set_bit(TXDONE_FAILURE, &txdesc.flags);
- txdesc.retry = 7;
- }
-
- /*
- * the frame was retried at least once
- * -> hw used fallback rates
- */
- if (txdesc.retry)
- __set_bit(TXDONE_FALLBACK, &txdesc.flags);
-
- rt2x00lib_txdone(entry, &txdesc);
- }
-}
-
static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
{
struct ieee80211_conf conf = { .flags = 0 };
@@ -863,7 +759,7 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
* 4 - Tx done interrupt.
*/
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
- rt2800pci_txdone(rt2x00dev);
+ rt2800_txdone(rt2x00dev);
/*
* 5 - Auto wakeup interrupt.
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 9084b9a..9ad28be 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
@@ -378,6 +379,38 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
}
/*
+ * TX control handlers
+ */
+static void rt2800usb_work_txdone(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, txdone_work);
+ struct data_queue *queue;
+ struct queue_entry *entry;
+
+ rt2800_txdone(rt2x00dev);
+
+ /*
+ * Process any trailing TX status reports for IO failures,
+ * we loop until we find the first non-IO error entry. This
+ * can either be a frame which is free, is being uploaded,
+ * or has completed the upload but didn't have an entry
+ * in the TX_STAT_FIFO register yet.
+ */
+ tx_queue_for_each(rt2x00dev, queue) {
+ while (!rt2x00queue_empty(queue)) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+ break;
+
+ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+ }
+ }
+}
+
+/*
* RX control handlers
*/
static void rt2800usb_fill_rxdone(struct queue_entry *entry,
@@ -513,6 +546,11 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
*/
rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+ /*
+ * Overwrite TX done handler
+ */
+ PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
+
return 0;
}
--
1.7.2
^ permalink raw reply related
* [PATCH 6/7] rt2x00: Update comments regarding TXWI and TX_STA_FIFO
From: Ivo van Doorn @ 2010-08-06 18:48 UTC (permalink / raw)
To: John W. Linville; +Cc: users, linux-wireless
In-Reply-To: <201008062047.58607.IvDoorn@gmail.com>
From: Helmut Schaa <helmut.schaa@googlemail.com>
Add some comments about the TXWI fields and the TX_STA_FIFO register.
Especially describe the relationship between the TXWI field PACKETID
and the PID field in the TX_STA_FIFO register.
Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
---
drivers/net/wireless/rt2x00/rt2800.h | 27 ++++++++++++++++++++++++++-
1 files changed, 26 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index ed4ebcd..cf1f16b 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -1318,7 +1318,25 @@
#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000)
/*
- * TX_STA_FIFO: TX Result for specific PID status fifo register
+ * TX_STA_FIFO: TX Result for specific PID status fifo register.
+ *
+ * This register is implemented as FIFO with 16 entries in the HW. Each
+ * register read fetches the next tx result. If the FIFO is full because
+ * it wasn't read fast enough after the according interrupt (TX_FIFO_STATUS)
+ * triggered, the hw seems to simply drop further tx results.
+ *
+ * VALID: 1: this tx result is valid
+ * 0: no valid tx result -> driver should stop reading
+ * PID_TYPE: The PID latched from the PID field in the TXWI, can be used
+ * to match a frame with its tx result (even though the PID is
+ * only 4 bits wide).
+ * TX_SUCCESS: Indicates tx success (1) or failure (0)
+ * TX_AGGRE: Indicates if the frame was part of an aggregate (1) or not (0)
+ * TX_ACK_REQUIRED: Indicates if the frame needed to get ack'ed (1) or not (0)
+ * WCID: The wireless client ID.
+ * MCS: The tx rate used during the last transmission of this frame, be it
+ * successful or not.
+ * PHYMODE: The phymode used for the transmission.
*/
#define TX_STA_FIFO 0x1718
#define TX_STA_FIFO_VALID FIELD32(0x00000001)
@@ -1945,6 +1963,13 @@ struct mac_iveiv_entry {
/*
* Word1
+ * ACK: 0: No Ack needed, 1: Ack needed
+ * NSEQ: 0: Don't assign hw sequence number, 1: Assign hw sequence number
+ * BW_WIN_SIZE: BA windows size of the recipient
+ * WIRELESS_CLI_ID: Client ID for WCID table access
+ * MPDU_TOTAL_BYTE_COUNT: Length of 802.11 frame
+ * PACKETID: Will be latched into the TX_STA_FIFO register once the according
+ * frame was processed. 0: Don't report tx status for this frame.
*/
#define TXWI_W1_ACK FIELD32(0x00000001)
#define TXWI_W1_NSEQ FIELD32(0x00000002)
--
1.7.2
^ permalink raw reply related
* [PATCH 7/7] rt2x00: Remove ieee80211_rx_status from rt2x00_dev
From: Ivo van Doorn @ 2010-08-06 18:49 UTC (permalink / raw)
To: John W. Linville; +Cc: users, linux-wireless
In-Reply-To: <201008062048.28764.IvDoorn@gmail.com>
rt2x00 was keeping a copy of ieee80211_rx_status embedded
into the rt2x00_dev structure. For each RX frame, this structure
was copied into the skb->cb where mac80211 would handle it further.
However at the moment only the fields current band, and frequency
were updated. Whereas the band was already provided directly within
the rt2x00_dev structure. Save a memcpy action, and reduce memory
a bit, by adding a curr_freq field to rt2x00_dev, and completely
remove the ieee80211_rx_status structure from rt2x00_dev.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Gertjan van Wingerde <gwingerde@gmail.com>
---
drivers/net/wireless/rt2x00/rt2800lib.c | 2 +-
drivers/net/wireless/rt2x00/rt2x00.h | 6 +-----
drivers/net/wireless/rt2x00/rt2x00config.c | 4 +---
drivers/net/wireless/rt2x00/rt2x00dev.c | 16 +++++++++-------
drivers/net/wireless/rt2x00/rt61pci.c | 4 ++--
drivers/net/wireless/rt2x00/rt73usb.c | 4 ++--
6 files changed, 16 insertions(+), 20 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 827a258..3a150d3 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -494,7 +494,7 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
u8 offset1;
u8 offset2;
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index edfc2b7..8c65244 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -699,6 +699,7 @@ struct rt2x00_dev {
struct ieee80211_hw *hw;
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
enum ieee80211_band curr_band;
+ int curr_freq;
/*
* If enabled, the debugfs interface structures
@@ -851,11 +852,6 @@ struct rt2x00_dev {
struct ieee80211_low_level_stats low_level_stats;
/*
- * RX configuration information.
- */
- struct ieee80211_rx_status rx_status;
-
- /*
* Scheduled work.
* NOTE: intf_work will use ieee80211_iterate_active_interfaces()
* which means it cannot be placed on the hw->workqueue
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 953dc4f..9971d5c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -209,10 +209,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
rt2x00link_reset_tuner(rt2x00dev, false);
rt2x00dev->curr_band = conf->channel->band;
+ rt2x00dev->curr_freq = conf->channel->center_freq;
rt2x00dev->tx_power = conf->power_level;
rt2x00dev->short_retry = conf->short_frame_max_tx_count;
rt2x00dev->long_retry = conf->long_frame_max_tx_count;
-
- rt2x00dev->rx_status.band = conf->channel->band;
- rt2x00dev->rx_status.freq = conf->channel->center_freq;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 6499cc4..e692608 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -464,7 +464,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
{
struct rxdone_entry_desc rxdesc;
struct sk_buff *skb;
- struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
+ struct ieee80211_rx_status *rx_status;
unsigned int header_length;
int rate_idx;
@@ -535,19 +535,21 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
*/
rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
rt2x00debug_update_crypto(rt2x00dev, &rxdesc);
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
+ /*
+ * Initialize RX status information, and send frame
+ * to mac80211.
+ */
+ rx_status = IEEE80211_SKB_RXCB(entry->skb);
rx_status->mactime = rxdesc.timestamp;
+ rx_status->band = rt2x00dev->curr_band;
+ rx_status->freq = rt2x00dev->curr_freq;
rx_status->rate_idx = rate_idx;
rx_status->signal = rxdesc.rssi;
rx_status->flag = rxdesc.flags;
rx_status->antenna = rt2x00dev->link.ant.active.rx;
- /*
- * Send frame to mac80211 & debugfs.
- * mac80211 will clean up the skb structure.
- */
- rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
- memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
/*
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index dc6f3eb..cff503f 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1050,7 +1050,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev,
/*
* Determine r17 bounds.
*/
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
low_bound = 0x28;
up_bound = 0x48;
if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
@@ -1972,7 +1972,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
return 0;
}
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
if (lna == 3 || lna == 2)
offset += 10;
}
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index aa9de18..c655296 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -929,7 +929,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev,
/*
* Determine r17 bounds.
*/
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
low_bound = 0x28;
up_bound = 0x48;
@@ -1597,7 +1597,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
return 0;
}
- if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+ if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
if (lna == 3 || lna == 2)
offset += 10;
--
1.7.2
^ permalink raw reply related
* Patches not make into wireless-next
From: Guy, Wey-Yi @ 2010-08-06 18:59 UTC (permalink / raw)
To: linville@tuxdriver.com
Cc: linux-wireless@vger.kernel.org,
ipw3945-devel@lists.sourceforge.net
In-Reply-To: <1281106291.22150.2.camel@wwguy-ubuntu>
Hi John,
Number of patches not make into wireless-next-2.6 last week
iwlwifi: make iwl_set_hw_params static to _agn
iwlwifi: separate thermal throttling function
iwlagn: log pci revision id
iwlwifi: make iwl_hw_detect static to _agn
I need to re-work "thermal-throttling" patch to include Johanne's fix,
how about other patches, any recommendation?
Thanks
Wey
^ permalink raw reply
* Re: [ath9k-devel] Multiple interfaces with one card
From: Hakan Coskun @ 2010-08-06 18:59 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: ath9k-devel@lists.ath9k.org, linux-wireless
In-Reply-To: <20100806184849.GF1757@tux>
Am 06.08.2010 um 20:48 schrieb Luis R. Rodriguez:
> On Fri, Aug 06, 2010 at 03:32:20AM -0700, Hakan Coskun wrote:
>> Hi,
>>
>> we are doing research in order to study the behaviour of virtual wifi interfaces with channel switching. After a simulative study, we started to perform some real world experiments with ath9k. Running multiple wiphys on top of a card is working quite good. Of course there are several restrictions and performance problems, we are working on some scheduling algorithms to improve the operation.
>> But now to take it a step further, we plan to go for a mac80211 based virtualization, meaning to run multiple vifs in parallel in station mode. The first step is to run them on the same channel, but as expected this is not working. We can create several interfaces with iw, there is no problem. Even scanning is working, but as soon as we want to connect to an open AP we get into trouble. The authentication is not working.
>>
>> Sure, the mac80211 needs some additional functionality like ath9k, to cope with multiple associations and channel switching, etc.. How can we track the sequence of operations during the runtime in order to get a better understanding of the mac80211. At the moment, we enabled tracing and debug messages for mac80211, this helps but is not sufficient to follow the functions step by step. We can put a lot of debugging messages into the files, but are there any "best practices" we should follow.
>>
>
> Hakan, I recommend you use the linux-wireless mailing list for this
> and also always use wireless-testing.git for your development.
>
> Can you post patches of what you have done to mac80211 / cfg80211?
>
> Luis
>
Hi Luis,
thank you for your really quick reply. We are already using wireless-testing for our development. The ath9k extensions will be commited soon. At the moment, we are using the eclipse to index the code and walk through the files. This is working quite good. But how can we see during runtime, what is happening. Should we use something like kgdb to trace the operation or what is your approach you take for development. Can you give us any hints ?
Hakan
^ permalink raw reply
* Compat-wireless release for 2010-08-06 is baked
From: Compat-wireless cronjob account @ 2010-08-06 19:03 UTC (permalink / raw)
To: linux-wireless
>From git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/compat-wireless-2.6
1bf4bba..bd3cf78 linux-2.6.35.y -> origin/linux-2.6.35.y
55764c1..8eb662b wl -> origin/wl
* [new tag] compat-wireless-v2.6.35-1 -> compat-wireless-v2.6.35-1
>From git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/compat
464e8d5..9855656 linux-2.6.35.y -> origin/linux-2.6.35.y
226b1c2..d6f0174 master -> origin/master
>From git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next
8a39b1f..b7cb6f4 history -> origin/history
+ b07c08d...598a80f master -> origin/master (forced update)
3cfc2c4..fc1caf6 stable -> origin/stable
* [new tag] next-20100806 -> next-20100806
compat-wireless code metrics
494668 - Total upstream lines of code being pulled
1532 - backport code changes
1296 - backport code additions
236 - backport code deletions
5805 - backport from compat module
7337 - total backport code
1.4832 - % of code consists of backport work
1218 - Crap changes not yet posted
1179 - Crap additions not yet posted
39 - Crap deletions not yet posted
0.2462 - % of crap code
Base tree: linux-next.git
Base tree version: next-20100806
compat-wireless release: compat-wireless-2010-08-03-1-g3672499
^ permalink raw reply
* Re: Odd BUG on wireless-testing master-2010-08-05
From: Luis R. Rodriguez @ 2010-08-06 19:05 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless
In-Reply-To: <20100806135057.GA2753@tuxdriver.com>
On Fri, Aug 6, 2010 at 6:50 AM, John W. Linville <linville@tuxdriver.com> wrote:
> On Thu, Aug 05, 2010 at 03:31:06PM -0700, Luis R. Rodriguez wrote:
>> I just ran into this. My first load of master-2010-08-05 was fine but
>> I started getting a lot of disconnects on AR9003 hardware after a
>> period of RX'ing data over an encrypted legacy network. Instead of
>> checking dmesg I just rebooted though. After that I connected to the
>> same AP again, started Rx'ing for a while and then shortly got this:
>>
>>
>> [ 818.749585] BUG: unable to handle kernel paging request at 00003f3f00000000
>> [ 818.749594] IP: [<ffffffff814ee0d8>] unix_stream_recvmsg+0x3f8/0x790
>
>> After a reboot I got a hard hang which I could not capture any logs
>> for. I rebooted and am up now but not seeing these issues yet. John,
>> does this smell like what you were seeing or is this different?
>
> Yeah, I'm seeing that too. There is some netdev stuff in
> wireless-testing at the moment that I suspect was undercooked...
>
> Sorry for the inconvenience while this gets sorted-out!
Ah no problem, just wanted to see if I should dig into ath9k or not,
sounds like I don't. FWIW I had a hang overnight as well.
Luis
^ 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