Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: Moving drivers into staging (was Re: [GIT PULL] SCSI fixes for 2.6.32-rc3)
From: James Bottomley @ 2009-10-12 15:43 UTC (permalink / raw)
  To: Greg KH
  Cc: Ingo Molnar, Linus Torvalds, Theodore Tso, Andrew Morton,
	linux-scsi, linux-kernel, Jing Huang, netdev, linux-wireless
In-Reply-To: <20091012150911.GB1656@suse.de>

On Mon, 2009-10-12 at 08:09 -0700, Greg KH wrote:
> adding David Miller and the wireless developers who had this idea as
> well...
> 
> On Mon, Oct 12, 2009 at 04:54:53PM +0200, Ingo Molnar wrote:
> > I think your interpretation is arbitrary - where did you get that ABI 
> > rule from? I'm sure it cannot be from any of the drivers/staging/ 
> > discussions on lkml, i've followed them quite closely. If 'has a messy 
> > ABI' was the only requirement for drivers/staging/ then we could move 
> > 90% of drivers/staging/ into drivers/ straight away - and that would be 
> > counter-productive IMHO.
> 
> I agree with this, and the other points you raised that I snipped out.
> 
> > Sidenote, in fact i think we should expand on that: drivers/staging/ 
> > should be used in the _other_ direction as well - to un-upstream stale 
> > drivers that are abandoned and unused, in a gradual fashion. 'git mv' is 
> > cheap.
> 
> Ok, this is about the 3rd or 4th time I've heard this, from totally
> different people lately.  It seems that I'm the only one that has the
> ability to drop drivers out of the kernel tree, which is a funny
> situation :)
> 
> In thinking about this a lot more, I don't really mind it.  If people
> want to push stuff out of "real" places in the kernel, into
> drivers/staging/ and give the original authors and maintainers notice
> about what is going on, _and_ provide a TODO file for what needs to
> happen to get the code back into the main portion of the kernel tree,
> then I'll be happy to help out with this and manage it.
> 
> I think a 6-9 month window (basically 3 kernel releases) should be
> sufficient time to have a driver that has been in drivers/staging/ be
> cleaned up enough to move back into the main kernel tree.  If not, it
> could be easily dropped.
> 
> Any objections to this?

Not as an optional tool to use when necessary.

If you want to make this a mandatory path for old drivers, then, I think
it's far too rigid, yes.   There's a huge amount of danger to changing
working drivers simply on grounds of code cleanup and that danger
increases exponentially as they get older and the hardware gets rarer.
Look at what happened to the initio driver in 2008 for instance.  That
was cleaned up by Alan Cox, no mean expert in the field, with the
assistance of a tester with the actual card, so basically a textbook
operation.  However, a bug crept in during this process that wasn't
spotted by the tester.  When it was spotted (bug report ~6 months later)
the original tester wasn't available and code inspection across the
cleanup was very hard.  Fortunately, the reporter was motivated to track
down and patch the driver, so it worked out all right in the end, but a
lot of bug reporters aren't so capable (or so motivated).  Plus most
clean up patches for old hardware tend only to be compile tested, so the
potential for bugs is far greater.

James

> > Basically, drivers/staging/ gives us an excellent opportunity to 
> > _increase_ the quality of drivers by applying stronger upstream 
> > inclusion filters, without having to hurt users/developers in the 
> > process. We just have to start using it that way as well.
> 
> I totally agree.  And so far, it does seem to be working well for this.
> A number of companies have used it to successfully get their code into
> the main kernel, as well as driving them to clean up their code better
> to keep it from having to go into the staging tree.
> 
> thanks,
> 
> greg k-h


^ permalink raw reply

* Re: Moving drivers into staging (was Re: [GIT PULL] SCSI fixes for 2.6.32-rc3)
From: Ingo Molnar @ 2009-10-12 15:42 UTC (permalink / raw)
  To: Greg KH
  Cc: James Bottomley, Linus Torvalds, Theodore Tso, Andrew Morton,
	linux-scsi, linux-kernel, Jing Huang, netdev, linux-wireless
In-Reply-To: <20091012150911.GB1656@suse.de>


* Greg KH <gregkh@suse.de> wrote:

> > Sidenote, in fact i think we should expand on that: drivers/staging/ 
> > should be used in the _other_ direction as well - to un-upstream 
> > stale drivers that are abandoned and unused, in a gradual fashion. 
> > 'git mv' is cheap.
> 
> Ok, this is about the 3rd or 4th time I've heard this, from totally 
> different people lately. [...]

Heh. I guess i had a good crystal ball on that then - i raised that 
issue in my very first comments on drivers/staging/, 2.5 years ago - see 
the "Linux Kernel developer statement about closed source code" thread, 
where i wrote:

| - We must accept open-source drivers (which are license-compatible
|   with the kernel) for new hardware the moment they are offered. No 
|   ifs and when. No whining about quality, style, security, re-use, 
|   non-reuse, obsolete APIs, overlapping functionality, the already 
|   busy merge schedule of a maintainer or whatever other thing can come 
|   up on lkml.
|
|   We can create arbitrary quarantine mechanisms we wish to use: 
|   CONFIG_REALLY_BROKEN. We could even create drivers/staging/ as a 
|   temporary staging area for drivers.
|
|   What we cannot do is to _deny_ the distribution channel and exclude 
|   users. The moment we do that (and we still do that in way too many 
|   areas of the kernel) we have lost the availability race.

[...]

| If it's not maintained actively(sc) (i.e. it's a fire-and-forget 
| driver) then it can get marked BROKEN with time, and can get removed 
| as well.

Hm, i think i even gave drivers/staging/ its name?

> [...] It seems that I'm the only one that has the ability to drop 
> drivers out of the kernel tree, which is a funny situation :)

You are the only one who has the ability to send a warning shot towards 
drivers _without hurting users_, and by moving it into the focus of a 
team of cleanup oriented developers.

I think that's an important distinction ;-)

> In thinking about this a lot more, I don't really mind it.  If people 
> want to push stuff out of "real" places in the kernel, into 
> drivers/staging/ and give the original authors and maintainers notice 
> about what is going on, _and_ provide a TODO file for what needs to 
> happen to get the code back into the main portion of the kernel tree, 
> then I'll be happy to help out with this and manage it.
> 
> I think a 6-9 month window (basically 3 kernel releases) should be 
> sufficient time to have a driver that has been in drivers/staging/ be 
> cleaned up enough to move back into the main kernel tree.  If not, it 
> could be easily dropped.
> 
> Any objections to this?

Sounds excellent to me!

> > Basically, drivers/staging/ gives us an excellent opportunity to 
> > _increase_ the quality of drivers by applying stronger upstream 
> > inclusion filters, without having to hurt users/developers in the 
> > process. We just have to start using it that way as well.
> 
> I totally agree.  And so far, it does seem to be working well for 
> this. A number of companies have used it to successfully get their 
> code into the main kernel, as well as driving them to clean up their 
> code better to keep it from having to go into the staging tree.

Yeah. I think we were hurting from an under-estimated trust problem: 
driver authors couldnt trust _us maintainers_ to follow through with 
upstreaming. drivers/staging/ improved that IMHO.

I.e. the old process of upstreaming drivers was too arbitrary, incurred 
big latencies and was dependent on the whims of maintainers. I.e. new 
developers got exposed to some of the worst social aspects of a 
distributed development process.

Now there's basically a single (and friendly! ;-) upstreaming channel 
that people (yet-)unfamilar with Linux practices can standardize on. 
This reduces the pressure on maintainers and also creates a reference 
point for upstreaming honesty - which is almost unconditionally good i 
think.

	Ingo

^ permalink raw reply

* Moving drivers into staging (was Re: [GIT PULL] SCSI fixes for 2.6.32-rc3)
From: Greg KH @ 2009-10-12 15:09 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: James Bottomley, Linus Torvalds, Theodore Tso, Andrew Morton,
	linux-scsi, linux-kernel, Jing Huang, netdev, linux-wireless
In-Reply-To: <20091012145453.GD4565@elte.hu>

adding David Miller and the wireless developers who had this idea as
well...

On Mon, Oct 12, 2009 at 04:54:53PM +0200, Ingo Molnar wrote:
> I think your interpretation is arbitrary - where did you get that ABI 
> rule from? I'm sure it cannot be from any of the drivers/staging/ 
> discussions on lkml, i've followed them quite closely. If 'has a messy 
> ABI' was the only requirement for drivers/staging/ then we could move 
> 90% of drivers/staging/ into drivers/ straight away - and that would be 
> counter-productive IMHO.

I agree with this, and the other points you raised that I snipped out.

> Sidenote, in fact i think we should expand on that: drivers/staging/ 
> should be used in the _other_ direction as well - to un-upstream stale 
> drivers that are abandoned and unused, in a gradual fashion. 'git mv' is 
> cheap.

Ok, this is about the 3rd or 4th time I've heard this, from totally
different people lately.  It seems that I'm the only one that has the
ability to drop drivers out of the kernel tree, which is a funny
situation :)

In thinking about this a lot more, I don't really mind it.  If people
want to push stuff out of "real" places in the kernel, into
drivers/staging/ and give the original authors and maintainers notice
about what is going on, _and_ provide a TODO file for what needs to
happen to get the code back into the main portion of the kernel tree,
then I'll be happy to help out with this and manage it.

I think a 6-9 month window (basically 3 kernel releases) should be
sufficient time to have a driver that has been in drivers/staging/ be
cleaned up enough to move back into the main kernel tree.  If not, it
could be easily dropped.

Any objections to this?

> Basically, drivers/staging/ gives us an excellent opportunity to 
> _increase_ the quality of drivers by applying stronger upstream 
> inclusion filters, without having to hurt users/developers in the 
> process. We just have to start using it that way as well.

I totally agree.  And so far, it does seem to be working well for this.
A number of companies have used it to successfully get their code into
the main kernel, as well as driving them to clean up their code better
to keep it from having to go into the staging tree.

thanks,

greg k-h

^ permalink raw reply

* [PATCH] crda: Cosmetic fix for udev path
From: Tim Gardner @ 2009-10-12 15:02 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless@vger.kernel.org

