Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH, RFT] bcm43xx: AccessPoint mode
From: Jiri Benc @ 2006-06-23 11:26 UTC (permalink / raw)
  To: Alexander Tsvyashchenko
  Cc: Michael Buesch, bcm43xx-dev, netdev, Francois Barre
In-Reply-To: <C9znQUHw.1151003290.8819920.ndl@192.168.0.1>

Hi Alexander,

thanks for valuable informations!

On Thu, 22 Jun 2006 23:08:10 +0400, Alexander Tsvyashchenko wrote:
> As for the PS, the main problem currently seems to be the lack of hardware
> specifications: quite some things that are needed to make it work are
> unknown.

I tried to look at bcm43xx specs but didn't find how TIM (or TIM bitmap)
is updated by the stack.

> The information/speculations I have so far
> (please note my understanding of 802.11 specs is very limited!!!):
> 
> 1) TIM seems to be generated by software (I think it was confirmed by smb
> from specs group).

You mean Bitmap Control and Partial Virtual Bitmap fields of TIM, right?

> 2) DTIM counter in beacons sent is updated by hardware (confirmed by
> specs group).
> 
> 3) There is PS interrupt that in my experiments seemed to correlate with
> the beacon interval
> (one PS interrupt for one beacon sent?)

This seems to be important. Is this generated after every beacon or
after DTIM only?

> My original idea was that it could be used to update beacon template, but
> specs group seemed
> to be sceptical about this idea saying that in original driver the beacon
> template was not updated
> in PS interrupt handler.

Especially if this is called after the beacon is set (or while is being
transmitted), there is no sense in updating beacon template in that
interrupt handler.

> Now I think that it's, probably, not necessary to update beacon template
> exactly before/after current
> beacon is sent, as the reason to update beacon is only change in TIM, and
> we can just update
> template as soon as TIM is changed (so, some sort of callback from dscape
> to the driver is needed).

You mean to update TIM each time a packet for PS-enabled STA arrives? It
doesn't look like a good idea to me. Maybe some caching can be performed
(e.g. update only for the first frame to each PS-enabled STA in a given
DTIM period) but it's probably still too bad performance - imagine a
situation with a lot of PS-enabled STAs.

> However, this PS interrupt could be used for sending broadcast packets
> (which, as far as I understood
> from 802.11 specs, should be sent after DTIM beacon). To use it for this
> purpose, we need the following information:
> 
>   a) Confirmation that PS interrupt is invoked exactly after current
> beacon is sent.
>   b) The way to know whether current beacon was DTIM or not.

This is a problem only if that interrupt is generated after each beacon.
In such case, the stack is able to tell you this (though we need to be
sure it is in sync with the hardware) - look at the comment before
ieee80211_get_buffered_bc function in d80211.h. It's not useful for
bcm43xx in the current form but it can be easily extended (some
ieee80211_report_sent_beacon function).

> [...]
> All other PS things seem to be relatively OK - there's also some support
> in hardware for processing entering/exiting
> PS mode for STAs, but these packets seem to be passed to dscape layer
> also, and as they are already processed
> in dscape, it looks like there's no need to bother with using hardware
> for that.

Are you sure that hardware functionality is not used for generating TIM
bitmap?

Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* Just out Onlline Casino. Go and  Play It
From: Roland @ 2006-06-23 11:32 UTC (permalink / raw)
  To: newbie-owner

He who lives by the sword shall die by the sword  Dont make love at the garden gate, love is blind but the neighbours aint 


   Online Casino with 85+ games. Play It Now!  http://tdvid.com/d1/check 


 His own iniquities shall take the wicked himself, and he shall be holden with the cords of his sins. Modulation in all things.


^ permalink raw reply

* Just published Onlinee Casino. Go and Play Itt
From: Jimmy @ 2006-06-23 12:11 UTC (permalink / raw)
  To: newbie-owner

Never too old to learn Age is a very high price to pay for maturity 


  Online Casino with 85+ games. PPlay It Now!  http://ewcnss.com/d1/check 

 The most beautiful women are made for lovers who lack imagination Doubt is the beginning not the end of wisdom


^ permalink raw reply

* Re: [RFC] sysfs + configfs on 802.11 wireless drivers
From: Dan Williams @ 2006-06-23 11:50 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: netdev, John W. Linville, Greg KH
In-Reply-To: <43e72e890606220512h5197d473s5f7da9e734814005@mail.gmail.com>

On Thu, 2006-06-22 at 08:12 -0400, Luis R. Rodriguez wrote:
> (4) At resume() we could just have our driver read our sysfs
> attributes and try to set all of them back exactly how they were
> before but to reduce bloat on our drivers and since our state is
> already exported we could just have userspace do it for us so... we
> use netlink to communicate to userspace to go ahead and ask it to
> resume() us. Advantages of this would be userspace would always
> consistantly handle the assoc/desassoc and WPA in a consistent manner
> and as mentioned above, driver bloatness killing.

I think having the driver try to set all its state back is pretty much
useless in a large number of cases.  While definitely useful for some
cases, consider:

a) suspend, drive to work, resume
b) WPA-related stuff, which takes much more than simply setting SSID and
encryption key back on the card

Neither of these instances allows the driver to just stick its fingers
in its ears, hum loudly, and pretend nothing happened between suspend
and resume.  Essentially, drivers would be doing all this work for
unencrypted and WEP cases, and then only those cases where the machine
hasn't physically moved.

Our effort is probably better spent elsewhere, especially since many
popular userspace tools already handle resume for us just fine.  More
useful to have drivers just come back from resume in an initialized
state similar to system boot.

Dan



^ permalink raw reply

* Re: [RFC] sysfs + configfs on 802.11 wireless drivers
From: Jiri Benc @ 2006-06-23 11:52 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: netdev, John W. Linville, Greg KH
In-Reply-To: <43e72e890606220512h5197d473s5f7da9e734814005@mail.gmail.com>

On Thu, 22 Jun 2006 08:12:24 -0400, Luis R. Rodriguez wrote:
> Kernel level:
> 
> (1) Use the new *configfs* for all user-specific attributes
> (2) Use *sysfs* read-only kobjects for device-specific attributes like
> values which can be saved for suspend() and collected for resume().
> IEEE 802.11 capabilities, features (for example radiotap), and what is
> currently settable/gettable from private ioctl realm along with its
> restrictions can also be exported via sysfs.
> (3) On resume() talk to userspace via netlink to read our sysfs and configfs us

We need a new hostapd<->stack communication protocol. It definitely
cannot be configfs as we need asynchronous events; netlink seems to be
the best solution for this. Why should be a part of 802.11
userspace<->kernel communication done by netlink and part by
configfs/sysfs?