[-- Attachment #1: Type: text/plain, Size: 184 bytes --]

Luis,

This patch is against
git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/crda.git. It fixes
some complaints about an extra '/'.

rtg
-- 
Tim Gardner tim.gardner@canonical.com

[-- Attachment #2: 0001-Cosmetic-fix-for-udev-path.patch --]
[-- Type: text/x-patch, Size: 911 bytes --]

>From 31a08704192dee87ee592f70988ee7806c37523a Mon Sep 17 00:00:00 2001
From: Tim Gardner <tim.gardner@canonical.com>
Date: Mon, 12 Oct 2009 08:53:31 -0600
Subject: [PATCH] crda: Cosmetic fix for udev path

BugLink: http://bugs.launchpad.net/bugs/340995

SBINDIR already has a trailing '/', so its not needed
in the udev rule.

Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
---
 udev/regulatory.rules |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/udev/regulatory.rules b/udev/regulatory.rules
index 5588ed7..3d6add8 100644
--- a/udev/regulatory.rules
+++ b/udev/regulatory.rules
@@ -2,4 +2,4 @@
 # For more information see:
 # http://wireless.kernel.org/en/developers/Regulatory/CRDA
 
-KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="$(SBINDIR)/crda"
+KERNEL=="regulatory*", ACTION=="change", SUBSYSTEM=="platform", RUN+="$(SBINDIR)crda"
-- 
1.6.2.4


^ permalink raw reply related

* Re: [PATCH V3] iwlwifi: use paged Rx
From: Stanislaw Gruszka @ 2009-10-12 14:20 UTC (permalink / raw)
  To: Zhu Yi; +Cc: linville, linux-wireless
In-Reply-To: <1255079985-17282-1-git-send-email-yi.zhu@intel.com>

On Fri, Oct 09, 2009 at 05:19:45PM +0800, Zhu Yi wrote:
> This switches the iwlwifi driver to use paged skb from linear skb for Rx
> buffer. So that it relieves some Rx buffer allocation pressure for the
> memory subsystem. Currently iwlwifi (4K for 3945) requests 8K bytes for
> Rx buffer. Due to the trailing skb_shared_info in the skb->data,
> alloc_skb() will do the next order allocation, which is 16K bytes. This
> is suboptimal and more likely to fail when the system is under memory
> usage pressure. Switching to paged Rx skb lets us allocate the RXB
> directly by alloc_pages(), so that only order 1 allocation is required.

[snip]

> Finally, mac80211 doesn't support paged Rx yet. So we linearize the skb
> for all the management frames and software decryption or defragmentation
> required data frames before handed to mac80211. For all the other frames,
> we __pskb_pull_tail 64 bytes in the linear area of the skb for mac80211
> to handle them properly.

This seems to be big overhead, but since there is no way to avoid it ...

> Signed-off-by: Zhu Yi <yi.zhu@intel.com>
> ---
> V2: fix 3945 problem and linearize skb for fragemented frames
> V3: fix a 3945 pci_unmap_page bug
> 
>  drivers/net/wireless/iwlwifi/iwl-3945.c     |   67 ++++++++++-----
>  drivers/net/wireless/iwlwifi/iwl-4965.c     |    2 +-
>  drivers/net/wireless/iwlwifi/iwl-5000.c     |    4 +-
>  drivers/net/wireless/iwlwifi/iwl-agn.c      |   42 ++++-----
>  drivers/net/wireless/iwlwifi/iwl-commands.h |   10 ++
>  drivers/net/wireless/iwlwifi/iwl-core.c     |   13 ++--
>  drivers/net/wireless/iwlwifi/iwl-core.h     |    2 +-
>  drivers/net/wireless/iwlwifi/iwl-dev.h      |   27 ++++--
>  drivers/net/wireless/iwlwifi/iwl-hcmd.c     |   21 ++----
>  drivers/net/wireless/iwlwifi/iwl-rx.c       |  122 +++++++++++++++++----------
>  drivers/net/wireless/iwlwifi/iwl-scan.c     |   20 ++--
>  drivers/net/wireless/iwlwifi/iwl-spectrum.c |    2 +-
>  drivers/net/wireless/iwlwifi/iwl-sta.c      |   62 +++++--------
>  drivers/net/wireless/iwlwifi/iwl-tx.c       |   10 +-
>  drivers/net/wireless/iwlwifi/iwl3945-base.c |  120 +++++++++++++-------------
>  15 files changed, 284 insertions(+), 240 deletions(-)

[snip]

> @@ -543,14 +543,17 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
>  				   struct iwl_rx_mem_buffer *rxb,
>  				   struct ieee80211_rx_status *stats)
>  {
> -	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> +	struct iwl_rx_packet *pkt = rxb_addr(rxb);
>  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
>  	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
>  	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
> -	short len = le16_to_cpu(rx_hdr->len);
> +	u16 len = le16_to_cpu(rx_hdr->len);
> +	struct sk_buff *skb;
> +	int ret;
>  
>  	/* We received data from the HW, so stop the watchdog */
> -	if (unlikely((len + IWL39_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
> +	if (unlikely(len + IWL39_RX_FRAME_SIZE >
> +		     PAGE_SIZE << priv->hw_params.rx_page_order)) {
>  		IWL_DEBUG_DROP(priv, "Corruption detected!\n");
>  		return;
>  	}
> @@ -562,20 +565,45 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
>  		return;
>  	}
>  
> -	skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);
> -	/* Set the size of the skb to the size of the frame */
> -	skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
> +	skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
> +	if (!skb) {
> +		IWL_ERR(priv, "alloc_skb failed\n");
> +		return;
> +	}

If we know that we need to linearize we can alloc as big skb as needed,
otherwise skb_linearize() need to do reallocation.

Can we also remove IWL_LINK_HDR_MAX and do __pskb_pull_tail based on 
real header(s) size ? 

Or.

If we decide to do alloc_skb(IWL_LINK_HDR_MAX, gfp_flags) can this be 
done together with skb_add_rx_frag() in iwl_rx_allocate(), to offload
this interrupt context ?

>  	if (!iwl3945_mod_params.sw_crypto)
>  		iwl_set_decrypted_flag(priv,
> -				       (struct ieee80211_hdr *)rxb->skb->data,
> +				       (struct ieee80211_hdr *)rxb_addr(rxb),
>  				       le32_to_cpu(rx_end->status), stats);
>  
> +	skb_add_rx_frag(skb, 0, rxb->page,
> +			(void *)rx_hdr->payload - (void *)pkt, len);
> +
> +	/* mac80211 currently doesn't support paged SKB. Convert it to
> +	 * linear SKB for management frame and data frame requires
> +	 * software decryption or software defragementation. */
> +	if (ieee80211_is_mgmt(hdr->frame_control) ||
> +	    ieee80211_has_protected(hdr->frame_control) ||
> +	    ieee80211_has_morefrags(hdr->frame_control) ||
> +	    le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)

Minor optimization:
	    hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)

> +		ret = skb_linearize(skb);
> +	else
> +		ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
> +			0 : -ENOMEM;
> +
> +	if (ret) {
> +		kfree_skb(skb);
> +		goto out;
> +	}
> +
>  	iwl_update_stats(priv, false, hdr->frame_control, len);
>  
> -	memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
> -	ieee80211_rx_irqsafe(priv->hw, rxb->skb);
> -	rxb->skb = NULL;
> +	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
> +	ieee80211_rx(priv->hw, skb);
> +
> + out:
> +	priv->alloc_rxb_page--;
> +	rxb->page = NULL;
>  }

[snip] 

>  struct iwl_rx_mem_buffer {
> -	dma_addr_t real_dma_addr;
> -	dma_addr_t aligned_dma_addr;
> -	struct sk_buff *skb;
> +	dma_addr_t page_dma;
> +	struct page *page;
>  	struct list_head list;
>  };
>  
> +#define rxb_addr(r) page_address(r->page)

Since we mostly use pointer, perhaps better would be save address of page
in iwl_rx_mem_buffer, and use virt_to_page where struct page is needed.

[snip]
 
> @@ -252,29 +252,34 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
>  
>  		if (rxq->free_count > RX_LOW_WATERMARK)
>  			priority |= __GFP_NOWARN;
> -		/* Alloc a new receive buffer */
> -		skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
> -						priority);
>  
> -		if (!skb) {
> +		if (priv->hw_params.rx_page_order > 0)
> +			priority |= __GFP_COMP;
> +
> +		/* Alloc a new receive buffer */
> +		page = alloc_pages(priority, priv->hw_params.rx_page_order);
> +		if (!page) {
>  			if (net_ratelimit())
> -				IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
> +				IWL_DEBUG_INFO(priv, "alloc_pages failed, "
> +					       "order: %d\n",
> +					       priv->hw_params.rx_page_order);
> +
>  			if ((rxq->free_count <= RX_LOW_WATERMARK) &&
>  			    net_ratelimit())
> -				IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n",
> +				IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n",
>  					 priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL",

priority can not be equal GFP_ATOMIC if was or'ed with __GFP_COMP or __GFP_NOWARN

Cheers
Stanislaw


^ permalink raw reply

* Re: WARNING: slow-path
From: Holger Schurig @ 2009-10-12 14:02 UTC (permalink / raw)
  To: David Woodhouse; +Cc: linux-wireless
In-Reply-To: <1255352906.30919.11.camel@macbook.infradead.org>

> What happens if you make that last argument NULL instead of
> passing 'dummy' back to it? That makes cfg80211_send_deauth()
> magically do different things w.r.t. locking.

That worked, thanks.


> Johannes, this is _evil_: 

It's not only _evil_, it's also undocumented. I was just
following include/net/cfg80211.h. There is no kernel-doc in the
comments for "cookie", neither in

  [struct cfg80211_ops:]

        int     (*deauth)(struct wiphy *wiphy, struct net_device *dev,
                          struct cfg80211_deauth_request *req,
                          void *cookie);

nor in


void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
                          void *cookie);


so I automatically assumed that I have to provide the "cookie" I
got in my deauth()-handler to cfg80211_send_deauth().

/me says "I can haz a cookie?"

-- 
http://www.holgerschurig.de

^ permalink raw reply

* Re: 802.11: Throughput optimization beyond rate selection
From: John W. Linville @ 2009-10-12 13:59 UTC (permalink / raw)
  To: Joerg Pommnitz; +Cc: linux-wireless
In-Reply-To: <487238.22616.qm@web51405.mail.re2.yahoo.com>

On Mon, Oct 12, 2009 at 02:28:07AM -0700, Joerg Pommnitz wrote:
> Hello all,
> the throughput achieved over a wireless 802.11 network depends on more than the 
> rate selection. Other parameters are fragmentation threshold, RTS threshold 
> and the retry limits. Are you aware of a "unified throughput optimization" algorithm 
> that tries to optimize the whole parameter set instead of just the data rate? 

No, do tell...post code as well... :-)

-- 
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

* Re: [PATCH] b43: fix ieee80211_rx() context
From: John W. Linville @ 2009-10-12 13:38 UTC (permalink / raw)
  To: David Miller; +Cc: kalle.valo, johannes, hidave.darkstar, linux-wireless
In-Reply-To: <20091011.200857.141215452.davem@davemloft.net>

On Sun, Oct 11, 2009 at 08:08:57PM -0700, David Miller wrote:
> From: Kalle Valo <kalle.valo@iki.fi>
> Date: Sun, 11 Oct 2009 19:08:58 +0300
> 
> > Johannes Berg <johannes@sipsolutions.net> writes:
> > 
> >>> > +	local_bh_disable();
> >>> >  	ieee80211_rx(dev->wl->hw, skb);
> >>> > +	local_bh_enable();
> >>> 
> >>> This is a bit awkward from drivers' point of view, we have to add the
> >>> same code to all mac80211 drivers using either SPI or SDIO buses.
> >>> 
> >>> What about adding a new inline function ieee80211_rx_ni() which would
> >>> disable bottom halves like above and call ieee80211_rx()? IMHO that's
> >>> easier for the driver developers to understand and also easier to
> >>> document ("use this function when calling from process context"). If
> >>> this is acceptable, I can create a patch.
> >>
> >> I really don't see the point, since it's just three lines of code, but I
> >> wouldn't mind all that much either.
> > 
> > My worry are the developers who even don't know what is a bottom half
> > and might get it all wrong. (Yes, there really are such people.)
> 
> And the difference between this and knowing you need to call the
> ieee80211_rx_ni() thing is?
> 
> You have to know what the heck a bottom half is to even know that you
> would need to call the ieee80211_rx_ni() thing.
> 
> And that's the same amount of knowledge necessary to simply wrap the
> thing in a BH disable/enable sequence.

I'm not sure I see the difference between this and the rationale for
having netif_rx_ni vs. an open-coded version of it?  ieee80211_rx_ni
seems like a small amount of code (could even be inline) that
potentially avoids some stupid bugs...?

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

* Re: RaLink 148f:3070 not working since upgrade from 2.6.30 to 2.6.31
From: John W. Linville @ 2009-10-12 13:43 UTC (permalink / raw)
  To: Bráulio B O Bhavamitra; +Cc: linux-wireless
In-Reply-To: <1df1788c0910110518l1d120983id2bf997d2446b4a7@mail.gmail.com>

On Sun, Oct 11, 2009 at 09:18:24AM -0300, Bráulio B O Bhavamitra wrote:
> Also in Ubuntu Karmic Beta (where the firmware is present) it doesn't
> work (radio not working, can't find any access point)
> 
> 2009/10/11 Bráulio B O Bhavamitra <brauliobo@gmail.com>:
> > Since the upgrade from kernel 2.6.30 to 2.6.31 on archlinux the usb
> > wireless from Ralink doesn't work anymore.
> > Please ask for more info if necessary.

This commit is post-2.6.30 (and pre-2.6.31):

commit d53d9e67b55f6a9fc3f836c5c392eb41ce5676f4
Author: Ivo van Doorn <IvDoorn@gmail.com>
Date:   Sun Apr 26 15:47:48 2009 +0200

    rt2x00: Implement support for rt2800usb
    
    Add support for the rt2800usb chipset.
    
    Current problems:
     * Cannot scan 11n AP's
     * No TX during first minute after association
     * Broken Hardware encryption
    
    Includes various patches from Mattias, Felix, Xose and Axel.
    
    Signed-off-by: Mattias Nissler <mattias.nissler@gmx.de>
    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
    Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
    Signed-off-by: Axel Kollhofer <rain_maker@root-forum.org>
    Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

That is the first time 148f:3070 is supported by the rt2x00 drivers.
I have no idea what you were using up to 2.6.30...

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

* Re: [RFC] p54pci: skb_over_panic, soft lockup, stall under flood
From: Quintin Pitts @ 2009-10-12 13:34 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: Larry Finger, linux-wireless
In-Reply-To: <200910121057.10381.chunkeey@googlemail.com>

On Mon Oct 12 2009 03:57:10 GMT-0500 (CDT), Christian Lamparter wrote:
> On Monday 12 October 2009 02:09:22 Quintin Pitts wrote:
>> On Sun Oct 11 2009 10:31:42 GMT-0500 (CDT), Larry Finger wrote:
>>> On 10/11/2009 09:28 AM, Quintin Pitts wrote:
>>> As I understand it, this patch is to fix the driver to work around
>>> firmware errors. If that is correct, please state that clearly. If
>>> only partially correct, then indicate which parts are to fix firmware
>>> errors, and which are to fix driver errors. Has your analysis included
>>> thinking about where the driver might delay to avoid firmware problems.
>> I think Christian has hit the nail on the head.
>> Mostly flaky hardware or implementation (it8152 pci bridge) when pushed.
> 
> hmm, flaky hardware or simply incomplete linux support.
> you've said that it works with win ce,
> so I suppose the code is missing some important bits.
> 
> e.g.:
> 
> 00:06.0 Network controller: Intersil Corporation ISL3886 [Prism Javelin/Prism Xbow] (rev 01)
> Subsystem: Intersil Corporation Device 0000
> Flags: bus master, medium devsel, latency 56, IRQ 217
> 
> by the looks of it, something could wrong with the latency timer value.
> (what's lspci -vvnnxxx output for the card?)

00:06.0 Network controller [0280]: Intersil Corporation ISL3886 [Prism Javelin/Prism Xbow] [1260:3886] (rev 01)
	Subsystem: Intersil Corporation Device [1260:0000]
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 56 (2500ns min, 7000ns max), Cache Line Size: 32 bytes
	Interrupt: pin A routed to IRQ 217
	Region 0: Memory at 11000000 (32-bit, non-prefetchable) [size=8K]
	Capabilities: [dc] Power Management version 1
		Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
		Status: D0 PME-Enable- DSel=0 DScale=0 PME-
	Kernel modules: prism54, p54pci
00: 60 12 86 38 06 01 90 02 01 00 80 02 08 38 00 00
10: 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 01 08 00 00 60 12 00 00
30: 00 00 00 00 dc 00 00 00 00 00 00 00 d9 01 0a 1c
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 01 00 01 fe
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

After the driver is up with the p54-latency patch:

00:06.0 Network controller [0280]: Intersil Corporation ISL3886 [Prism Javelin/Prism Xbow] [1260:3886] (rev 01)
	Subsystem: Intersil Corporation Device [1260:0000]
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx+
	Latency: 80 (2500ns min, 7000ns max), Cache Line Size: 32 bytes
	Interrupt: pin A routed to IRQ 217
	Region 0: Memory at 11000000 (32-bit, non-prefetchable) [size=8K]
	Capabilities: [dc] Power Management version 1
		Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
		Status: D0 PME-Enable- DSel=0 DScale=0 PME-
	Kernel driver in use: p54pci
	Kernel modules: prism54, p54pci
00: 60 12 86 38 16 01 98 02 01 00 80 02 08 50 00 00
10: 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 01 08 00 00 60 12 00 00
30: 00 00 00 00 dc 00 00 00 00 00 00 00 d9 01 0a 1c
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 01 00 01 fe
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

> 
> I've attached a minimal patch which c&p some latency-timer related logic
> from the original prism54 driver code to p54pci.
> Can you please give this a try?

Still same weird results with p54-latency patch.  Triggering my condition
statements. under a 3 minute iperf test.

p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: index > ring_index diff *index=176894 devidx=176640 hostidx=
176901 ring_limit=8 Returning call!                                             
p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: rx_ring len/flags has address - skipping!                   
p54p_check_rx_ring: rx_ring len/flags has address - skipping!     

> I don't have a p54pci available for testing right now.
> 
> Regards,
> 	Chr

Thanks,

Quintin.

^ permalink raw reply

* Re: [PATCH 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: John W. Linville @ 2009-10-12 13:17 UTC (permalink / raw)
  To: David Miller
  Cc: tomasw, netdev, linux-wireless, linux-mmc, yi.zhu,
	inaky.perez-gonzalez, cindy.h.kao, guy.cohen, ron.rindjunsky
In-Reply-To: <20091011.033647.66923614.davem@davemloft.net>

On Sun, Oct 11, 2009 at 03:36:47AM -0700, David Miller wrote:
> From: Tomas Winkler <tomasw@gmail.com>
> Date: Sun, 11 Oct 2009 10:05:20 +0200
> 
> > Just close my eyes and there is new game to play. :)
> > It's not in the patchwork, so is there any reason you are not planning
> > to add it.   The patch intention was for net-next, it looks like
> > I didn't mark it as such, my fault.
> 
> Because there still seems to be some confusion between which of these
> bits go through John Linville as a wireless driver and which bits
> go directly through me.
> 
> By default I assume John picks up "wireless" drivers and send them
> to me in his wireless merges to me.
> 
> If that's not the case, explicitly do a fresh submission of this patch
> and explicitly ask me to merge it.

I was afraid this might get lost in the confusion.  I had other things
to worry about and since it crossed so many lines and was sent to
netdev, I figured I'd worry about it later if it got lost... :-(

FWIW, I think the wimax/bluetooth/wifi connection makes net-next-2.6
the right tree for this.

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

* Re: WARNING: slow-path
From: David Woodhouse @ 2009-10-12 13:08 UTC (permalink / raw)
  To: Holger Schurig; +Cc: linux-wireless
In-Reply-To: <200910121335.21807.hs4233@mail.mn-solutions.de>

On Mon, 2009-10-12 at 13:35 +0200, Holger Schurig wrote:
> [   33.369923] WARNING: at net/wireless/mlme.c:135 __cfg80211_send_deauth+0x3f/0x1e1 [cfg80211]()

You're triggering the warning at line 135 of net/wireless/mlme.c, which
is 'ASSERT_WDEV_LOCK(wdev)' -- it's complaining that the lock isn't
held.
 
> static int lbs_cfg_ret_deauth(struct lbs_private *priv, unsigned long dummy,
>                            struct cmd_header *resp)
>         cfg80211_send_deauth(priv->dev, (u8 *)&mgmt, sizeof(mgmt),
>                              (void *)dummy); 

What happens if you make that last argument NULL instead of passing
'dummy' back to it? That makes cfg80211_send_deauth() magically do
different things w.r.t. locking. Johannes, this is _evil_:

void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
                          void *cookie)
{
        struct wireless_dev *wdev = dev->ieee80211_ptr;

        BUG_ON(cookie && wdev != cookie);

        if (cookie) {
                /* called within callback */
                __cfg80211_send_deauth(dev, buf, len);
        } else {
                wdev_lock(wdev);
                __cfg80211_send_deauth(dev, buf, len);
                wdev_unlock(wdev);
        }
}


-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse@intel.com                              Intel Corporation


^ permalink raw reply

* Re: [PATCH] b43: fix ieee80211_rx() context
From: Luciano Coelho @ 2009-10-12 12:29 UTC (permalink / raw)
  To: ext Kalle Valo
  Cc: David Miller, johannes@sipsolutions.net, linville@tuxdriver.com,
	hidave.darkstar@gmail.com, linux-wireless@vger.kernel.org
In-Reply-To: <87tyy5njbf.fsf@purkki.valot.fi>

ext Kalle Valo wrote:
> David Miller <davem@davemloft.net> writes:
> 
>>>> I really don't see the point, since it's just three lines of code, but I
>>>> wouldn't mind all that much either.
>>> My worry are the developers who even don't know what is a bottom half
>>> and might get it all wrong. (Yes, there really are such people.)
>> And the difference between this and knowing you need to call the
>> ieee80211_rx_ni() thing is?
>>
>> You have to know what the heck a bottom half is to even know that you
>> would need to call the ieee80211_rx_ni() thing.
>>
>> And that's the same amount of knowledge necessary to simply wrap the
>> thing in a BH disable/enable sequence.
> 
> I was thinking that it's possible to document it something like this:
> 
> o in irq context use ieee80211_rx_irqsafe()
> o in a tasklet use ieee80211_rx()
> o in process context use ieee80211_rx_ni()
> 
> Also in the future it might be easier to optimise something based on
> these functions. Maybe.
> 
> But as Johannes didn't like the idea, and neither do you, I'm going to
> drop the idea. I'll add the BH disable/enable to wl1251 instead and
> hopefully Luciano does the same to wl1271.

Yeps, I can do the same for wl1271.

-- 
Cheers,
Luca.

^ permalink raw reply

* 2.6.32-rc4-git1 -- INFO: possible circular locking dependency detected
From: Miles Lane @ 2009-10-12 12:28 UTC (permalink / raw)
  To: LKML, Johannes Berg, linux-wireless

[  823.466853] [ INFO: possible circular locking dependency detected ]
[  823.466866] 2.6.32-rc4-git1 #2
[  823.466873] -------------------------------------------------------
[  823.466884] swapper/0 is trying to acquire lock:
[  823.466893]  (&sta->lock){+.-...}, at: [<f857bda4>]
sta_addba_resp_timer_expired+0x1b/0x50 [mac80211]
[  823.466940]
[  823.466943] but task is already holding lock:
[  823.466953]
(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer){+.-...}, at:
[<c1032f22>] run_timer_softirq+0x125/0x1e5
[  823.466984]
[  823.466987] which lock already depends on the new lock.
[  823.466991]
[  823.467000]
[  823.467002] the existing dependency chain (in reverse order) is:
[  823.467013]
[  823.467015] -> #1 (&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer){+.-...}:
[  823.467037]        [<c104ac2c>] __lock_acquire+0x9fb/0xb6d
[  823.467056]        [<c104adfa>] lock_acquire+0x5c/0x73
[  823.467072]        [<c10336b8>] del_timer_sync+0x29/0x6c
[  823.467089]        [<f857bceb>]
ieee80211_process_addba_resp+0x49/0xa0 [mac80211]
[  823.467121]        [<f8584585>] ieee80211_rx_h_action+0xeb/0x335 [mac80211]
[  823.467157]        [<f8585654>]
ieee80211_invoke_rx_handlers+0xe50/0x10d8 [mac80211]
[  823.467193]        [<f8585d46>]
__ieee80211_rx_handle_packet+0x46a/0x497 [mac80211]
[  823.467229]        [<f8586475>] ieee80211_rx+0x4d1/0x530 [mac80211]
[  823.467263]        [<f89936e3>] ath_rx_send_to_mac80211+0xa0/0xa8 [ath9k]
[  823.467302]        [<f899439e>] ath_rx_tasklet+0x7b6/0x7f5 [ath9k]
[  823.467338]        [<f8992115>] ath9k_tasklet+0x47/0xc7 [ath9k]
[  823.467373]        [<c102f4a1>] tasklet_action+0x8e/0xe1
[  823.467391]        [<c102f95b>] __do_softirq+0x8d/0x117
[  823.467409]
[  823.467412] -> #0 (&sta->lock){+.-...}:
[  823.467430]        [<c104ab2e>] __lock_acquire+0x8fd/0xb6d
[  823.467447]        [<c104adfa>] lock_acquire+0x5c/0x73
[  823.467464]        [<c132526f>] _spin_lock_bh+0x2a/0x39
[  823.467481]        [<f857bda4>]
sta_addba_resp_timer_expired+0x1b/0x50 [mac80211]
[  823.467514]        [<c1032f6d>] run_timer_softirq+0x170/0x1e5
[  823.467531]        [<c102f95b>] __do_softirq+0x8d/0x117
[  823.467548]
[  823.467551] other info that might help us debug this:
[  823.467555]
[  823.467566] 1 lock held by swapper/0:
[  823.467574]  #0:
(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer){+.-...}, at:
[<c1032f22>] run_timer_softirq+0x125/0x1e5
[  823.467604]
[  823.467607] stack backtrace:
[  823.467619] Pid: 0, comm: swapper Not tainted 2.6.32-rc4-git1 #2
[  823.467628] Call Trace:
[  823.467643]  [<c13233c8>] ? printk+0xf/0x11
[  823.467659]  [<c1049ef5>] print_circular_bug+0x8a/0x96
[  823.467675]  [<c104ab2e>] __lock_acquire+0x8fd/0xb6d
[  823.467694]  [<c104adfa>] lock_acquire+0x5c/0x73
[  823.467725]  [<f857bda4>] ? sta_addba_resp_timer_expired+0x1b/0x50 [mac80211]
[  823.467742]  [<c132526f>] _spin_lock_bh+0x2a/0x39
[  823.467772]  [<f857bda4>] ? sta_addba_resp_timer_expired+0x1b/0x50 [mac80211]
[  823.467803]  [<f857bda4>] sta_addba_resp_timer_expired+0x1b/0x50 [mac80211]
[  823.467820]  [<c1032f6d>] run_timer_softirq+0x170/0x1e5
[  823.467836]  [<c1032f22>] ? run_timer_softirq+0x125/0x1e5
[  823.467866]  [<f857bd89>] ? sta_addba_resp_timer_expired+0x0/0x50 [mac80211]
[  823.467885]  [<c102f95b>] __do_softirq+0x8d/0x117
[  823.467901]  [<c102f8ce>] ? __do_softirq+0x0/0x117
[  823.467911]  <IRQ>  [<c102faf5>] ? irq_exit+0x38/0x75
[  823.467939]  [<c10045b1>] ? do_IRQ+0x88/0x9c
[  823.467954]  [<c1003175>] ? common_interrupt+0x35/0x3c
[  823.467971]  [<c104007b>] ? sched_clock_tick+0x31/0x77
[  823.467989]  [<c11b84ff>] ? acpi_idle_enter_bm+0x233/0x25e
[  823.468008]  [<c125c232>] ? cpuidle_idle_call+0x65/0x9b
[  823.468023]  [<c1001cd1>] ? cpu_idle+0xb9/0xe8
[  823.468041]  [<c131708b>] ? rest_init+0x67/0x69
[  823.468058]  [<c14e28e8>] ? start_kernel+0x3a3/0x3aa
[  823.468076]  [<c14e2098>] ? i386_start_kernel+0x98/0x9f

^ permalink raw reply

* Re: 2.6.32-rc4: Reported regressions 2.6.30 -> 2.6.31
From: Frederik Deweerdt @ 2009-10-12 12:22 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux Kernel Mailing List, Andrew Morton, Linus Torvalds,
	Natalie Protasevich, Kernel Testers List, Network Development,
	Linux ACPI, Linux PM List, Linux SCSI List, Linux Wireless List,
	DRI
In-Reply-To: <56acieJJ2fF.A.nEB.Hzl0KB@chimera>

Hi Rafael,

On Mon, Oct 12, 2009 at 12:41:30AM +0200, Rafael J. Wysocki wrote:
> Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=14185
> Subject		: Oops in driversbasefirmware_class
> Submitter	:  <lars_ericsson@telia.com>
> Date		: 2009-09-17 05:09 (25 days old)
> First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=6e03a201bbe8137487f340d26aa662110e324b20
> 
> 
> Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=14253
> Subject		: Oops in driversbasefirmware_class
> Submitter	: Lars Ericsson <Lars_Ericsson@telia.com>
> Date		: 2009-09-16 20:44 (26 days old)
> References	: http://lkml.org/lkml/2009/9/16/461
> Handled-By	: Frederik Deweerdt <frederik.deweerdt@xprog.eu>
> Patch		: http://patchwork.kernel.org/patch/49914/
> 
Those two are refering to the same bug.

Regards,
Frederik

^ permalink raw reply

* [PATCH 11/16] wl1271: Enable smart reflex
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Juuso Oikarinen
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

From: Juuso Oikarinen <juuso.oikarinen@nokia.com>

Enable and configure smart reflex. This should have a reducing impact on
power consumption.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271_acx.c  |   72 +++++++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/wl1271_acx.h  |   23 +++++++++
 drivers/net/wireless/wl12xx/wl1271_init.c |    5 ++
 3 files changed, 100 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index d5dac57..6c29890 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -998,3 +998,75 @@ out:
 	kfree(rx_conf);
 	return ret;
 }