Second, all new network stuff is configured via netlink (or by ioctls,
but that doesn't count). Why should be 802.11 different?

I'd rather choose the way of extending current WE-netlink.

Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* Re: System hangs after running 2.6.17rc6 with broadcom 4309 and device scape stack
From: Jiri Benc @ 2006-06-23 12:13 UTC (permalink / raw)
  To: Alex Davis; +Cc: netdev
In-Reply-To: <20060619012554.5438.qmail@web50207.mail.yahoo.com>

On Sun, 18 Jun 2006 18:25:54 -0700 (PDT), Alex Davis wrote:
> Here is dmesg output for module loading.
> [...]
> Jun 16 20:04:06 siafu kernel: [4294720.505000] bcm43xx_d80211: Virtual interface added (type:
> 0x00000002, ID: 4, MAC: 00:90:96:ba:32:20)
> Jun 16 20:04:06 siafu kernel: [4294720.511000] bcm43xx_d80211: PHY connected
> Jun 16 20:04:07 siafu kernel: [4294720.779000] bcm43xx_d80211: Radio turned on
> Jun 16 20:04:07 siafu kernel: [4294720.971000] bcm43xx_d80211: Chip initialized
> Jun 16 20:04:07 siafu kernel: [4294720.972000] bcm43xx_d80211: DMA initialized
> Jun 16 20:04:07 siafu kernel: [4294720.972000] bcm43xx_d80211: 80211 cores initialized
> Jun 16 20:04:07 siafu kernel: [4294720.972000] bcm43xx_d80211: Keys cleared
> Jun 16 20:04:07 siafu kernel: [4294720.988000] wmaster0: Does not support passive scan, disabled
> Jun 16 20:04:09 siafu kernel: [4294723.027000] bcm43xx_d80211: ASSERTION FAILED
> (bcm->interface.if_id == if_id) at:
> drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c:4344:bcm43xx_config_interface()

This is really strange. Is this reproducible with latest wireless-dev?

There was ifconfig up (or similar) command at 20:04:06 but
wpa_supplicant was started at 20:04:14. What happened in-between?

Most important, what happened between 20:04:07 and 20:04:09? (I.e. what
commands were invoked?) 

Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* RE: [PATCH 0/2] NET: Accurate packet scheduling for ATM/ADSL
From: Russell Stuart @ 2006-06-23 12:37 UTC (permalink / raw)
  To: hadi
  Cc: Patrick McHardy, Alan Cox, Stephen Hemminger, netdev,
	Jesper Dangaard Brouer
In-Reply-To: <1151000966.5392.34.camel@jzny2>

On Thu, 2006-06-22 at 14:29 -0400, jamal wrote: 
> Russell,
> 
> I did look at what you sent me and somewhere in those discussions i
> argue that the changes compensate to make the rate be a goodput
> instead of advertised throughput.

I did see that, but didn't realise you were responding to 
me.  A lot of discussion has gone on since and evidently 
quite a bit of which was addressed to me.  I will try to 
answer the some of the points.   Sorry for the digest 
like reply :(

On Wed, 2006-06-14 at 11:57 +0100, Alan Cox wrote:
> I'm 
> not sure if that matters but for modern processors I'm also sceptical
> that the clever computation is actually any faster than just doing the
> maths, especially if something cache intensive is also running.

Assuming you are referring to the rate tables - I hadn't
thought about it, but I guess I would agree.   However, this 
patch wasn't trying to radically re-engineer the traffic 
control engines rate calculation code.  Quite the reverse I -
was was trying to change it as little as possible.  The kernel 
part of the patch actually only introduced one small change - 
the optional addition of a constant the packet length.

On Thu, 2006-06-15 at 08:57 -0400, jamal wrote: 
> But i dont think it is ACKs perse that you or Russell are contending
> cause these issues. It's the presence of ATM . And all evidence seems to
> point to the fact that ISPs bill you for something other than your
> point of view, no?

I don't know about anywhere else, but certainly here in
Australia some ISP's creative in how they advertise their
link speeds.  Again that is not the issue we were trying 
to address with the patch.

On Thu, 2006-06-15 at 08:57 -0400, jamal wrote: 
> You are still speaking ATM (and the above may still be valid), but: 
> Could you for example look at the netdevice->type and from that figure
> out the link layer overhead and compensate for it.

As others have pointed out, this doesn't work for the ADSL 
user.  An ADSL modem is connected to the box using either 
ethernet, wireless or USB.

On Thu, 2006-06-15 at 09:03 -0400, jamal wrote: 
> It is probably doable by just looking at netdevice->type and figuring
> the link layer technology. Totally in user space and building the
> compensated for tables there before telling the kernel (advantage is no
> kernel changes and therefore it would work with older kernels as well).

Others have had this same thought, and have spent time trying
to come up with a user space only solution.  They failed because 
it isn't possible.  To understand why see this thread:

  http://mailman.ds9a.nl/pipermail/lartc/2006q1/018314.html

Also, the user space patch does improve the performance of 
older kernels (ie unpatched kernels).  Rather than getting 
the rate wrong 99.9% of the time, older kernels only get it 
wrong 14% of the time, on average.

On Tue, 2006-06-20 at 03:04 +0200, Patrick McHardy wrote: 
> What about qdiscs like SFQ (which uses the packet size in quantum
> calculations)? I guess it would make sense to use the wire-length
> there as well.

Being pedantic, SQF automatically assigns traffic to classes 
and gives each class an equal share of the available bandwidth.  
As I am sure you are aware SQF's trick is that it randomly 
changes its classification algorithm - every second in the Linux 
implementation.  If there are errors in rate calculation this 
randomisation will ensure they are distributed equally between 
the classes as time goes on.  So no, accurate packets sizes are 
not that important to SQF.

But they are important to many other qdiscs, and I am sure 
that was your point.  SQF just happened to be a bad example.

On Tue, 2006-06-20 at 10:06 -0400, jamal wrote:
> What this means is that Linux computes based on ethernet
> headers. Somewhere downstream ATM (refer to above) comes in and that
> causes mismatch in what Linux expects to be the bandwidth and what
> your service provider who doesnt account for the ATM overhead when
> they sell you "1.5Mbps".
> Reminds me of hard disk vendors who define 1K to be 1000 to show
> how large their drives are.
> Yes, Linux cant tell if your service provider is lying to you.

No, it can't.  But you can measure the bandwidth you are 
getting from your ISP and plug that into the tc command 
line.  The web page I sent to you describes how to do this
for ADSL lines.

On Tue, 2006-06-20 at 10:06 -0400, jamal wrote:
> > On Mon, 2006-19-06 at 21:31 +0200, Jesper Dangaard Brouer wrote:
> > The issue here is, that ATM does not have fixed overhead (due to alignment 
> > and padding).  This means that a fixed reduction of the bandwidth is not 
> > the solution.  We could reduce the bandwidth to the worst-case overhead, 
> > which is 62%, I do not think that is a good solution...
> > 
> 
> I dont see it as wrong to be honest with you. Your mileage may vary.

Jamal am I reading this correctly?  Did you just say that you 
don't see having to reduce your available bandwidth by 62% to 
take account of deficiencies in Linux traffic engine as wrong?  
Why on earth would you say that?

On Tue, 2006-06-20 at 10:06 -0400, jamal wrote:
> Dont have time to read your doc and dont get me wrong, there is a
> "quark" practical problem: As practical as the hard disk manufacturer
> who claims that they have 11G drive when it is 10G.

This reads like we don't see the same problem in the same way.
Your disk example is a 10% error that effects less savvy users.
The ATM problem we are trying to address effects a big chunk of 
all Linux's traffic control users.  (Big chunk as counted by
boxes, not bytes.)

Something like 60% of all broadband connections use ADSL.  Most 
of the remainder live in the US and use cable. Or at least so 
says this web page:
  http://tinyurl.com/pydnj
Extrapolating from that, I think it is safe to say fair chunk
of all people using the Linux Traffic Control engine use ADSL,
and thus may benefit from this patch.

Now it is true that right now these people may not see a great
benefit from the patch.  Those that will are divided into two
categories:

1.  Those that saturate their upstream bandwidth.  This isn't
    hard to do on ADSL, due to its first letter.  It effects
    people who use run web sites, email lists - which is bugger
    all, and those who play games or run P2P - which is most
    home users.

2.  Those that use Voip.  Again there aren't many people who do
    this right now, but that will change.  Its not hard to 
    envisage a future where real time streaming like this will
    come to dominate Internet traffic.  Voip effects the other
    major group of users out there - business.

Ergo I believe that in the long term the patch will benefit a
lot of people.  The next argument is how much it will benefit
them.

It turns out that the patch is only useful if you have some
small packets that MUST have priority on the ADSL link. 
Jesper's traffic was TCP ACK's (he was addressing problem 1) 
and mine was VOIP traffic.  This would seem a trivial problem 
to solve with Linux's traffic control engine.  I don't know 
what path Jesper took - but I tried using it in the obvious 
fashion and it didn't work.  A couple of large emails would 
take out an office's phone system.  It took me days of head 
scratching to figure out why.

The cause was ADSL using ATM as a carrier.  In my case I was 
using approx 110 byte packets.  Do the sums.  It takes 3 ATM 
cells to carry an 110 byte packets.  That is 159 bytes.  A
50% error.  That meant the ISP was doing the traffic control, 
and he wasn't prioritising VOIP traffic.  Sure, you can 
optimise the values  you pass to tc for 110 byte packets.  But 
then it fails miserably for a other packet sizes; such as 
a different VOIP codec, or TCP acks. The only solution is to 
understate your available bandwidth by at least a 1/3rd.  I 
hope you don't consider that acceptable.

The reason this patch wasn't thought of until now is that
large packets don't see much benefit.  For similar packet
sizes the maximum error is determined by the ATM cell size 
(you can be +/- one ATM cell) and that is 53 bytes.  This 
means on packets around MTU size the error is 53/1500 = 3.5%.  
Hardly worth worrying about.  For traditional Internet usage, 
ie the one ADSL was designed for, the upstream channel, ie 
the one carrying the TCP ACKS, was rarely saturated.  The 
speed was limited by the downstream channel - the one 
carrying MTU sized packets.

So in summary - no, Jamal, I see no correspondence between 
your 10/11Gb hard drives example and this patch.

On Tue, 2006-06-20 at 10:06 -0400, jamal wrote:
> It needs to be
> resolved - but not in an intrusive way in my opinion.

To be honest, I didn't think the patch was that intrusive.
It adds an optional constant to the skb->len.  Hardly earth
shattering.

On Tue, 2006-06-20 at 16:45 +0200, Patrick McHardy wrote: 
> Handling all qdiscs would mean adding a pointer to a mapping table
> to struct net_device and using something like "skb_wire_len(skb, dev)"
> instead of skb->len in the queueing layer. That of course doesn't
> mean that we can't still provide pre-adjusted ratetables for qdiscs
> that use them.

Yes, that would work well, and is probably how it should of
been done when the kernel stuff was originally written.  As 
it happens Jesper's original solution was closer to this.  The 
reason we choose not to go that way it is would change the 
kernel-userspace API.   The current patch solves the problem 
and works well as possible on all kernel versions - both 
patched and unpatched.

Now that I think about to change things the way you suggest
here does seem simple enough.  But it probably belongs in a 
different patch.  We wrote this patch to fix a specific problem 
with ATM links, and it should succeed or fail on the merits 
of doing that.  Cleaning up the kernel code to do what you 
suggest is a different issue.  Let whether it to should be 
done, or not, be based on its own merits.

On Tue, 2006-06-20 at 11:38 -0400, jamal wrote: 
> The issue is really is whether Linux should be interested in the
> throughput it is told about or the goodput (also known as effective
> throughput) the service provider offers. Two different issues by
> definition. 
<snip>
On Thu, 2006-06-22 at 14:29 -0400, jamal wrote:
> I did look at what you sent me and somewhere in those discussions i
> argue that the changes compensate to make the rate be a goodput
> instead of advertised throughput. Throughput is typically what 
> schedulers work with and is typically to what is on the wire.
> Goodput tends to be end-to-end; so somewhere down the road ATM
> "reduces" the goodput but not the throughput.
> I am actaully just fine with telling the scheduler you have less
> throughput than what your ISP is telling you. I am also
> not against a generic change as long as it is non-intrusive because i
> believe this is a practical issue and Patrick Mchardy says he can
> deliver such a patch.

I have read your throughput versus goodput thing a couple of
times, and I'm sorry - I don't understand.  What is it you
would like us to achieve?

As for the patch being invasive, it changes 37 lines of 
kernel code.  No other suggestion I have seen here will be 
that small.

If making the patch generic, ie allowing it to handle cell 
sizes other than ATM, then let me know I will make the
change on the weekend.  It is just a user space change.

One final point: if you are happy with an invasive patch that
changes the world, I have a suggestion.  Modularise the rate
calculation function.  We have qdisc modules, filter modules
and whatnot - so add another type.  Rate calculation.  The
current system can become the default rate calculation module
if none is specified.  Patrick can have his system, and Alan
can have his.  And we can add an ATM one.  If you wish, I can
(with Jespers help, I hope) re-do the patch in that style,
producing the default one and an ATM one.  My personal
preference though would be to put this patch in, and then
let this new idea stand or fall on its own merits.


^ permalink raw reply

* Re: [RFC] sysfs + configfs on 802.11 wireless drivers
From: John W. Linville @ 2006-06-23 12:47 UTC (permalink / raw)
  To: Dan Williams; +Cc: Luis R. Rodriguez, netdev, Greg KH
In-Reply-To: <1151063447.2473.6.camel@localhost.localdomain>

On Fri, Jun 23, 2006 at 07:50:47AM -0400, Dan Williams wrote:

> Our effort is probably better spent elsewhere, especially since many
> popular userspace tools already handle resume for us just fine.  More
> useful to have drivers just come back from resume in an initialized
> state similar to system boot.

I think Dan makes a lot of sense here.  Does anyone disagree?

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply

* [PATCH 0/5] d80211: pull request - fragmentation, fixes
From: Jiri Benc @ 2006-06-23 13:01 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

Please pull from
git://git.kernel.org/pub/scm/linux/kernel/git/jbenc/dscape.git master
to obtain following patches:

Jiri Benc:
      d80211: update tx.skb after TX handler calls
      d80211: per-queue TX flow control
      d80211: handle full queue when sending fragments
      d80211: add first_fragment flag to ieee80211_tx_control

Michael Buesch:
      d80211: allow NULL for control in beacon_get

 include/net/d80211.h     |   32 +++++
 net/d80211/ieee80211.c   |  293 ++++++++++++++++++++++++++++++++++++----------
 net/d80211/ieee80211_i.h |   20 +++
 net/d80211/wme.c         |    9 +
 4 files changed, 285 insertions(+), 69 deletions(-)


-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* [PATCH 1/5] d80211: update tx.skb after TX handler calls
From: Jiri Benc @ 2006-06-23 13:01 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev
In-Reply-To: <20060623150047.368594000.midnight@suse.cz>

TX and RX handlers are allowed to change skb. Fix (hopefully) the last place
where this is not taken into account.

This is similar to e81b1bc0f272a50458ab6ae8777f6327af0248e5.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 net/d80211/ieee80211.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

9372ebe184ff953be4f9d05b029477a57dd43bbd
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index a8ca8d1..944b89f 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1760,6 +1760,7 @@ ieee80211_get_buffered_bc(struct net_dev
 			break;
 	}
 	dev_put(tx.dev);
+	skb = tx.skb; /* handlers are allowed to change skb */
 
 	if (res == TXRX_DROP) {
 		I802_DEBUG_INC(local->tx_handlers_drop);
-- 
1.3.0


^ permalink raw reply related

* [PATCH 2/5] d80211: per-queue TX flow control
From: Jiri Benc @ 2006-06-23 13:01 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev
In-Reply-To: <20060623150047.368594000.midnight@suse.cz>

Currently, before a packet is passed to the driver, the driver is asked
about status of its TX queues (i.e. how many packets are queued in each
queue and how large are queues).

This is different from the way generic networking works in Linux and it
doesn't allow easy implementation of resubmitting fragments to the driver
when the queue gets filled up during transmitting.

This patch changes the stack not to ask driver about queue status but
require driver to do TX flow control.

Please note that this breaks drivers.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 include/net/d80211.h     |   30 ++++++++++++++++++++++++++++++
 net/d80211/ieee80211.c   |   27 +++++++++++++++++++++++++++
 net/d80211/ieee80211_i.h |    6 ++++++
 net/d80211/wme.c         |    6 +-----
 4 files changed, 64 insertions(+), 5 deletions(-)

39ee8c857aff2f97fb8c27cee2ee9001833f5a2b
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 4bdbdbe..141f776 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -781,6 +781,7 @@ int ieee80211_get_hdrlen(u16 fc);
  * netdevices for each hardware device. The low-level driver does not "see"
  * these interfaces, so it should use this function to perform netif
  * operations on all interface. */
+/* This function is deprecated. */
 typedef enum {
 	NETIF_ATTACH, NETIF_DETACH, NETIF_START, NETIF_STOP, NETIF_WAKE,
 	NETIF_IS_STOPPED, NETIF_UPDATE_TX_START
@@ -788,6 +789,35 @@ typedef enum {
 int ieee80211_netif_oper(struct net_device *dev, Netif_Oper op);
 
 /**
+ * ieee80211_wake_queue - wake specific queue
+ * @dev: pointer to &struct net_device as obtained from
+ *	ieee80211_alloc_hw().
+ * @queue: queue number (counted from zero).
+ *
+ * Drivers should use this function instead of netif_wake_queue.
+ */
+void ieee80211_wake_queue(struct net_device *dev, int queue);
+
+/**
+ * ieee80211_stop_queue - stop specific queue
+ * @dev: pointer to &struct net_device as obtained from
+ *	ieee80211_alloc_hw().
+ * @queue: queue number (counted from zero).
+ *
+ * Drivers should use this function instead of netif_stop_queue.
+ */
+void ieee80211_stop_queue(struct net_device *dev, int queue);
+
+/**
+ * ieee80211_start_queues - start all queues
+ * @dev: pointer to &struct net_device as obtained from
+ *	ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_start_queue.
+ */
+void ieee80211_start_queues(struct net_device *dev);
+
+/**
  * ieee80211_get_mc_list_item - iteration over items in multicast list
  * @dev: pointer to &struct net_device as obtained from
  *	ieee80211_alloc_hw().
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 944b89f..65f32a8 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4421,6 +4421,30 @@ #endif
         return 0;
 }
 
+void ieee80211_wake_queue(struct net_device *dev, int queue)
+{
+	struct ieee80211_local *local = dev->ieee80211_ptr;
+
+	if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
+			       &local->state[queue]))
+		__netif_schedule(dev);
+}
+
+void ieee80211_stop_queue(struct net_device *dev, int queue)
+{
+	struct ieee80211_local *local = dev->ieee80211_ptr;
+
+	set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+}
+
+void ieee80211_start_queues(struct net_device *dev)
+{
+	struct ieee80211_local *local = dev->ieee80211_ptr;
+	int i;
+
+	for (i = 0; i < local->hw->queues; i++)
+		clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
+}
 
 void * ieee80211_dev_hw_data(struct net_device *dev)
 {
@@ -4548,6 +4572,9 @@ EXPORT_SYMBOL(ieee80211_tx_status);
 EXPORT_SYMBOL(ieee80211_beacon_get);
 EXPORT_SYMBOL(ieee80211_get_buffered_bc);
 EXPORT_SYMBOL(ieee80211_netif_oper);
+EXPORT_SYMBOL(ieee80211_wake_queue);
+EXPORT_SYMBOL(ieee80211_stop_queue);
+EXPORT_SYMBOL(ieee80211_start_queues);
 EXPORT_SYMBOL(ieee80211_dev_hw_data);
 EXPORT_SYMBOL(ieee80211_dev_stats);
 EXPORT_SYMBOL(ieee80211_get_hw_conf);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index c1d7422..722860c 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -353,6 +353,8 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
 	struct sta_info *sta_hash[STA_HASH_SIZE];
 	struct timer_list sta_cleanup;
 
+	unsigned long state[NUM_TX_DATA_QUEUES];
+
 	int mc_count;	/* total count of multicast entries in all interfaces */
 	int iff_allmultis, iff_promiscs;
 			/* number of interfaces with corresponding IFF_ flags */
@@ -514,6 +516,10 @@ #endif /* CONFIG_D80211_DEBUG_COUNTERS *
 	int user_space_mlme;
 };
 
+enum ieee80211_link_state_t {
+	IEEE80211_LINK_STATE_XOFF = 0,
+};
+
 struct sta_attribute {
 	struct attribute attr;
 	ssize_t (*show)(const struct sta_info *, char *buf);
diff --git a/net/d80211/wme.c b/net/d80211/wme.c
index 138f892..87437cc 100644
--- a/net/d80211/wme.c
+++ b/net/d80211/wme.c
@@ -316,18 +316,14 @@ static struct sk_buff *wme_qdiscop_deque
 	struct net_device *dev = qd->dev;
 	struct ieee80211_local *local = dev->ieee80211_ptr;
 	struct ieee80211_hw *hw = local->hw;
-	struct ieee80211_tx_queue_stats stats;
 	struct sk_buff *skb;
 	struct Qdisc *qdisc;
 	int queue;
 
-	/* find which hardware queues have space in them */
-	hw->get_tx_stats(dev, &stats);
-
 	/* check all the h/w queues in numeric/priority order */
 	for (queue = 0; queue < hw->queues; queue++) {
 		/* see if there is room in this hardware queue */
-		if (stats.data[queue].len >= stats.data[queue].limit)
+		if (test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]))
 			continue;
 
 		/* there is space - try and get a frame */
-- 
1.3.0


^ permalink raw reply related

* [PATCH 3/5] d80211: handle full queue when sending fragments
From: Jiri Benc @ 2006-06-23 13:01 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev
In-Reply-To: <20060623150047.368594000.midnight@suse.cz>

When the queue gets filled up while sending fragments, do not discard the
frame.

Partially sent frames are stored in a buffer in ieee80211_local (there is
place for one frame for each queue there). When the space in hw queue gets
available again, stored frame for that queue is sent first.

Also, the case when driver returns NETDEV_TX_BUSY is handled properly now.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 net/d80211/ieee80211.c   |  227 ++++++++++++++++++++++++++++++++++++----------
 net/d80211/ieee80211_i.h |   14 +++
 net/d80211/wme.c         |    5 +
 3 files changed, 198 insertions(+), 48 deletions(-)

975a964398a0beb665747691350282b0a0b809c1
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 65f32a8..0f01311 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1153,6 +1153,74 @@ static void inline ieee80211_tx_prepare(
 	__ieee80211_tx_prepare(tx, skb, dev, control);
 }
 
+static inline int __ieee80211_queue_stopped(struct ieee80211_local *local,
+					    int queue)
+{
+	return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+}
+
+static inline int __ieee80211_queue_pending(struct ieee80211_local *local,
+					    int queue)
+{
+	return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]);
+}
+
+#define IEEE80211_TX_OK		0
+#define IEEE80211_TX_AGAIN	1
+#define IEEE80211_TX_FRAG_AGAIN	2
+
+static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
+			  struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_tx_control *control = tx->u.tx.control;
+	int ret, i;
+
+	if (skb) {
+		ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb);
+		ret = local->hw->tx(local->mdev, skb, control);
+		if (ret)
+			return IEEE80211_TX_AGAIN;
+#ifdef IEEE80211_LEDS
+		if (local->tx_led_counter++ == 0) {
+			ieee80211_tx_led(1, local->mdev);
+		}
+#endif /* IEEE80211_LEDS */
+	}
+	if (tx->u.tx.extra_frag) {
+		control->use_rts_cts = 0;
+		control->use_cts_protect = 0;
+		control->clear_dst_mask = 0;
+		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			if (!tx->u.tx.extra_frag[i])
+				continue;
+			if (__ieee80211_queue_stopped(local, control->queue))
+				return IEEE80211_TX_FRAG_AGAIN;
+			if (i == tx->u.tx.num_extra_frag) {
+				control->tx_rate = tx->u.tx.last_frag_hwrate;
+				control->rateidx = tx->u.tx.last_frag_rateidx;
+				control->rate_ctrl_probe =
+					tx->u.tx.probe_last_frag;
+			}
+
+			ieee80211_dump_frame(local->mdev->name,
+					     "TX to low-level driver", skb);
+			ret = local->hw->tx(local->mdev, tx->u.tx.extra_frag[i],
+					    control);
+			if (ret)
+				return IEEE80211_TX_FRAG_AGAIN;
+#ifdef IEEE80211_LEDS
+			if (local->tx_led_counter++ == 0) {
+				ieee80211_tx_led(1, local->mdev);
+			}
+#endif /* IEEE80211_LEDS */
+			tx->u.tx.extra_frag[i] = NULL;
+		}
+		kfree(tx->u.tx.extra_frag);
+		tx->u.tx.extra_frag = NULL;
+	}
+	return IEEE80211_TX_OK;
+}
+
 static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 			struct ieee80211_tx_control *control, int mgmt)
 {
@@ -1163,6 +1231,8 @@ static int ieee80211_tx(struct net_devic
 	ieee80211_txrx_result res = TXRX_DROP;
         int ret, i;
 
+	WARN_ON(__ieee80211_queue_pending(local, control->queue));
+
 	if (unlikely(skb->len < 10)) {
 		dev_kfree_skb(skb);
 		return 0;
@@ -1193,65 +1263,60 @@ static int ieee80211_tx(struct net_devic
 		return 0;
 	}
 
-	ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb);
-	ret = local->hw->tx(local->mdev, skb, control);
-#ifdef IEEE80211_LEDS
-	if (!ret && local->tx_led_counter++ == 0) {
-                ieee80211_tx_led(1, dev);
-        }
-#endif /* IEEE80211_LEDS */
 	if (tx.u.tx.extra_frag) {
-		if (ret > 0) {
-			/* Must free all fragments and return 0 since skb data
-			 * has been fragmented into multiple buffers.
-			 * TODO: could free extra fragments and restore skb to
-			 * the original form since the data is still there and
-			 * then return nonzero so that Linux netif would
-			 * retry. */
-			goto drop;
-		}
-
-		skb = NULL; /* skb is now owned by low-level driver */
-		control->use_rts_cts = 0;
-		control->use_cts_protect = 0;
-		control->clear_dst_mask = 0;
 		for (i = 0; i < tx.u.tx.num_extra_frag; i++) {
 			int next_len, dur;
 			struct ieee80211_hdr *hdr =
 				(struct ieee80211_hdr *)
 				tx.u.tx.extra_frag[i]->data;
-			if (i + 1 < tx.u.tx.num_extra_frag)
+
+			if (i + 1 < tx.u.tx.num_extra_frag) {
 				next_len = tx.u.tx.extra_frag[i + 1]->len;
-			else {
+			} else {
 				next_len = 0;
 				tx.u.tx.rate = tx.u.tx.last_frag_rate;
-				tx.u.tx.control->tx_rate = tx.u.tx.rate->val;
-				tx.u.tx.control->rateidx =
-					tx.u.tx.last_frag_rateidx;
-				tx.u.tx.control->rate_ctrl_probe =
-					tx.u.tx.probe_last_frag;
+				tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val;
 			}
 			dur = ieee80211_duration(&tx, 0, next_len);
 			hdr->duration_id = cpu_to_le16(dur);
+		}
+	}
 
-			ieee80211_dump_frame(local->mdev->name,
-					     "TX to low-level driver", skb);
-			ret = local->hw->tx(local->mdev, tx.u.tx.extra_frag[i],
-					    control);
-			if (ret > 0)
-				goto drop;
-#ifdef IEEE80211_LEDS
-			if (local->tx_led_counter++ == 0) {
-                                ieee80211_tx_led(1, dev);
-                        }
-#endif /* IEEE80211_LEDS */
-			tx.u.tx.extra_frag[i] = NULL;
+retry:
+	ret = __ieee80211_tx(local, skb, &tx);
+	if (ret) {
+		struct ieee80211_tx_stored_packet *store =
+			&local->pending_packet[control->queue];
+
+		if (ret == IEEE80211_TX_FRAG_AGAIN)
+			skb = NULL;
+		set_bit(IEEE80211_LINK_STATE_PENDING,
+			&local->state[control->queue]);
+		smp_mb();
+		/* When the driver gets out of buffers during sending of
+		 * fragments and calls ieee80211_stop_queue, there is
+		 * a small window between IEEE80211_LINK_STATE_XOFF and
+		 * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer
+		 * gets available in that window (i.e. driver calls
+		 * ieee80211_wake_queue), we would end up with ieee80211_tx
+		 * called with IEEE80211_LINK_STATE_PENDING. Prevent this by
+		 * continuing transmitting here when that situation is
+		 * possible to have happened. */
+		if (!__ieee80211_queue_stopped(local, control->queue)) {
+			clear_bit(IEEE80211_LINK_STATE_PENDING,
+				  &local->state[control->queue]);
+			goto retry;
 		}
-		kfree(tx.u.tx.extra_frag);
-        }
-        if (ret == -1)
-		ret = 0;
-	return ret;
+		memcpy(&store->control, control,
+		       sizeof(struct ieee80211_tx_control));
+		store->skb = skb;
+		store->extra_frag = tx.u.tx.extra_frag;
+		store->num_extra_frag = tx.u.tx.num_extra_frag;
+		store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
+		store->last_frag_rateidx = tx.u.tx.last_frag_rateidx;
+		store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag;
+	}
+	return 0;
 
  drop:
 	if (skb)
@@ -1263,6 +1328,62 @@ #endif /* IEEE80211_LEDS */
 	return 0;
 }
 
+static void ieee80211_tx_pending(unsigned long data)
+{
+	struct ieee80211_local *local = (struct ieee80211_local *)data;
+	struct net_device *dev = local->mdev;
+	struct ieee80211_tx_stored_packet *store;
+	struct ieee80211_txrx_data tx;
+	int i, ret, reschedule = 0;
+
+	spin_lock_bh(&dev->xmit_lock);
+	dev->xmit_lock_owner = smp_processor_id();
+	for (i = 0; i < local->hw->queues; i++) {
+		if (__ieee80211_queue_stopped(local, i))
+			continue;
+		if (!__ieee80211_queue_pending(local, i)) {
+			reschedule = 1;
+			continue;
+		}
+		store = &local->pending_packet[i];
+		tx.u.tx.control = &store->control;
+		tx.u.tx.extra_frag = store->extra_frag;
+		tx.u.tx.num_extra_frag = store->num_extra_frag;
+		tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
+		tx.u.tx.last_frag_rateidx = store->last_frag_rateidx;
+		tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe;
+		ret = __ieee80211_tx(local, store->skb, &tx);
+		if (ret) {
+			if (ret == IEEE80211_TX_FRAG_AGAIN)
+				store->skb = NULL;
+		} else {
+			clear_bit(IEEE80211_LINK_STATE_PENDING,
+				  &local->state[i]);
+			reschedule = 1;
+		}
+	}
+	dev->xmit_lock_owner = -1;
+	spin_unlock_bh(&dev->xmit_lock);
+	if (reschedule)
+		netif_schedule(dev);
+}
+
+static void ieee80211_clear_tx_pending(struct ieee80211_local *local)
+{
+	int i, j;
+	struct ieee80211_tx_stored_packet *store;
+
+	for (i = 0; i < local->hw->queues; i++) {
+		if (!__ieee80211_queue_pending(local, i))
+			continue;
+		store = &local->pending_packet[i];
+		kfree_skb(store->skb);
+		for (j = 0; j < store->num_extra_frag; j++)
+			kfree_skb(store->extra_frag[j]);
+		kfree(store->extra_frag);
+		clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]);
+	}
+}
 
 static int ieee80211_master_start_xmit(struct sk_buff *skb,
 				       struct net_device *dev)