+
+int wl1271_acx_smart_reflex(struct wl1271 *wl)
+{
+	struct acx_smart_reflex_state *sr_state = NULL;
+	struct acx_smart_reflex_config_params *sr_param = NULL;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "acx smart reflex");
+
+	sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL);
+	if (!sr_param) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* set cryptic smart reflex parameters - source TI reference code */
+	sr_param->error_table[0].len = 0x07;
+	sr_param->error_table[0].upper_limit = 0x03;
+	sr_param->error_table[0].values[0] = 0x18;
+	sr_param->error_table[0].values[1] = 0x10;
+	sr_param->error_table[0].values[2] = 0x05;
+	sr_param->error_table[0].values[3] = 0xfb;
+	sr_param->error_table[0].values[4] = 0xf0;
+	sr_param->error_table[0].values[5] = 0xe8;
+
+	sr_param->error_table[1].len = 0x07;
+	sr_param->error_table[1].upper_limit = 0x03;
+	sr_param->error_table[1].values[0] = 0x18;
+	sr_param->error_table[1].values[1] = 0x10;
+	sr_param->error_table[1].values[2] = 0x05;
+	sr_param->error_table[1].values[3] = 0xf6;
+	sr_param->error_table[1].values[4] = 0xf0;
+	sr_param->error_table[1].values[5] = 0xe8;
+
+	sr_param->error_table[2].len = 0x07;
+	sr_param->error_table[2].upper_limit = 0x03;
+	sr_param->error_table[2].values[0] = 0x18;
+	sr_param->error_table[2].values[1] = 0x10;
+	sr_param->error_table[2].values[2] = 0x05;
+	sr_param->error_table[2].values[3] = 0xfb;
+	sr_param->error_table[2].values[4] = 0xf0;
+	sr_param->error_table[2].values[5] = 0xe8;
+
+	ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS,
+				   sr_param, sizeof(*sr_param));
+	if (ret < 0) {
+		wl1271_warning("failed to set smart reflex params: %d", ret);
+		goto out;
+	}
+
+	sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL);
+	if (!sr_state) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* enable smart reflex */
+	sr_state->enable = 1;
+
+	ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE,
+				   sr_state, sizeof(*sr_state));
+	if (ret < 0) {
+		wl1271_warning("failed to set smart reflex params: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(sr_state);
+	kfree(sr_param);
+	return ret;
+
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
index 07256d2..0c704af 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
@@ -445,6 +445,25 @@ struct acx_bt_wlan_coex {
 	u8 pad[3];
 } __attribute__ ((packed));
 
+struct acx_smart_reflex_state {
+	struct acx_header header;
+
+	u8 enable;
+	u8 padding[3];
+};
+
+struct smart_reflex_err_table {
+	u8 len;
+	s8 upper_limit;
+	s8 values[14];
+};
+
+struct acx_smart_reflex_config_params {
+	struct acx_header header;
+
+	struct smart_reflex_err_table error_table[3];
+};
+
 #define PTA_ANTENNA_TYPE_DEF		  (0)
 #define PTA_BT_HP_MAXTIME_DEF		  (2000)
 #define PTA_WLAN_HP_MAX_TIME_DEF	  (5000)
@@ -1184,6 +1203,9 @@ enum {
 	ACX_PEER_HT_CAP             = 0x0057,
 	ACX_HT_BSS_OPERATION        = 0x0058,
 	ACX_COEX_ACTIVITY           = 0x0059,
+	ACX_SET_SMART_REFLEX_DEBUG  = 0x005A,
+	ACX_SET_SMART_REFLEX_STATE  = 0x005B,
+	ACX_SET_SMART_REFLEX_PARAMS = 0x005F,
 	DOT11_RX_MSDU_LIFE_TIME     = 0x1004,
 	DOT11_CUR_TX_PWR            = 0x100D,
 	DOT11_RX_DOT11_MODE         = 0x1012,
@@ -1233,5 +1255,6 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl);
 int wl1271_acx_mem_cfg(struct wl1271 *wl);
 int wl1271_acx_init_mem_config(struct wl1271 *wl);
 int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
+int wl1271_acx_smart_reflex(struct wl1271 *wl);
 
 #endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c
index bf4d0e1..f9315f6 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.c
+++ b/drivers/net/wireless/wl12xx/wl1271_init.c
@@ -394,6 +394,11 @@ int wl1271_hw_init(struct wl1271 *wl)
 	if (ret < 0)
 		goto out_free_memmap;
 
+	/* Configure smart reflex */
+	ret = wl1271_acx_smart_reflex(wl);
+	if (ret < 0)
+		goto out_free_memmap;
+
 	return 0;
 
  out_free_memmap:
-- 
1.5.6.5


^ permalink raw reply related

* [PATCH 09/16] wl1271: Update interrupt handling by removing an extra SPI read
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Juuso Oikarinen
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

From: Juuso Oikarinen <juuso.oikarinen@nokia.com>

Remove separate interrupt register reading from the interrupt handling
routine. This will slightly improve interrupt performance.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271_main.c |   74 ++++++++++++-----------------
 drivers/net/wireless/wl12xx/wl1271_reg.h  |    2 +-
 2 files changed, 31 insertions(+), 45 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 22d44ba..8ac9bc1 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -76,20 +76,14 @@ static void wl1271_power_on(struct wl1271 *wl)
 	wl->set_power(true);
 }
 
-static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status)
+static void wl1271_fw_status(struct wl1271 *wl,
+			     struct wl1271_fw_status *status)
 {
 	u32 total = 0;
 	int i;
 
-	/*
-	 * FIXME: Reading the FW status directly from the registers seems to
-	 * be the right thing to do, but it doesn't work.  And in the
-	 * reference driver, there is a workaround called
-	 * USE_SDIO_24M_WORKAROUND, which reads the status from memory
-	 * instead, so we do the same here.
-	 */
-
-	wl1271_spi_mem_read(wl, STATUS_MEM_ADDRESS, status, sizeof(*status));
+	wl1271_spi_reg_read(wl, FW_STATUS_ADDR, status,
+			    sizeof(*status), false);
 
 	wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
 		     "drv_rx_counter = %d, tx_results_counter = %d)",
@@ -114,11 +108,10 @@ static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status)
 	wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime;
 }
 
-#define WL1271_IRQ_MAX_LOOPS 10
 static void wl1271_irq_work(struct work_struct *work)
 {
-	u32 intr, ctr = WL1271_IRQ_MAX_LOOPS;
 	int ret;
+	u32 intr;
 	struct wl1271 *wl =
 		container_of(work, struct wl1271, irq_work);
 
@@ -135,7 +128,8 @@ static void wl1271_irq_work(struct work_struct *work)
 
 	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
 
-	intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+	wl1271_fw_status(wl, wl->fw_status);
+	intr = wl->fw_status->intr;
 	if (!intr) {
 		wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
 		goto out_sleep;
@@ -143,43 +137,35 @@ static void wl1271_irq_work(struct work_struct *work)
 
 	intr &= WL1271_INTR_MASK;
 
-	do {
-		wl1271_fw_status(wl, wl->fw_status);
-
-
-		if (intr & (WL1271_ACX_INTR_EVENT_A |
-			    WL1271_ACX_INTR_EVENT_B)) {
-			wl1271_debug(DEBUG_IRQ,
-				     "WL1271_ACX_INTR_EVENT (0x%x)", intr);
-			if (intr & WL1271_ACX_INTR_EVENT_A)
-				wl1271_event_handle(wl, 0);
-			else
-				wl1271_event_handle(wl, 1);
-		}
+	if (intr & (WL1271_ACX_INTR_EVENT_A |
+		    WL1271_ACX_INTR_EVENT_B)) {
+		wl1271_debug(DEBUG_IRQ,
+			     "WL1271_ACX_INTR_EVENT (0x%x)", intr);
+		if (intr & WL1271_ACX_INTR_EVENT_A)
+			wl1271_event_handle(wl, 0);
+		else
+			wl1271_event_handle(wl, 1);
+	}
 
-		if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
-			wl1271_debug(DEBUG_IRQ,
-				     "WL1271_ACX_INTR_INIT_COMPLETE");
+	if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
+		wl1271_debug(DEBUG_IRQ,
+			     "WL1271_ACX_INTR_INIT_COMPLETE");
 
-		if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
-			wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
+	if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
+		wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
 
-		if (intr & WL1271_ACX_INTR_DATA) {
-			u8 tx_res_cnt = wl->fw_status->tx_results_counter -
-				wl->tx_results_count;
+	if (intr & WL1271_ACX_INTR_DATA) {
+		u8 tx_res_cnt = wl->fw_status->tx_results_counter -
+			wl->tx_results_count;
 
-			wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
+		wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
 
-			/* check for tx results */
-			if (tx_res_cnt)
-				wl1271_tx_complete(wl, tx_res_cnt);
+		/* check for tx results */
+		if (tx_res_cnt)
+			wl1271_tx_complete(wl, tx_res_cnt);
 
-			wl1271_rx(wl, wl->fw_status);
-		}
-
-		intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
-		intr &= WL1271_INTR_MASK;
-	} while (intr && --ctr);
+		wl1271_rx(wl, wl->fw_status);
+	}
 
 out_sleep:
 	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h
index bd12615..6af87b5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_reg.h
+++ b/drivers/net/wireless/wl12xx/wl1271_reg.h
@@ -34,7 +34,7 @@
 #define REGISTERS_WORK_SIZE 0x0000b000
 
 #define HW_ACCESS_ELP_CTRL_REG_ADDR         0x1FFFC
-#define STATUS_MEM_ADDRESS                  0x40400
+#define FW_STATUS_ADDR                      (0x14FC0 + 0xA000)
 
 /* ELP register commands */
 #define ELPCTRL_WAKE_UP             0x1
-- 
1.5.6.5


^ permalink raw reply related

* [PATCH 10/16] wl1271: Enable ELP
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Juuso Oikarinen
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

From: Juuso Oikarinen <juuso.oikarinen@nokia.com>

The new firmware has fixed a firmware crash problem related to ELP entry.
Enable ELP to conserve power.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271_ps.c |    7 +------
 1 files changed, 1 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c
index 5580e53..fb821c9 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.c
@@ -39,12 +39,7 @@ void wl1271_elp_work(struct work_struct *work)
 
 	mutex_lock(&wl->mutex);
 
-	/*
-	 * FIXME: below, by means of the "true", ELP has been disabled for now
-	 * to work around a firmware bug. To be enabled upon receiving a new
-	 * firmware version.
-	 */
-	if (true || wl->elp || !wl->psm)
+	if (wl->elp || !wl->psm)
 		goto out;
 
 	wl1271_debug(DEBUG_PSM, "chip to elp");
-- 
1.5.6.5


^ permalink raw reply related

* [PATCH 02/16] wl1271: workaround to send a disconnect before rejoining
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

We don't get any indication from the stack when we have disassociated.  In
wl1271, it is important to send a CMD_DISCONNECT before joining again,
because the firmware cleans some things up.  So we check if we're already
joined and disconnect if that's the case.

Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Reviewed-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271.h      |    3 +++
 drivers/net/wireless/wl12xx/wl1271_cmd.c  |   15 +++++++++++++++
 drivers/net/wireless/wl12xx/wl1271_main.c |    3 +++
 3 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 96a5813..858bf6b 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -422,6 +422,9 @@ struct wl1271 {
 	struct wl1271_tx_hw_res_if *tx_res_if;
 
 	struct ieee80211_vif *vif;
+
+	/* Used for a workaround to send disconnect before rejoining */
+	bool joined;
 };
 
 int wl1271_plt_start(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index d09ad12..ef92834 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -191,6 +191,19 @@ int wl1271_cmd_join(struct wl1271 *wl)
 			do_cal = false;
 	}
 
+	/* FIXME: This is a workaround, because with the current stack, we
+	 * cannot know when we have disassociated.  So, if we have already
+	 * joined, we disconnect before joining again. */
+	if (wl->joined) {
+		ret = wl1271_cmd_disconnect(wl);
+		if (ret < 0) {
+			wl1271_error("failed to disconnect before rejoining");
+			goto out;
+		}
+
+		wl->joined = false;
+	}
+
 	join = kzalloc(sizeof(*join), GFP_KERNEL);
 	if (!join) {
 		ret = -ENOMEM;
@@ -245,6 +258,8 @@ int wl1271_cmd_join(struct wl1271 *wl)
 		goto out_free;
 	}
 
+	wl->joined = true;
+
 	/*
 	 * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
 	 * simplify locking we just sleep instead, for now
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 3662715..b9f2091 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -648,6 +648,8 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 	wl->tx_security_seq_32 = 0;
 	wl->time_offset = 0;
 	wl->session_counter = 0;
+	wl->joined = false;
+
 	for (i = 0; i < NUM_TX_QUEUES; i++)
 		wl->tx_blocks_freed[i] = 0;
 
@@ -1395,6 +1397,7 @@ static int __devinit wl1271_probe(struct spi_device *spi)
 	wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
 	wl->band = IEEE80211_BAND_2GHZ;
 	wl->vif = NULL;
+	wl->joined = false;
 
 	for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
 		wl->tx_frames[i] = NULL;
-- 
1.5.6.5


^ permalink raw reply related

* [PATCH 14/16] wl1271: Update boot time configuration for the new firmware
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Juuso Oikarinen
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

From: Juuso Oikarinen <juuso.oikarinen@nokia.com>

Update the magic values of the wl1271 boot time config according to the new
reference driver.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271_init.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c
index f9315f6..e45af07 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.c
+++ b/drivers/net/wireless/wl12xx/wl1271_init.c
@@ -202,7 +202,7 @@ static int wl1271_init_general_parms(struct wl1271 *wl)
 	gen_parms->clk_valid_on_wakeup = 0;
 	gen_parms->dc2dcmode = 0;
 	gen_parms->single_dual_band = 0;
-	gen_parms->tx_bip_fem_autodetect = 1;
+	gen_parms->tx_bip_fem_autodetect = 0;
 	gen_parms->tx_bip_fem_manufacturer = 1;
 	gen_parms->settings = 1;
 
-- 
1.5.6.5


^ permalink raw reply related

* [PATCH 13/16] wl1271: Remove outdated SPI functions
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Juuso Oikarinen
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

From: Juuso Oikarinen <juuso.oikarinen@nokia.com>

With the change to the new firmware, there was a change to firmware memory
partitioning. Along with that change, the translation of all partitions was
unified, and separate functions for reg and mem access became unnecessary.

Cleanup the unnecessary functions.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271_boot.c  |   63 +++++++++++----------
 drivers/net/wireless/wl12xx/wl1271_cmd.c   |   19 +++---
 drivers/net/wireless/wl12xx/wl1271_event.c |    8 +-
 drivers/net/wireless/wl12xx/wl1271_main.c  |   12 ++--
 drivers/net/wireless/wl12xx/wl1271_ps.c    |    4 +-
 drivers/net/wireless/wl12xx/wl1271_rx.c    |   10 ++--
 drivers/net/wireless/wl12xx/wl1271_spi.c   |   85 +++++++++-------------------
 drivers/net/wireless/wl12xx/wl1271_spi.h   |   36 +++++-------
 drivers/net/wireless/wl12xx/wl1271_tx.c    |   10 ++--
 9 files changed, 107 insertions(+), 140 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index b586577..a27601d 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -93,19 +93,19 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
 	u32 cpu_ctrl;
 
 	/* 10.5.0 run the firmware (I) */
-	cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+	cpu_ctrl = wl1271_spi_read32(wl, ACX_REG_ECPU_CONTROL);
 
 	/* 10.5.1 run the firmware (II) */
 	cpu_ctrl |= flag;
-	wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+	wl1271_spi_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
 }
 
 static void wl1271_boot_fw_version(struct wl1271 *wl)
 {
 	struct wl1271_static_data static_data;
 
-	wl1271_spi_mem_read(wl, wl->cmd_box_addr,
-			    &static_data, sizeof(static_data));
+	wl1271_spi_read(wl, wl->cmd_box_addr,
+			&static_data, sizeof(static_data), false);
 
 	strncpy(wl->chip.fw_ver, static_data.fw_version,
 		sizeof(wl->chip.fw_ver));
@@ -164,7 +164,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
 		memcpy(chunk, p, CHUNK_SIZE);
 		wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
 			     p, addr);
-		wl1271_spi_mem_write(wl, addr, chunk, CHUNK_SIZE);
+		wl1271_spi_write(wl, addr, chunk, CHUNK_SIZE, false);
 
 		chunk_num++;
 	}