@@ -1999,6 +2120,7 @@ static int ieee80211_master_open(struct 
 	list_for_each_entry(sdata, &local->sub_if_list, list) {
 		if (sdata->dev != dev && netif_running(sdata->dev)) {
 			res = 0;
+			tasklet_enable(&local->tx_pending_tasklet);
 			break;
 		}
 	}
@@ -2010,6 +2132,7 @@ static int ieee80211_master_stop(struct 
 	struct ieee80211_local *local = dev->ieee80211_ptr;
 	struct ieee80211_sub_if_data *sdata;
 
+	tasklet_disable(&local->tx_pending_tasklet);
 	list_for_each_entry(sdata, &local->sub_if_list, list) {
 		if (sdata->dev != dev && netif_running(sdata->dev))
 			return -EOPNOTSUPP;
@@ -4175,6 +4298,10 @@ struct net_device *ieee80211_alloc_hw(si
         sdata->local = local;
         list_add_tail(&sdata->list, &local->sub_if_list);
 
+	tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
+		     (unsigned long)local);
+	tasklet_disable(&local->tx_pending_tasklet);
+
         tasklet_init(&local->tasklet,
 		     ieee80211_tasklet_handler,
 		     (unsigned long) local);
@@ -4344,6 +4471,7 @@ void ieee80211_unregister_hw(struct net_
 	}
 	rtnl_unlock();
 
+	ieee80211_clear_tx_pending(local);
 	sta_info_stop(local);
 	rate_control_remove_attrs(local, local->rate_ctrl_priv,
 				  &local->class_dev.kobj);
@@ -4426,8 +4554,13 @@ void ieee80211_wake_queue(struct net_dev
 	struct ieee80211_local *local = dev->ieee80211_ptr;
 
 	if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
-			       &local->state[queue]))
-		__netif_schedule(dev);
+			       &local->state[queue])) {
+		if (test_bit(IEEE80211_LINK_STATE_PENDING,
+			     &local->state[queue]))
+			tasklet_schedule(&local->tx_pending_tasklet);
+		else
+			__netif_schedule(dev);
+	}
 }
 
 void ieee80211_stop_queue(struct net_device *dev, int queue)
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 722860c..0409c52 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -125,6 +125,7 @@ struct ieee80211_txrx_data {
 			 * when using CTS protection with IEEE 802.11g. */
 			struct ieee80211_rate *last_frag_rate;
 			int last_frag_rateidx;
+			int last_frag_hwrate;
 			int mgmt_interface;
 
 			/* Extra fragments (in addition to the first fragment
@@ -155,6 +156,16 @@ struct ieee80211_tx_packet_data {
 	unsigned int mgmt_iface:1;
 };
 
+struct ieee80211_tx_stored_packet {
+	struct ieee80211_tx_control control;
+	struct sk_buff *skb;
+	int num_extra_frag;
+	struct sk_buff **extra_frag;
+	int last_frag_rateidx;
+	int last_frag_hwrate;
+	unsigned int last_frag_rate_ctrl_probe:1;
+};
+
 struct ieee80211_passive_scan {
         unsigned int in_scan:1; /* this must be cleared before calling
 				 * netif_oper(WAKEUP) */
@@ -354,6 +365,8 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
 	struct timer_list sta_cleanup;
 
 	unsigned long state[NUM_TX_DATA_QUEUES];
+	struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
+	struct tasklet_struct tx_pending_tasklet;
 
 	int mc_count;	/* total count of multicast entries in all interfaces */
 	int iff_allmultis, iff_promiscs;
@@ -518,6 +531,7 @@ #endif /* CONFIG_D80211_DEBUG_COUNTERS *
 
 enum ieee80211_link_state_t {
 	IEEE80211_LINK_STATE_XOFF = 0,
+	IEEE80211_LINK_STATE_PENDING,
 };
 
 struct sta_attribute {
diff --git a/net/d80211/wme.c b/net/d80211/wme.c
index 87437cc..76de062 100644
--- a/net/d80211/wme.c
+++ b/net/d80211/wme.c
@@ -323,7 +323,10 @@ static struct sk_buff *wme_qdiscop_deque
 	/* check all the h/w queues in numeric/priority order */
 	for (queue = 0; queue < hw->queues; queue++) {
 		/* see if there is room in this hardware queue */
-		if (test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]))
+		if (test_bit(IEEE80211_LINK_STATE_XOFF,
+			     &local->state[queue]) ||
+		    test_bit(IEEE80211_LINK_STATE_PENDING,
+			     &local->state[queue]))
 			continue;
 
 		/* there is space - try and get a frame */
-- 
1.3.0


^ permalink raw reply related

* [PATCH 4/5] d80211: add first_fragment flag to ieee80211_tx_control
From: Jiri Benc @ 2006-06-23 13:01 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev
In-Reply-To: <20060623150047.368594000.midnight@suse.cz>

If a driver needs to find out if the fragment it is supposed to pass to the
hardware is the first fragment, the only way to do this is to check if
a Fragment Number part of seq_ctrl field in the frame header equals to 0.
Let's make it easier.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 include/net/d80211.h   |    2 ++
 net/d80211/ieee80211.c |    2 ++
 2 files changed, 4 insertions(+), 0 deletions(-)

e360f2605cbb71f359de21a59eff1bcbab150e7f
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 141f776..6ae4325 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -158,6 +158,8 @@ struct ieee80211_tx_control {
 	unsigned int rate_ctrl_probe:1;
 	unsigned int clear_dst_mask:1;
 	unsigned int requeue:1;
+	unsigned int first_fragment:1;	/* This is a first fragment of the
+					 * frame */
 	 /* following three flags are only used with Atheros Super A/G */
 	unsigned int compress:1;
 	unsigned int turbo_prime_notify:1; /* notify HostaAPd after frame
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 0f01311..9fc3518 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1120,6 +1120,7 @@ __ieee80211_tx_prepare(struct ieee80211_
 		u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
 		tx->ethertype = (pos[0] << 8) | pos[1];
 	}
+	control->first_fragment = 1;
 
 }
 
@@ -1190,6 +1191,7 @@ #endif /* IEEE80211_LEDS */
 		control->use_rts_cts = 0;
 		control->use_cts_protect = 0;
 		control->clear_dst_mask = 0;
+		control->first_fragment = 0;
 		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
 			if (!tx->u.tx.extra_frag[i])
 				continue;
-- 
1.3.0


^ permalink raw reply related

* [PATCH 5/5] d80211: allow NULL for control in beacon_get
From: Jiri Benc @ 2006-06-23 13:01 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev
In-Reply-To: <20060623150047.368594000.midnight@suse.cz>

From: Michael Buesch <mb@bu3sch.de>

bcm43xx has no use for the "control" data provided by
ieee80211_beacon_get(), so allow passing a NULL pointer
to avoid setting up a dummy struct and throwing the data
away afterwards in the driver.

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 net/d80211/ieee80211.c |   40 +++++++++++++++++++++-------------------
 1 files changed, 21 insertions(+), 19 deletions(-)

634f9d6f4bbafbcf218ac303087a0e83c5c95cda
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 9fc3518..ffb0f18 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1806,28 +1806,30 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
 		memcpy(skb_put(skb, bt_len), b_tail, bt_len);
 	}
 
-	memset(&extra, 0, sizeof(extra));
-	extra.endidx = local->num_curr_rates;
+	if (control) {
+		memset(&extra, 0, sizeof(extra));
+		extra.endidx = local->num_curr_rates;
 
-	rate = rate_control_get_rate(dev, skb, &extra);
-	if (rate == NULL) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
-			       "found\n", dev->name);
+		rate = rate_control_get_rate(dev, skb, &extra);
+		if (rate == NULL) {
+			if (net_ratelimit()) {
+				printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
+				       "found\n", dev->name);
+			}
+			dev_kfree_skb(skb);
+			return NULL;
 		}