@@ -175,7 +175,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
 	memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
 	wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
 		     fw_data_len % CHUNK_SIZE, p, addr);
-	wl1271_spi_mem_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE);
+	wl1271_spi_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
 
 	kfree(chunk);
 	return 0;
@@ -262,7 +262,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
 			wl1271_debug(DEBUG_BOOT,
 				     "nvs burst write 0x%x: 0x%x",
 				     dest_addr, val);
-			wl1271_reg_write32(wl, dest_addr, val);
+			wl1271_spi_write32(wl, dest_addr, val);
 
 			nvs_ptr += 4;
 			dest_addr += 4;
@@ -289,7 +289,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
 	/* FIXME: In wl1271, we upload everything at once.
 	   No endianness handling needed here?! The ref driver doesn't do
 	   anything about it at this point */
-	wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len);
+	wl1271_spi_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
 
 	kfree(nvs_aligned);
 	return 0;
@@ -298,9 +298,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
 static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
 {
 	enable_irq(wl->irq);
-	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
 			   WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
-	wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+	wl1271_spi_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
 }
 
 static int wl1271_boot_soft_reset(struct wl1271 *wl)
@@ -309,12 +309,13 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
 	u32 boot_data;
 
 	/* perform soft reset */
-	wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+	wl1271_spi_write32(wl, ACX_REG_SLV_SOFT_RESET,
+			   ACX_SLV_SOFT_RESET_BIT);
 
 	/* SOFT_RESET is self clearing */
 	timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
 	while (1) {
-		boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
+		boot_data = wl1271_spi_read32(wl, ACX_REG_SLV_SOFT_RESET);
 		wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
 		if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
 			break;
@@ -330,10 +331,10 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
 	}
 
 	/* disable Rx/Tx */
-	wl1271_reg_write32(wl, ENABLE, 0x0);
+	wl1271_spi_write32(wl, ENABLE, 0x0);
 
 	/* disable auto calibration on start*/
-	wl1271_reg_write32(wl, SPARE_A2, 0xffff);
+	wl1271_spi_write32(wl, SPARE_A2, 0xffff);
 
 	return 0;
 }
@@ -345,7 +346,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
 
 	wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
 
-	chip_id = wl1271_reg_read32(wl, CHIP_ID_B);
+	chip_id = wl1271_spi_read32(wl, CHIP_ID_B);
 
 	wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
 
@@ -358,7 +359,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
 	loop = 0;
 	while (loop++ < INIT_LOOP) {
 		udelay(INIT_LOOP_DELAY);
-		interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+		interrupt = wl1271_spi_read32(wl,
+					      ACX_REG_INTERRUPT_NO_CLEAR);
 
 		if (interrupt == 0xffffffff) {
 			wl1271_error("error reading hardware complete "
@@ -367,7 +369,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
 		}
 		/* check that ACX_INTR_INIT_COMPLETE is enabled */
 		else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
-			wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+			wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
 					   WL1271_ACX_INTR_INIT_COMPLETE);
 			break;
 		}
@@ -380,10 +382,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
 	}
 
 	/* get hardware config command mail box */
-	wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
+	wl->cmd_box_addr = wl1271_spi_read32(wl, REG_COMMAND_MAILBOX_PTR);
 
 	/* get hardware config event mail box */
-	wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+	wl->event_box_addr = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
 
 	/* set the working partition to its "running" mode offset */
 	wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -458,9 +460,9 @@ int wl1271_boot(struct wl1271 *wl)
 		wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
 	}
 
-	wl1271_reg_write32(wl, PLL_PARAMETERS, clk);
+	wl1271_spi_write32(wl, PLL_PARAMETERS, clk);
 
-	pause = wl1271_reg_read32(wl, PLL_PARAMETERS);
+	pause = wl1271_spi_read32(wl, PLL_PARAMETERS);
 
 	wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
 
@@ -469,10 +471,10 @@ int wl1271_boot(struct wl1271 *wl)
 					   * 0x3ff (magic number ).  How does
 					   * this work?! */
 	pause |= WU_COUNTER_PAUSE_VAL;
-	wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause);
+	wl1271_spi_write32(wl, WU_COUNTER_PAUSE, pause);
 
 	/* Continue the ELP wake up sequence */
-	wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+	wl1271_spi_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
 	udelay(500);
 
 	wl1271_set_partition(wl, &part_table[PART_DRPW]);
@@ -482,18 +484,18 @@ int wl1271_boot(struct wl1271 *wl)
 	   before taking DRPw out of reset */
 
 	wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
-	clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START);
+	clk = wl1271_spi_read32(wl, DRPW_SCRATCH_START);
 
 	wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
 
 	/* 2 */
 	clk |= (REF_CLOCK << 1) << 4;
-	wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk);
+	wl1271_spi_write32(wl, DRPW_SCRATCH_START, clk);
 
 	wl1271_set_partition(wl, &part_table[PART_WORK]);
 
 	/* Disable interrupts */
-	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
 
 	ret = wl1271_boot_soft_reset(wl);
 	if (ret < 0)
@@ -508,21 +510,22 @@ int wl1271_boot(struct wl1271 *wl)
 	 * ACX_EEPROMLESS_IND_REG */
 	wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
 
-	wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
+	wl1271_spi_write32(wl, ACX_EEPROMLESS_IND_REG,
+			   ACX_EEPROMLESS_IND_REG);
 
-	tmp = wl1271_reg_read32(wl, CHIP_ID_B);
+	tmp = wl1271_spi_read32(wl, CHIP_ID_B);
 
 	wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
 
 	/* 6. read the EEPROM parameters */
-	tmp = wl1271_reg_read32(wl, SCR_PAD2);
+	tmp = wl1271_spi_read32(wl, SCR_PAD2);
 
 	ret = wl1271_boot_write_irq_polarity(wl);
 	if (ret < 0)
 		goto out;
 
 	/* FIXME: Need to check whether this is really what we want */
-	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
 			   WL1271_ACX_ALL_EVENTS_VECTOR);
 
 	/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index ef92834..f727744 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -55,13 +55,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len)
 
 	WARN_ON(len % 4 != 0);
 
-	wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
+	wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false);
 
-	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
 
 	timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
 
-	intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+	intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
 	while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
 		if (time_after(jiffies, timeout)) {
 			wl1271_error("command complete timeout");
@@ -71,10 +71,10 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len)
 
 		msleep(1);
 
-		intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+		intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
 	}
 
-	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
 			   WL1271_ACX_INTR_CMD_COMPLETE);
 
 out:
@@ -302,7 +302,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
 		 * The answer would be a wl1271_command, where the
 		 * parameter array contains the actual answer.
 		 */
-		wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+		wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false);
 
 		cmd_answer = buf;
 
@@ -341,7 +341,7 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
 	}
 
 	/* the interrogate command got in, we can read the answer */
-	wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
+	wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false);
 
 	acx = buf;
 	if (acx->cmd.status != CMD_STATUS_SUCCESS)
@@ -496,7 +496,7 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
 	}
 
 	/* the read command got in, we can now read the answer */
-	wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+	wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false);
 
 	if (cmd->header.status != CMD_STATUS_SUCCESS)
 		wl1271_error("error in read command result: %d",
@@ -591,7 +591,8 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
 		goto out;
 	}
 
-	wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+	wl1271_spi_read(wl, wl->cmd_box_addr, params, sizeof(*params),
+			false);
 
 	if (params->header.status != CMD_STATUS_SUCCESS) {
 		wl1271_error("Scan command error: %d",
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index f329276..4189e97 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -98,7 +98,7 @@ int wl1271_event_unmask(struct wl1271 *wl)
 
 void wl1271_event_mbox_config(struct wl1271 *wl)
 {
-	wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+	wl->mbox_ptr[0] = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
 	wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
 
 	wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
@@ -116,8 +116,8 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
 		return -EINVAL;
 
 	/* first we read the mbox descriptor */
-	wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
-			    sizeof(struct event_mailbox));
+	wl1271_spi_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+			sizeof(struct event_mailbox), false);
 
 	/* process the descriptor */
 	ret = wl1271_event_process(wl, &mbox);
@@ -125,7 +125,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
 		return ret;
 
 	/* then we let the firmware know it can go on...*/
-	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
+	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 8ac9bc1..5ef0bd5 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -82,8 +82,8 @@ static void wl1271_fw_status(struct wl1271 *wl,
 	u32 total = 0;
 	int i;
 
-	wl1271_spi_reg_read(wl, FW_STATUS_ADDR, status,
-			    sizeof(*status), false);
+	wl1271_spi_read(wl, FW_STATUS_ADDR, status,
+			sizeof(*status), false);
 
 	wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
 		     "drv_rx_counter = %d, tx_results_counter = %d)",
@@ -126,7 +126,7 @@ static void wl1271_irq_work(struct work_struct *work)
 	if (ret < 0)
 		goto out;
 
-	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
 
 	wl1271_fw_status(wl, wl->fw_status);
 	intr = wl->fw_status->intr;
@@ -168,7 +168,7 @@ static void wl1271_irq_work(struct work_struct *work)
 	}
 
 out_sleep:
-	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
 			   WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
 	wl1271_ps_elp_sleep(wl);
 
@@ -279,7 +279,7 @@ static void wl1271_fw_wakeup(struct wl1271 *wl)
 	u32 elp_reg;
 
 	elp_reg = ELPCTRL_WAKE_UP;
-	wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+	wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
 }
 
 static int wl1271_setup(struct wl1271 *wl)
@@ -322,7 +322,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 	/* whal_FwCtrl_BootSm() */
 
 	/* 0. read chip id from CHIP_ID */
-	wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B);
+	wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
 
 	/* 1. check if chip id is valid */
 
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c
index fb821c9..bb8745d 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.c
@@ -43,7 +43,7 @@ void wl1271_elp_work(struct work_struct *work)
 		goto out;
 
 	wl1271_debug(DEBUG_PSM, "chip to elp");
-	wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+	wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
 	wl->elp = true;
 
 out:
@@ -86,7 +86,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
 		wl->elp_compl = &compl;
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 
-	wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+	wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
 
 	if (!pending) {
 		ret = wait_for_completion_timeout(
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index 1d98653..7979b69 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -132,7 +132,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
 	}
 
 	buf = skb_put(skb, length);
-	wl1271_spi_reg_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
+	wl1271_spi_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
 
 	/* the data read starts with the descriptor */
 	desc = (struct wl1271_rx_descriptor *) buf;
@@ -176,9 +176,9 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
 			wl->rx_mem_pool_addr.addr + 4;
 
 		/* Choose the block we want to read */
-		wl1271_spi_reg_write(wl, WL1271_SLV_REG_DATA,
-				     &wl->rx_mem_pool_addr,
-				     sizeof(wl->rx_mem_pool_addr), false);
+		wl1271_spi_write(wl, WL1271_SLV_REG_DATA,
+				 &wl->rx_mem_pool_addr,
+				 sizeof(wl->rx_mem_pool_addr), false);
 
 		wl1271_rx_handle_data(wl, buf_size);
 
@@ -186,5 +186,5 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
 		drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
 	}
 
-	wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
+	wl1271_spi_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
 }
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 7a7890b..4800fdf 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -183,13 +183,13 @@ int wl1271_set_partition(struct wl1271 *wl,
 		     p->mem3.start, p->mem3.size);
 
 	/* write partition info to the chipset */
-	wl1271_write32(wl, HW_PART0_START_ADDR, p->mem.start);
-	wl1271_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
-	wl1271_write32(wl, HW_PART1_START_ADDR, p->reg.start);
-	wl1271_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
-	wl1271_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
-	wl1271_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
-	wl1271_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
+	wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
+	wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
+	wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
+	wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
+	wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
+	wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
+	wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
 
 	return 0;
 }
@@ -257,8 +257,8 @@ void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
 	wl1271_error("SPI read busy-word timeout!\n");
 }
 
-void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
-		     size_t len, bool fixed)
+void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
+			 size_t len, bool fixed)
 {
 	struct spi_transfer t[3];
 	struct spi_message m;
@@ -302,8 +302,8 @@ void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
 	wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
 }
 
-void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
-		      size_t len, bool fixed)
+void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
+			  size_t len, bool fixed)
 {
 	struct spi_transfer t[2];
 	struct spi_message m;
@@ -336,77 +336,47 @@ void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
 	wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
 }
 
-void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf,
-			 size_t len)
+void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+		     bool fixed)
 {
 	int physical;
 
 	physical = wl1271_translate_addr(wl, addr);
 
-	wl1271_spi_read(wl, physical, buf, len, false);
+	wl1271_spi_raw_read(wl, physical, buf, len, fixed);
 }
 
-void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf,
-			  size_t len)
+void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+		      bool fixed)
 {
 	int physical;
 
 	physical = wl1271_translate_addr(wl, addr);
 
-	wl1271_spi_write(wl, physical, buf, len, false);
+	wl1271_spi_raw_write(wl, physical, buf, len, fixed);
 }
 
-void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len,
-			 bool fixed)
+u32 wl1271_spi_read32(struct wl1271 *wl, int addr)
 {
-	int physical;
-
-	physical = wl1271_translate_addr(wl, addr);
-
-	wl1271_spi_read(wl, physical, buf, len, fixed);
-}
-
-void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len,
-			  bool fixed)
-{
-	int physical;
-
-	physical = wl1271_translate_addr(wl, addr);
-
-	wl1271_spi_write(wl, physical, buf, len, fixed);
+	return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
 }
 
-u32 wl1271_mem_read32(struct wl1271 *wl, int addr)
+void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val)
 {
-	return wl1271_read32(wl, wl1271_translate_addr(wl, addr));
-}
-
-void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val)
-{
-	wl1271_write32(wl, wl1271_translate_addr(wl, addr), val);
-}
-
-u32 wl1271_reg_read32(struct wl1271 *wl, int addr)
-{
-	return wl1271_read32(wl, wl1271_translate_addr(wl, addr));
-}
-
-void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val)
-{
-	wl1271_write32(wl, wl1271_translate_addr(wl, addr), val);
+	wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
 }
 
 void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
 {
 	/* write address >> 1 + 0x30000 to OCP_POR_CTR */
 	addr = (addr >> 1) + 0x30000;
-	wl1271_reg_write32(wl, OCP_POR_CTR, addr);
+	wl1271_spi_write32(wl, OCP_POR_CTR, addr);
 
 	/* write value to OCP_POR_WDATA */
-	wl1271_reg_write32(wl, OCP_DATA_WRITE, val);
+	wl1271_spi_write32(wl, OCP_DATA_WRITE, val);
 
 	/* write 1 to OCP_CMD */
-	wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE);
+	wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_WRITE);
 }
 
 u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
@@ -416,14 +386,14 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
 
 	/* write address >> 1 + 0x30000 to OCP_POR_CTR */
 	addr = (addr >> 1) + 0x30000;
-	wl1271_reg_write32(wl, OCP_POR_CTR, addr);
+	wl1271_spi_write32(wl, OCP_POR_CTR, addr);
 
 	/* write 2 to OCP_CMD */
-	wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ);
+	wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_READ);
 
 	/* poll for data ready */
 	do {
-		val = wl1271_reg_read32(wl, OCP_DATA_READ);
+		val = wl1271_spi_read32(wl, OCP_DATA_READ);
 		timeout--;
 	} while (!(val & OCP_READY_MASK) && timeout);
 
@@ -440,4 +410,3 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
 		return 0xffff;
 	}
 }
-
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h
index 4f1608e..cb7df1c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.h
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.h
@@ -85,24 +85,18 @@
 #define OCP_STATUS_RESP_ERROR 0x30000
 
 /* Raw target IO, address is not translated */
-void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
+void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
 		      size_t len, bool fixed);
-void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
+void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
 		     size_t len, bool fixed);
 
-/* Memory target IO, address is tranlated to partition 0 */
-void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, size_t len);
-void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, size_t len);
-u32 wl1271_mem_read32(struct wl1271 *wl, int addr);
-void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val);
-
-/* Registers IO */
-void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len,
-			 bool fixed);
-void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len,
-			  bool fixed);
-u32 wl1271_reg_read32(struct wl1271 *wl, int addr);
-void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val);
+/* Translated target IO */
+void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+		     bool fixed);
+void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+		      bool fixed);
+u32 wl1271_spi_read32(struct wl1271 *wl, int addr);
+void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val);
 
 /* Top Register IO */
 void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
@@ -114,19 +108,19 @@ void wl1271_spi_init(struct wl1271 *wl);
 int wl1271_set_partition(struct wl1271 *wl,
 			 struct wl1271_partition_set *p);
 
-static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
+static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
 {
-	wl1271_spi_read(wl, addr, &wl->buffer_32,
-			sizeof(wl->buffer_32), false);
+	wl1271_spi_raw_read(wl, addr, &wl->buffer_32,
+			    sizeof(wl->buffer_32), false);
 
 	return wl->buffer_32;
 }
 
-static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
+static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
 {
 	wl->buffer_32 = val;
-	wl1271_spi_write(wl, addr, &wl->buffer_32,
-			 sizeof(wl->buffer_32), false);
+	wl1271_spi_raw_write(wl, addr, &wl->buffer_32,
+			     sizeof(wl->buffer_32), false);
 }
 
 #endif /* __WL1271_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 56a7f36..4560458 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -154,11 +154,11 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
 	len = WL1271_TX_ALIGN(skb->len);
 
 	/* perform a fixed address block write with the packet */
-	wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
+	wl1271_spi_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
 
 	/* write packet new counter into the write access register */
 	wl->tx_packets_count++;
-	wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+	wl1271_spi_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
 
 	desc = (struct wl1271_tx_hw_descr *) skb->data;
 	wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
@@ -331,8 +331,8 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
 	wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
 
 	/* read the tx results from the chipset */
-	wl1271_spi_mem_read(wl, memmap->tx_result,
-			    wl->tx_res_if, sizeof(*wl->tx_res_if));
+	wl1271_spi_read(wl, memmap->tx_result,
+			wl->tx_res_if, sizeof(*wl->tx_res_if), false);
 
 	/* verify that the result buffer is not getting overrun */
 	if (count > TX_HW_RESULT_QUEUE_LEN) {
@@ -353,7 +353,7 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
 	}
 
 	/* write host counter to chipset (to ack) */
-	wl1271_mem_write32(wl, memmap->tx_result +
+	wl1271_spi_write32(wl, memmap->tx_result +
 			   offsetof(struct wl1271_tx_hw_res_if,
 				    tx_result_host_counter),
 			   wl->tx_res_if->tx_result_fw_counter);
-- 
1.5.6.5


^ permalink raw reply related

* [PATCH 16/16] wl1271: remove unnecessary joins and join only when the bssid changes
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

We were using the join command to change some settings when the stack asked
us to do it.  In many cases they were not needed (and could cause potential
problems), so they were removed.  In other cases there are ACX commands that
can be used instead of using join to reconfigure.

Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Reviewed-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271.h      |    4 --
 drivers/net/wireless/wl12xx/wl1271_cmd.c  |    4 +-
 drivers/net/wireless/wl12xx/wl1271_main.c |   61 ++++++++++------------------
 3 files changed, 24 insertions(+), 45 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index b2bc7b5..aa9bb2e 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -378,10 +378,6 @@ struct wl1271 {
 	/* Our association ID */
 	u16 aid;
 
-	/* Beacon parameters */
-	u16 beacon_int;
-	u8 dtim_period;
-
 	/* currently configured rate set */
 	u32 basic_rate_set;
 
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index f727744..eaa1de9 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -232,8 +232,8 @@ int wl1271_cmd_join(struct wl1271 *wl)
 	join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
 		RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
 
-	join->beacon_interval = wl->beacon_int;
-	join->dtim_interval = wl->dtim_period;
+	join->beacon_interval = WL1271_DEFAULT_BEACON_INT;
+	join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
 	join->bss_type = wl->bss_type;
 	join->channel = wl->channel;
 	join->ssid_len = wl->ssid_len;
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index fc0d03f..821a775 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -710,7 +710,15 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
 	if (ret < 0)
 		goto out;
 
-	memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+	if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
+		wl1271_debug(DEBUG_MAC80211, "bssid changed");
+
+		memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+
+		ret = wl1271_cmd_join(wl);
+		if (ret < 0)
+			goto out_sleep;
+	}
 
 	ret = wl1271_cmd_build_null_data(wl);
 	if (ret < 0)
@@ -720,12 +728,6 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
 	if (wl->ssid_len)
 		memcpy(wl->ssid, conf->ssid, wl->ssid_len);
 
-	if (wl->bss_type != BSS_TYPE_IBSS) {
-		ret = wl1271_cmd_join(wl);
-		if (ret < 0)
-			goto out_sleep;
-	}
-
 	if (conf->changed & IEEE80211_IFCC_BEACON) {
 		beacon = ieee80211_beacon_get(hw, vif);
 		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
@@ -743,11 +745,6 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
 
 		if (ret < 0)
 			goto out_sleep;
-
-		ret = wl1271_cmd_join(wl);
-
-		if (ret < 0)
-			goto out_sleep;
 	}
 
 out_sleep:
@@ -782,14 +779,13 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 		goto out;
 
 	if (channel != wl->channel) {
-		u8 old_channel = wl->channel;
+		/*
+		 * We assume that the stack will configure the right channel
+		 * before associating, so we don't need to send a join
+		 * command here.  We will join the right channel when the
+		 * BSSID changes
+		 */
 		wl->channel = channel;
-
-		ret = wl1271_cmd_join(wl);
-		if (ret < 0) {
-			wl->channel = old_channel;
-			goto out_sleep;
-		}
 	}
 
 	ret = wl1271_cmd_build_null_data(wl);
@@ -1102,17 +1098,14 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 
 	if (changed & BSS_CHANGED_ASSOC) {
 		if (bss_conf->assoc) {
-			wl->beacon_int = bss_conf->beacon_int;
-			wl->dtim_period = bss_conf->dtim_period;
 			wl->aid = bss_conf->aid;
 
-			ret = wl1271_cmd_join(wl);
-			if (ret < 0) {
-				wl1271_warning("Association configuration "
-					       "failed %d", ret);
-				goto out_sleep;
-			}
-
+			/*
+			 * with wl1271, we don't need to update the
+			 * beacon_int and dtim_period, because the firmware
+			 * updates it by itself when the first beacon is
+			 * received after a join.
+			 */
 			ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
 			if (ret < 0)
 				goto out_sleep;
@@ -1130,8 +1123,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 			}
 		} else {
 			/* use defaults when not associated */
-			wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
-			wl->dtim_period = WL1271_DEFAULT_DTIM_PERIOD;
 			wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
 			wl->aid = 0;
 		}
@@ -1170,18 +1161,12 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 	if (changed & BSS_CHANGED_BASIC_RATES) {
 		wl->basic_rate_set = wl1271_enabled_rates_get(
 			wl, bss_conf->basic_rates);
-		ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
 
+		ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
 		if (ret < 0) {
 			wl1271_warning("Set rate policies failed %d", ret);
 			goto out_sleep;
 		}
-		ret = wl1271_cmd_join(wl);
-		if (ret < 0) {
-			wl1271_warning("Join with new basic rate "
-				       "set failed %d", ret);
-			goto out_sleep;
-		}
 	}
 
 out_sleep:
@@ -1380,8 +1365,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
 	wl->psm_requested = false;
 	wl->tx_queue_stopped = false;
 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
-	wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
-	wl->dtim_period = WL1271_DEFAULT_DTIM_PERIOD;
 	wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
 	wl->band = IEEE80211_BAND_2GHZ;
 	wl->vif = NULL;
-- 
1.5.6.5


^ permalink raw reply related

* [PATCH 03/16] wl1271: add workaround to avoid distortion due to excessive tx power
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

We still don't have proper calibration for our devices, so we are using way
too much power for TX, which causes a lot of distortion.  This hack hardcodes
the txpower to 7dBm.

Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Reviewed-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271_acx.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index b9dfa09..d5dac57 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -137,7 +137,12 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
 		goto out;
 	}
 
-	acx->current_tx_power = power * 10;
+	/*
+	 * FIXME: This is a workaround needed while we don't the correct
+	 * calibration, to avoid distortions
+	 */
+	/* acx->current_tx_power = power * 10; */
+	acx->current_tx_power = 70;
 
 	ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
 	if (ret < 0) {
-- 
1.5.6.5


^ permalink raw reply related

* [PATCH 01/16] wl1271: implement cmd_disconnect
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

This patch implements the CMD_DISCONNECT command, which should be sent to the
firmware when we are disassociated.

Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Reviewed-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271_cmd.c |   32 +++++++++++++++++++++++++++++-
 drivers/net/wireless/wl12xx/wl1271_cmd.h |   27 +++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index ac93efd..d09ad12 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -191,7 +191,6 @@ int wl1271_cmd_join(struct wl1271 *wl)
 			do_cal = false;
 	}
 
-
 	join = kzalloc(sizeof(*join), GFP_KERNEL);
 	if (!join) {
 		ret = -ENOMEM;
@@ -825,3 +824,34 @@ out:
 
 	return ret;
 }
+
+int wl1271_cmd_disconnect(struct wl1271 *wl)
+{
+	struct wl1271_cmd_disconnect *cmd;
+	int ret = 0;
+
+	wl1271_debug(DEBUG_CMD, "cmd disconnect");
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cmd->rx_config_options = wl->rx_config;
+	cmd->rx_filter_options = wl->rx_filter;
+	/* disconnect reason is not used in immediate disconnections */
+	cmd->type = DISCONNECT_IMMEDIATE;
+
+	ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd));
+	if (ret < 0) {
+		wl1271_error("failed to send disconnect command");
+		goto out_free;
+	}
+
+out_free:
+	kfree(cmd);
+
+out:
+	return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index 63bc441..0219664 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -50,6 +50,7 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
 int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
 		       u8 key_size, const u8 *key, const u8 *addr,
 		       u32 tx_seq_32, u16 tx_seq_16);
+int wl1271_cmd_disconnect(struct wl1271 *wl);
 
 enum wl1271_commands {
 	CMD_INTERROGATE     = 1,    /*use this to read information elements*/
@@ -461,4 +462,30 @@ struct wl1271_cmd_cal_p2g {
 	u8  padding2;
 } __attribute__ ((packed));
 
+
+/*
+ * There are three types of disconnections:
+ *
+ * DISCONNECT_IMMEDIATE: the fw doesn't send any frames
+ * DISCONNECT_DEAUTH:    the fw generates a DEAUTH request with the reason
+ *                       we have passed
+ * DISCONNECT_DISASSOC:  the fw generates a DESASSOC request with the reason
+ *                       we have passed
+ */
+enum wl1271_disconnect_type {
+	DISCONNECT_IMMEDIATE,
+	DISCONNECT_DEAUTH,
+	DISCONNECT_DISASSOC
+};
+
+struct wl1271_cmd_disconnect {
+	u32 rx_config_options;
+	u32 rx_filter_options;
+
+	u16 reason;
+	u8  type;
+
+	u8  padding;
+} __attribute__ ((packed));
+
 #endif /* __WL1271_CMD_H__ */
-- 
1.5.6.5


^ permalink raw reply related

* [PATCH 07/16] wl1271: Add top-register access functions
From: Luciano Coelho @ 2009-10-12 12:08 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Juuso Oikarinen
In-Reply-To: <1255349337-9776-1-git-send-email-luciano.coelho@nokia.com>

From: Juuso Oikarinen <juuso.oikarinen@nokia.com>

Add top register access function.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
---
 drivers/net/wireless/wl12xx/wl1271_boot.c |   27 ++---------------
 drivers/net/wireless/wl12xx/wl1271_boot.h |   15 +---------
 drivers/net/wireless/wl12xx/wl1271_spi.c  |   46 +++++++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/wl1271_spi.h  |   16 ++++++++++
 4 files changed, 66 insertions(+), 38 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index 2eb7836..1a3084c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -419,34 +419,13 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
 
 static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
 {
-	u32 polarity, status, i;
+	u32 polarity;
 
-	wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
-	wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ);
-
-	/* Wait until the command is complete (ie. bit 18 is set) */
-	for (i = 0; i < OCP_CMD_LOOP; i++) {
-		polarity = wl1271_reg_read32(wl, OCP_DATA_READ);
-		if (polarity & OCP_READY_MASK)
-			break;
-	}
-	if (i == OCP_CMD_LOOP) {
-		wl1271_error("OCP command timeout!");
-		return -EIO;
-	}
-
-	status = polarity & OCP_STATUS_MASK;
-	if (status != OCP_STATUS_OK) {
-		wl1271_error("OCP command failed (%d)", status);
-		return -EIO;
-	}
+	polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
 
 	/* We use HIGH polarity, so unset the LOW bit */
 	polarity &= ~POLARITY_LOW;
-
-	wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
-	wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity);
-	wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE);
+	wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h
index b0d8fb4..4501653 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.h
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.h
@@ -50,20 +50,7 @@ struct wl1271_static_data {
 #define WU_COUNTER_PAUSE_VAL 0x3FF
 #define WELP_ARM_COMMAND_VAL 0x4
 
-#define OCP_CMD_LOOP  32
-
-#define OCP_CMD_WRITE 0x1
-#define OCP_CMD_READ  0x2
-
-#define OCP_READY_MASK  BIT(18)
-#define OCP_STATUS_MASK (BIT(16) | BIT(17))
-
-#define OCP_STATUS_NO_RESP    0x00000
-#define OCP_STATUS_OK         0x10000
-#define OCP_STATUS_REQ_FAILED 0x20000
-#define OCP_STATUS_RESP_ERROR 0x30000
-
-#define OCP_REG_POLARITY 0x30032
+#define OCP_REG_POLARITY 0x0064
 
 #define CMD_MBOX_ADDRESS 0x407B4
 
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 367f2d3..7a7890b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -395,3 +395,49 @@ void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val)
 {
 	wl1271_write32(wl, wl1271_translate_addr(wl, addr), val);
 }
+
+void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
+{
+	/* write address >> 1 + 0x30000 to OCP_POR_CTR */
+	addr = (addr >> 1) + 0x30000;
+	wl1271_reg_write32(wl, OCP_POR_CTR, addr);
+
+	/* write value to OCP_POR_WDATA */
+	wl1271_reg_write32(wl, OCP_DATA_WRITE, val);
+
+	/* write 1 to OCP_CMD */
+	wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE);
+}
+
+u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
+{
+	u32 val;
+	int timeout = OCP_CMD_LOOP;
+
+	/* write address >> 1 + 0x30000 to OCP_POR_CTR */
+	addr = (addr >> 1) + 0x30000;
+	wl1271_reg_write32(wl, OCP_POR_CTR, addr);
+
+	/* write 2 to OCP_CMD */
+	wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ);
+
+	/* poll for data ready */
+	do {
+		val = wl1271_reg_read32(wl, OCP_DATA_READ);
+		timeout--;
+	} while (!(val & OCP_READY_MASK) && timeout);
+
+	if (!timeout) {
+		wl1271_warning("Top register access timed out.");
+		return 0xffff;
+	}
+
+	/* check data status and return if OK */
+	if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
+		return val & 0xffff;
+	else {
+		wl1271_warning("Top register access returned error.");
+		return 0xffff;
+	}
+}
+
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h
index c58e027..4f1608e 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.h
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.h
@@ -71,6 +71,18 @@
 		((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
 #define HW_ACCESS_WSPI_INIT_CMD_MASK  0
 
+#define OCP_CMD_LOOP  32
+
+#define OCP_CMD_WRITE 0x1
+#define OCP_CMD_READ  0x2
+
+#define OCP_READY_MASK  BIT(18)
+#define OCP_STATUS_MASK (BIT(16) | BIT(17))
+
+#define OCP_STATUS_NO_RESP    0x00000
+#define OCP_STATUS_OK         0x10000
+#define OCP_STATUS_REQ_FAILED 0x20000
+#define OCP_STATUS_RESP_ERROR 0x30000
 
 /* Raw target IO, address is not translated */
 void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
@@ -92,6 +104,10 @@ void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len,
 u32 wl1271_reg_read32(struct wl1271 *wl, int addr);
 void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val);
 
+/* Top Register IO */
+void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
+u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
+
 /* INIT and RESET words */
 void wl1271_spi_reset(struct wl1271 *wl);
 void wl1271_spi_init(struct wl1271 *wl);
-- 
1.5.6.5


^ permalink raw reply related


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