-		dev_kfree_skb(skb);
-		return NULL;
-	}
 
-	control->tx_rate = (local->short_preamble &&
-			    (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-		rate->val2 : rate->val;
-	control->antenna_sel = local->conf.antenna_sel;
-	control->power_level = local->conf.power_level;
-	control->no_ack = 1;
-	control->retry_limit = 1;
-	control->rts_cts_duration = 0;
-	control->clear_dst_mask = 1;
+		control->tx_rate = (local->short_preamble &&
+				    (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+			rate->val2 : rate->val;
+		control->antenna_sel = local->conf.antenna_sel;
+		control->power_level = local->conf.power_level;
+		control->no_ack = 1;
+		control->retry_limit = 1;
+		control->rts_cts_duration = 0;
+		control->clear_dst_mask = 1;
+	}
 
 	ap->num_beacons++;
 	return skb;
-- 
1.3.0


^ permalink raw reply related

* [PATCH 0/3] d80211 drivers: fixes for last d80211 patches
From: Jiri Benc @ 2006-06-23 13:09 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

These are fixes for d80211 drivers to work after last d80211 patches. Note
that bcm43xx-d80211 TX flow patch is still incomplete.

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* [PATCH 1/3] rt2x00: per-queue TX flow control
From: Jiri Benc @ 2006-06-23 13:09 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev
In-Reply-To: <20060623150913.986994000.midnight@suse.cz>

From: Ivo van Doorn <ivdoorn@gmail.com>

Based on Jiri's patch for rt2x00 driver to do TX flow control.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

diff --git a/drivers/net/wireless/d80211/rt2x00/rt2400pci.c b/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
index 8b856dd..946cf86 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
@@ -1002,6 +1002,12 @@ rt2400pci_txdone(void *data)
 	struct txd		*txd;
 	int			tx_status;
 	int			ack;
+	int			ring_full;
+
+	/*
+	 * Store the current status of the ring.
+	 */
+	ring_full = rt2x00_ring_full(ring);
 
 	while (!rt2x00_ring_empty(ring)) {
 		entry = rt2x00_get_data_entry_done(ring);
@@ -1062,6 +1068,16 @@ rt2400pci_txdone(void *data)
 		rt2x00pci->scan->status = SCANNING_READY;
 		complete(&rt2x00pci->scan->completion);
 	}
+
+	/*
+	 * If the data ring was full before the txdone handler
+	 * we must make sure the packet queue in the d80211 stack
+	 * is reenabled when the txdone handler has finished.
+	 */
+	entry = ring->entry;
+	if (ring_full && !rt2x00_ring_full(ring))
+		ieee80211_wake_queue(ring->net_dev,
+			entry->tx_status.control.queue);
 }
 
 static irqreturn_t
@@ -1541,18 +1557,26 @@ rt2400pci_tx(struct net_device *net_dev,
 		ERROR("Attempt to send packet over invalid queue %d.\n"
 			"Please file bug report to %s.\n",
 			control->queue, DRV_PROJECT);
-		return NET_XMIT_DROP;
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
 	}
 
-	if (rt2x00_ring_full(ring))
-		return NET_XMIT_DROP;
+	if (rt2x00_ring_full(ring)) {
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
 
 	entry = rt2x00_get_data_entry(ring);
 	txd = entry->desc_addr;
 
 	if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC)
-	|| rt2x00_get_field32(txd->word0, TXD_W0_VALID))
-		return NET_XMIT_DROP;
+	|| rt2x00_get_field32(txd->word0, TXD_W0_VALID)) {
+		ERROR("Arrived at non-free entry in the non-full queue %d.\n"
+			"Please file bug report to %s.\n",
+			control->queue, DRV_PROJECT);
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
 
 	memcpy(entry->data_addr, skb->data, skb->len);
 	rt2400pci_write_tx_desc(rt2x00pci, txd, skb, control);
@@ -1560,6 +1584,9 @@ rt2400pci_tx(struct net_device *net_dev,
 
 	rt2x00_ring_index_inc(ring);
 
+	if (rt2x00_ring_full(ring))
+		ieee80211_stop_queue(net_dev, control->queue);
+
 	rt2x00_register_read(rt2x00pci, TXCSR0, &reg);
 	if (control->queue == IEEE80211_TX_QUEUE_DATA0)
 		rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
@@ -1569,7 +1596,7 @@ rt2400pci_tx(struct net_device *net_dev,
 		rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
 	rt2x00_register_write(rt2x00pci, TXCSR0, reg);
 
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 static int
@@ -1669,6 +1696,8 @@ rt2400pci_open(struct net_device *net_de
 
 	SET_FLAG(rt2x00pci, RADIO_ENABLED);
 
+	ieee80211_start_queues(net_dev);
+
 	return 0;
 
 exit_fail:
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2500pci.c b/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
index 6aeaf1a..ca0edd5 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
@@ -1090,6 +1090,12 @@ rt2500pci_txdone(void *data)
 	struct txd		*txd;
 	int			tx_status;
 	int			ack;
+	int			ring_full;
+
+	/*
+	 * Store the current status of the ring.
+	 */
+	ring_full = rt2x00_ring_full(ring);
 
 	while (!rt2x00_ring_empty(ring)) {
 		entry = rt2x00_get_data_entry_done(ring);
@@ -1150,6 +1156,16 @@ rt2500pci_txdone(void *data)
 		rt2x00pci->scan->status = SCANNING_READY;
 		complete(&rt2x00pci->scan->completion);
 	}
+
+	/*
+	 * If the data ring was full before the txdone handler
+	 * we must make sure the packet queue in the d80211 stack
+	 * is reenabled when the txdone handler has finished.
+	 */
+	entry = ring->entry;
+	if (ring_full && !rt2x00_ring_full(ring))
+		ieee80211_wake_queue(ring->net_dev,
+			entry->tx_status.control.queue);
 }
 
 static irqreturn_t
@@ -1664,18 +1680,26 @@ rt2500pci_tx(struct net_device *net_dev,
 		ERROR("Attempt to send packet over invalid queue %d.\n"
 			"Please file bug report to %s.\n",
 			control->queue, DRV_PROJECT);
-		return NET_XMIT_DROP;
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
 	}
 
-	if (rt2x00_ring_full(ring))
-		return NET_XMIT_DROP;
+	if (rt2x00_ring_full(ring)) {
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
 
 	entry = rt2x00_get_data_entry(ring);
 	txd = entry->desc_addr;
 
 	if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC)
-	|| rt2x00_get_field32(txd->word0, TXD_W0_VALID))
-		return NET_XMIT_DROP;
+	|| rt2x00_get_field32(txd->word0, TXD_W0_VALID)) {
+		ERROR("Arrived at non-free entry in the non-full queue %d.\n"
+			"Please file bug report to %s.\n",
+			control->queue, DRV_PROJECT);
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
 
 	memcpy(entry->data_addr, skb->data, skb->len);
 	rt2500pci_write_tx_desc(rt2x00pci, txd, skb, control);
@@ -1683,6 +1707,9 @@ rt2500pci_tx(struct net_device *net_dev,
 
 	rt2x00_ring_index_inc(ring);
 
+	if (rt2x00_ring_full(ring))
+		ieee80211_stop_queue(net_dev, control->queue);
+
 	rt2x00_register_read(rt2x00pci, TXCSR0, &reg);
 	if (control->queue == IEEE80211_TX_QUEUE_DATA0)
 		rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
@@ -1692,7 +1719,7 @@ rt2500pci_tx(struct net_device *net_dev,
 		rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
 	rt2x00_register_write(rt2x00pci, TXCSR0, reg);
 
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 static int
@@ -1792,6 +1819,8 @@ rt2500pci_open(struct net_device *net_de
 
 	SET_FLAG(rt2x00pci, RADIO_ENABLED);
 
+	ieee80211_start_queues(net_dev);
+
 	return 0;
 
 exit_fail:
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2500usb.c b/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
index 1193e60..76c3a68 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
@@ -930,6 +930,12 @@ rt2500usb_txdone(void *data)
 	struct data_entry	*entry;
 	struct txd		*txd;
 	int			ack;
+	int			ring_full;
+
+	/*
+	 * Store the current status of the ring.
+	 */
+	ring_full = rt2x00_ring_full(ring);
 
 	 while (!rt2x00_ring_empty(ring)) {
 		entry = rt2x00_get_data_entry_done(ring);
@@ -982,6 +988,16 @@ rt2500usb_txdone(void *data)
 		rt2x00usb->scan->status = SCANNING_READY;
 		complete(&rt2x00usb->scan->completion);
 	}
+
+	/*
+	 * If the data ring was full before the txdone handler
+	 * we must make sure the packet queue in the d80211 stack
+	 * is reenabled when the txdone handler has finished.
+	 */
+	entry = ring->entry;
+	if (ring_full && !rt2x00_ring_full(ring))
+		ieee80211_wake_queue(ring->net_dev,
+			entry->tx_status.control.queue);
 }
 
 static void
@@ -1376,15 +1392,26 @@ rt2500usb_tx(struct net_device *net_dev,
 		ERROR("Attempt to send packet over invalid queue %d.\n"
 			"Please file bug report to %s.\n",
 			control->queue, DRV_PROJECT);
-		return NET_XMIT_DROP;
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
 	}
 
-	if (rt2x00_ring_full(ring))
-		return NET_XMIT_DROP;
+	if (rt2x00_ring_full(ring)) {
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
 
 	entry = rt2x00_get_data_entry(ring);
 	txd = rt2x00usb_txdesc_addr(entry);
 
+	if (GET_FLAG(entry, ENTRY_OWNER_NIC)) {
+		ERROR("Arrived at non-free entry in the non-full queue %d.\n"
+			"Please file bug report to %s.\n",
+			control->queue, DRV_PROJECT);
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
+
 	memcpy(rt2x00usb_txdata_addr(entry), skb->data, skb->len);
 	rt2500usb_write_tx_desc(rt2x00usb, txd, skb, control);
 	entry->skb = skb;
@@ -1402,7 +1429,10 @@ rt2500usb_tx(struct net_device *net_dev,
 
 	rt2x00_ring_index_inc(ring);
 
-	return 0;
+	if (rt2x00_ring_full(ring))
+		ieee80211_stop_queue(net_dev, control->queue);
+
+	return NETDEV_TX_OK;
 }
 
 static inline void
@@ -1469,6 +1499,8 @@ rt2500usb_open(struct net_device *net_de
 
 	SET_FLAG(rt2x00usb, RADIO_ENABLED);
 
+	ieee80211_start_queues(net_dev);
+
 	return 0;
 
 exit_fail:
diff --git a/drivers/net/wireless/d80211/rt2x00/rt61pci.c b/drivers/net/wireless/d80211/rt2x00/rt61pci.c
index fdbfa60..0799f9f 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt61pci.c
@@ -1353,6 +1353,12 @@ rt61pci_txdone(void *data)
 	int			tx_status;
 	int			ack;
 	int			reg;
+	int			ring_full;
+
+	/*
+	 * Store the current status of the ring.
+	 */
+	ring_full = rt2x00_ring_full(ring);
 
 	while (!rt2x00_ring_empty(ring)) {
 		entry = rt2x00_get_data_entry_done(ring);
@@ -1418,6 +1424,16 @@ rt61pci_txdone(void *data)
 		rt2x00pci->scan->status = SCANNING_READY;
 		complete(&rt2x00pci->scan->completion);
 	}
+
+	/*
+	 * If the data ring was full before the txdone handler
+	 * we must make sure the packet queue in the d80211 stack
+	 * is reenabled when the txdone handler has finished.
+	 */
+	entry = ring->entry;
+	if (ring_full && !rt2x00_ring_full(ring))
+		ieee80211_wake_queue(ring->net_dev,
+			entry->tx_status.control.queue);
 }
 
 static irqreturn_t
@@ -2100,18 +2116,26 @@ rt61pci_tx(struct net_device *net_dev,
 		ERROR("Attempt to send packet over invalid queue %d.\n"
 			"Please file bug report to %s.\n",
 			control->queue, DRV_PROJECT);
-		return NET_XMIT_DROP;
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
 	}
 
-	if (rt2x00_ring_full(ring))
-		return NET_XMIT_DROP;
+	if (rt2x00_ring_full(ring)) {
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
 
 	entry = rt2x00_get_data_entry(ring);
 	txd = entry->desc_addr;
 
 	if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC)
-	|| rt2x00_get_field32(txd->word0, TXD_W0_VALID))
-		return NET_XMIT_DROP;
+	|| rt2x00_get_field32(txd->word0, TXD_W0_VALID)) {
+		ERROR("Arrived at non-free entry in the non-full queue %d.\n"
+			"Please file bug report to %s.\n",
+			control->queue, DRV_PROJECT);
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
 
 	memcpy(entry->data_addr, skb->data, skb->len);
 	rt61pci_write_tx_desc(rt2x00pci, txd, skb, control);
@@ -2119,6 +2143,9 @@ rt61pci_tx(struct net_device *net_dev,
 
 	rt2x00_ring_index_inc(ring);
 
+	if (rt2x00_ring_full(ring))
+		ieee80211_stop_queue(net_dev, control->queue);
+
 	rt2x00_register_read(rt2x00pci, TX_CNTL_CSR, &reg);
 	if (control->queue == IEEE80211_TX_QUEUE_DATA0)
 		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
@@ -2132,7 +2159,7 @@ rt61pci_tx(struct net_device *net_dev,
 		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_MGMT, 1);
 	rt2x00_register_write(rt2x00pci, TX_CNTL_CSR, reg);
 
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 static int
@@ -2249,6 +2276,8 @@ rt61pci_open(struct net_device *net_dev)
 
 	SET_FLAG(rt2x00pci, RADIO_ENABLED);
 
+	ieee80211_start_queues(net_dev);
+
 	return 0;
 
 exit_fail:
diff --git a/drivers/net/wireless/d80211/rt2x00/rt73usb.c b/drivers/net/wireless/d80211/rt2x00/rt73usb.c
index 48e9917..1871204 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt73usb.c
@@ -1094,6 +1094,12 @@ rt73usb_txdone(void *data)
 	struct data_entry	*entry;
 	struct txd		*txd;
 	int			ack;
+	int			ring_full;
+
+	/*
+	 * Store the current status of the ring.
+	 */
+	ring_full = rt2x00_ring_full(ring);
 
 	while (!rt2x00_ring_empty(ring)) {
 		entry = rt2x00_get_data_entry_done(ring);
@@ -1148,6 +1154,16 @@ rt73usb_txdone(void *data)
 		rt2x00usb->scan->status = SCANNING_READY;
 		complete(&rt2x00usb->scan->completion);
 	}
+
+	/*
+	 * If the data ring was full before the txdone handler
+	 * we must make sure the packet queue in the d80211 stack
+	 * is reenabled when the txdone handler has finished.
+	 */
+	entry = ring->entry;
+	if (ring_full && !rt2x00_ring_full(ring))
+		ieee80211_wake_queue(ring->net_dev,
+			entry->tx_status.control.queue);
 }
 
 static void
@@ -1668,15 +1684,26 @@ rt73usb_tx(struct net_device *net_dev,
 		ERROR("Attempt to send packet over invalid queue %d.\n"
 			"Please file bug report to %s.\n",
 			control->queue, DRV_PROJECT);
-		return NET_XMIT_DROP;
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
 	}
 
-	if (rt2x00_ring_full(ring))
-		return NET_XMIT_DROP;
+	if (rt2x00_ring_full(ring)) {
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
 
 	entry = rt2x00_get_data_entry(ring);
 	txd = rt2x00usb_txdesc_addr(entry);
 
+	if (GET_FLAG(entry, ENTRY_OWNER_NIC)) {
+		ERROR("Arrived at non-free entry in the non-full queue %d.\n"
+			"Please file bug report to %s.\n",
+			control->queue, DRV_PROJECT);
+		ieee80211_stop_queue(net_dev, control->queue);
+		return NETDEV_TX_BUSY;
+	}
+
 	memcpy(rt2x00usb_txdata_addr(entry), skb->data, skb->len);
 	rt73usb_write_tx_desc(rt2x00usb, txd, skb, control);
 	entry->skb = skb;
@@ -1694,7 +1721,10 @@ rt73usb_tx(struct net_device *net_dev,
 
 	rt2x00_ring_index_inc(ring);
 
-	return 0;
+	if (rt2x00_ring_full(ring))
+		ieee80211_stop_queue(net_dev, control->queue);
+
+	return NETDEV_TX_OK;
 }
 
 static inline void
@@ -1766,6 +1796,8 @@ rt73usb_open(struct net_device *net_dev)
 
 	SET_FLAG(rt2x00usb, RADIO_ENABLED);
 
+	ieee80211_start_queues(net_dev);
+
 	return 0;
 
 exit_fail:


^ permalink raw reply related

* [PATCH 2/3] bcm43xx-d80211: fix sending of fragments
From: Jiri Benc @ 2006-06-23 13:09 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev
In-Reply-To: <20060623150913.986994000.midnight@suse.cz>

This makes fragmentation work with bcm43xx.

Signed-off-by: Jiri Benc <jbenc@suse.cz>
Signed-off-by: Michael Buesch <mb@bu3sch.de>

---
 drivers/net/wireless/d80211/bcm43xx/bcm43xx_dma.c |    2 +-
 drivers/net/wireless/d80211/bcm43xx/bcm43xx_pio.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

--- dscape.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_dma.c
+++ dscape/drivers/net/wireless/d80211/bcm43xx/bcm43xx_dma.c
@@ -703,7 +703,7 @@ static int dma_tx_fragment(struct bcm43x
 	bcm43xx_generate_txhdr(ring->bcm,
 			       (struct bcm43xx_txhdr *)hdr_skb->data,
 			       skb->data, skb->len,
-			       1,//FIXME
+			       ctl->first_fragment,
 			       generate_cookie(ring, slot),
 			       ctl);
 
--- dscape.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_pio.c
+++ dscape/drivers/net/wireless/d80211/bcm43xx/bcm43xx_pio.c
@@ -186,7 +186,7 @@ static void pio_tx_write_fragment(struct
 	assert(skb_shinfo(skb)->nr_frags == 0);
 	bcm43xx_generate_txhdr(queue->bcm,
 			       &txhdr, skb->data, skb->len,
-			       1,//FIXME
+			       packet->txstat.control.first_fragment,
 			       generate_cookie(queue, packet),
 			       &packet->txstat.control);
 

^ permalink raw reply

* [incomplete 3/3] bcm43xx-d80211: per-queue TX flow control
From: Jiri Benc @ 2006-06-23 13:09 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev
In-Reply-To: <20060623150913.986994000.midnight@suse.cz>

This is an attempt to fix bcm43xx driver. It is for DMA mode only and
incomplete even for that mode - ieee80211_hw->tx() callback should return
NETDEV_TX_* contants which is not completely fixed by this patch.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---
 drivers/net/wireless/d80211/bcm43xx/bcm43xx_dma.c  |    6 +++++-
 drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c |    1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

--- dscape.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_dma.c
+++ dscape/drivers/net/wireless/d80211/bcm43xx/bcm43xx_dma.c
@@ -778,13 +778,16 @@ int bcm43xx_dma_tx(struct bcm43xx_privat
 		 * recognizes if the device queue is full and does
 		 * not send data anymore.
 		 */
+		ieee80211_stop_queue(bcm->net_dev, 0);
 		printk(KERN_ERR PFX "DMA queue overflow\n");
-		return -ENOMEM;
+		return NETDEV_TX_BUSY;
 	}
 
 	err = dma_tx_fragment(ring, skb, ctl);
 	if (likely(!err))
 		ring->nr_tx_packets++;
+	if (free_slots(ring) < SLOTS_PER_PACKET)
+		ieee80211_stop_queue(bcm->net_dev, 0);
 
 	return err;
 }
@@ -833,6 +836,7 @@ void bcm43xx_dma_handle_xmitstatus(struc
 		slot = next_slot(ring, slot);
 	}
 	bcm->stats.last_tx = jiffies;
+	ieee80211_wake_queue(bcm->net_dev, 0);
 }
 
 void bcm43xx_dma_get_tx_stats(struct bcm43xx_private *bcm,
--- dscape.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
+++ dscape/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
@@ -3813,6 +3813,7 @@ static int bcm43xx_init_board(struct bcm
 	bcm43xx_security_init(bcm);
 	bcm43xx_measure_channel_change_time(bcm);
 	ieee80211_update_hw(bcm->net_dev, bcm->ieee);
+	ieee80211_start_queues(bcm->net_dev);
 	ieee80211_netif_oper(bcm->net_dev, NETIF_ATTACH);
 	ieee80211_netif_oper(bcm->net_dev, NETIF_START);
 	ieee80211_netif_oper(bcm->net_dev, NETIF_WAKE);

^ permalink raw reply

* Re: [PATCH 0/2][RFC] Network Event Notifier Mechanism
From: Steve Wise @ 2006-06-23 13:11 UTC (permalink / raw)
  To: hadi; +Cc: netdev, David Miller
In-Reply-To: <1151014488.5099.23.camel@jzny2>


> > 
> > > Out of curiosity - what does RDMA NIC have that would need these events?
> > > a route table or L2 table etc? Can you elucidate a little?
> > > 
> > 
> > Mainly the L2 table, next hop ip addr, and the path mtu.  RDMA NICs
> > implement the entire RDMA stack in HW.  How they deal with L2 and L3
> > changes vary to some degree, but what seems to be emerging is that they
> > get this information from the native stack because ARP and ICMP, for
> > example, are always passed up to the native stack.
> > 
> 
> I am still unclear: 
> You have destination IP address, the dstMAC of the nexthop to get the
> packet to this IP address and i suspect some srcMAC address you will use
> sending out as well as the pathMTU to get there correct?
> Because of the IP address it sounds to me like you are populating an L3
> table

I mispoke.  The HW I'm using really only maintains a table of next hop
mac addrs and a table of src mac addrs.  Each active RDMA connection in
HW keeps an index into each table for building the ethernet header. 

The _driver_ needs to know when the next hop mac addr changes, or when
the next hop itself changes for a given destination so that it can
update the active connections and/or the L2T table accordingly.   Same
deal with the path mtu...

> How is this info used in hardware? Can you explain how an arriving
> packet would be used by the RDMA in conjunction with this info once it
> is in the hardware?
> 

I think my stuff above explains this, eh?

> > These devices also act a standard Ethernet NIC btw...
> > 
> 
> Meaning there is no funky hardware processing?
> 

If an incoming packet is not for one of the active RDMA connections (or
a listening RDMA endpoint), then the packet is passed up to the native
stack via the device's netdev driver.

Stevo.



^ permalink raw reply

* Re: [PATCH 0/2][RFC] Network Event Notifier Mechanism
From: Steve Wise @ 2006-06-23 13:17 UTC (permalink / raw)
  To: hadi; +Cc: David Miller, netdev
In-Reply-To: <1151009762.5392.126.camel@jzny2>

On Thu, 2006-06-22 at 16:56 -0400, jamal wrote:
> On Thu, 2006-22-06 at 15:40 -0500, Steve Wise wrote:
> > On Thu, 2006-06-22 at 15:43 -0400, jamal wrote:
> > > 
> > > No - what these 2 gents are saying was these events and infrastructure
> > > already exist. 
> > 
> > Notification of the exact events needed does not exist today.   
> > 
> 
> Ok, so you cant event make use of anything that already exists?
> Or is a subset of what you need already there?
> 
> > The key events, again, are:
> > 
> > - the neighbour entry mac address has changed.
> > 
> >
> > - the next hop ip address (ie the neighbour) for a given dst_entry has
> > changed.
> 
> 
> I dont see a difference for the above two from an L2 perspective.
> Are you keeping track of IP addresses?

There is no difference from an L2 perspective, but the RDMA driver needs
notification of each so it can correctly manipulate the L2 table in HW
and/or control block for the affected active connections.

> You didn't answer my question in the previous email as to what RDMA
> needs to keep track of in hardware.
> 

See my previous email.  To reiterate: The HW I'm working on maintains a
L2 table, and each active RDMA connection keeps an index into this
table .  If the mac addr of the next hop changes, then the L2 Table gets
updated.  If the next hop itself changes, then each active connection
must be kicked to update its index into the L2 table.


> > 
> > - the path mtu for a given dst_entry has changed.
> > 
> 
> Same with this.
> 

The RDMA HW needs the path mtu for each connection in order to do
segmentation.



Steve.


^ permalink raw reply

* Re: [PATCH 0/2][RFC] Network Event Notifier Mechanism
From: Steve Wise @ 2006-06-23 13:24 UTC (permalink / raw)
  To: hadi; +Cc: David Miller, netdev, caitlinb
In-Reply-To: <1151024186.5099.46.camel@jzny2>

On Thu, 2006-06-22 at 20:56 -0400, jamal wrote:
> On Thu, 2006-22-06 at 15:58 -0700, David Miller wrote:
> 
> > Anyways, we can create normal notifiers for neighbour and route
> > events just like we have for network device stuff.
> >

So did you agree with a new notifier head for these events as in my
original patch?  Or do you think I should add these to the netdev
notifier?  

> > There should be netlink counterparts for that stuff too, which
> > are generated by the notifier calls or similar.
> 

Ok.

> PS:- I do think what they need is to hear route cache generation
> as opposed to ARP+FIB updates; but lets wait and see how clever 
> the patches would look.
> 

Based on what I undestand from this thread, I should keep a notifier
block for these events and integrate that so the events also get passed
up to user space via netlink.  

Can you expand on your statement above?  If hooking route cache
generation gets all the events I described, then I'd like to use that.
I'm still learning the Linux routing subsystem.  Any help would be
GREAT!

Thanks,

Steve.




^ permalink raw reply

* Re: [PATCH v3 1/7] AMSO1100 Low Level Driver.
From: Steve Wise @ 2006-06-23 13:44 UTC (permalink / raw)
  To: Arjan van de Ven; +Cc: rdreier, linux-kernel, openib-general, netdev
In-Reply-To: <1150836226.2891.231.camel@laptopd505.fenrus.org>


> 
> Also on a related note, have you checked the driver for the needed PCI
> posting flushes?
> 
> > +
> > +	/* Disable IRQs by clearing the interrupt mask */
> > +	writel(1, c2dev->regs + C2_IDIS);
> > +	writel(0, c2dev->regs + C2_NIMR0);
> 
> like here...

This code is followed by a call to c2_reset(), which interacts with the
firmware on the adapter to quiesce the hardware.  So I don't think we
need to wait here for the posted writes to flush...

> > +
> > +	elem = tx_ring->to_use;
> > +	elem->skb = skb;
> > +	elem->mapaddr = mapaddr;
> > +	elem->maplen = maplen;
> > +
> > +	/* Tell HW to xmit */
> > +	__raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_TXP_ADDR);
> > +	__raw_writew(cpu_to_be16(maplen), elem->hw_desc + C2_TXP_LEN);
> > +	__raw_writew(cpu_to_be16(TXP_HTXD_READY), elem->hw_desc + C2_TXP_FLAGS);
> 
> or here
> 

No need here.  This logic submits the packet for transmission.  We don't
assume it is transmitted until we (after a completion interrupt usually)
read back the HTXD entry and see the TXP_HTXD_DONE bit set (see
c2_tx_interrupt()). 


Steve.

^ permalink raw reply

* Re: [PATCH v3 1/7] AMSO1100 Low Level Driver.
From: Arjan van de Ven @ 2006-06-23 13:48 UTC (permalink / raw)
  To: Steve Wise; +Cc: rdreier, linux-kernel, openib-general, netdev
In-Reply-To: <1151070290.7808.33.camel@stevo-desktop>


> > > +	/* Tell HW to xmit */
> > > +	__raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_TXP_ADDR);
> > > +	__raw_writew(cpu_to_be16(maplen), elem->hw_desc + C2_TXP_LEN);
> > > +	__raw_writew(cpu_to_be16(TXP_HTXD_READY), elem->hw_desc + C2_TXP_FLAGS);
> > 
> > or here
> > 
> 
> No need here.  This logic submits the packet for transmission.  We don't
> assume it is transmitted until we (after a completion interrupt usually)
> read back the HTXD entry and see the TXP_HTXD_DONE bit set (see
> c2_tx_interrupt()). 

... but will that interrupt happen at all if these 3 writes never hit
the hardware?

^ permalink raw reply

* Re: [PATCH v3 1/7] AMSO1100 Low Level Driver.
From: Steve Wise @ 2006-06-23 13:56 UTC (permalink / raw)
  To: Arjan van de Ven; +Cc: rdreier, linux-kernel, openib-general, netdev
In-Reply-To: <1151070532.3204.10.camel@laptopd505.fenrus.org>

On Fri, 2006-06-23 at 15:48 +0200, Arjan van de Ven wrote:
> > > > +	/* Tell HW to xmit */
> > > > +	__raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_TXP_ADDR);
> > > > +	__raw_writew(cpu_to_be16(maplen), elem->hw_desc + C2_TXP_LEN);
> > > > +	__raw_writew(cpu_to_be16(TXP_HTXD_READY), elem->hw_desc + C2_TXP_FLAGS);
> > > 
> > > or here
> > > 
> > 
> > No need here.  This logic submits the packet for transmission.  We don't
> > assume it is transmitted until we (after a completion interrupt usually)
> > read back the HTXD entry and see the TXP_HTXD_DONE bit set (see
> > c2_tx_interrupt()). 
> 
> ... but will that interrupt happen at all if these 3 writes never hit
> the hardware?
> 

I thought the posted write WILL eventually get to adapter memory.  Not
stall forever cached in a bridge.  I'm wrong?

My point is for a given HTXD entry, we write it to post a packet for
transmission, then only free the packet memory and reuse this entry
_after_ reading the HTXD and seeing the DONE bit set.  So I still don't
see a problem.  But I've been wrong before ;-)

Steve.

^ permalink raw reply

* Re: [PATCH v3 1/7] AMSO1100 Low Level Driver.
From: Arjan van de Ven @ 2006-06-23 14:04 UTC (permalink / raw)
  To: Steve Wise; +Cc: rdreier, mshefty, linux-kernel, netdev, openib-general
In-Reply-To: <1151071005.7808.39.camel@stevo-desktop>

On Fri, 2006-06-23 at 08:56 -0500, Steve Wise wrote:
> On Fri, 2006-06-23 at 15:48 +0200, Arjan van de Ven wrote:
> > > > > +	/* Tell HW to xmit */
> > > > > +	__raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_TXP_ADDR);
> > > > > +	__raw_writew(cpu_to_be16(maplen), elem->hw_desc + C2_TXP_LEN);
> > > > > +	__raw_writew(cpu_to_be16(TXP_HTXD_READY), elem->hw_desc + C2_TXP_FLAGS);
> > > > 
> > > > or here
> > > > 
> > > 
> > > No need here.  This logic submits the packet for transmission.  We don't
> > > assume it is transmitted until we (after a completion interrupt usually)
> > > read back the HTXD entry and see the TXP_HTXD_DONE bit set (see
> > > c2_tx_interrupt()). 
> > 
> > ... but will that interrupt happen at all if these 3 writes never hit
> > the hardware?
> > 
> 
> I thought the posted write WILL eventually get to adapter memory.  Not
> stall forever cached in a bridge.  I'm wrong?

I'm not sure there is a theoretical upper bound.... 

(and if it's several msec per bridge, then you have a lot of latency
anyway)


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox