Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH/RFC] ath5k: clear rx queue on reset
From: Bob Copeland @ 2009-09-07 12:45 UTC (permalink / raw)
  To: lrodriguez; +Cc: mickflemm, jirislaby, ath5k-devel, linux-wireless


When changing channels or otherwise resetting the card, dump
any queued rx buffers so that we don't use the wrong channel
information when reporting the packets.  This should fix the
remaining instances of this warning:

WARNING: at /build/buildd-linux-2.6_2.6.30-1-i386-06t6n0/linux-2.6-2.6.30/debian/build/source_i386_none/drivers/net/wireless/ath5k/base.c:1096 ath5k_hw_to_driver_rix+0x52/0x58 [ath5k]()
Hardware name: MacBook1,1
invalid hw_rix: 1b
Modules linked in: i915 drm i2c_algo_bit binfmt_misc uvcvideo videodev v4l1_compat btusb rfcomm l2cap bluetooth ppdev parport_pc lp parport acpi_cpufreq cpufreq_powersave cpufreq_conservative cpufreq_userspace cpufreq_stats ext4 jbd2 crc16 ext2 fuse arc4 ecb ath5k mac80211 cfg80211 firewire_sbp2 loop joydev applesmc led_class input_polldev snd_hda_codec_idt isight_firmware pcspkr i2c_i801 i2c_core rng_core appletouch evdev iTCO_wdt snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq snd_timer snd_seq_device tpm_infineon tpm tpm_bios video output battery processor ac button snd soundcore snd_page_alloc intel_agp agpgart ext3 jbd mbcache usbhid dm_mirror dm_region_hash dm_log dm_snapshot dm_mod sd_mod crc_t10dif ide_cd_mod cdrom ata_piix ata_generic libata scsi_mod firewire_ohci firewire_core crc_itu_t ehci_hcd uhci_hcd ide_pci_generic piix ide_core sky2 usbcore thermal fan thermal_sys hid_apple hid
Pid: 5218, comm: euphoria Tainted: G        W  2.6.30-1-686 #1
Call Trace:
 [<c0126ff8>] ? warn_slowpath_common+0x5e/0x8a
 [<c0127056>] ? warn_slowpath_fmt+0x26/0x2a
 [<f86c139b>] ? ath5k_hw_to_driver_rix+0x52/0x58 [ath5k]
 [<f86c1899>] ? ath5k_tasklet_rx+0x2b7/0x42e [ath5k]
 [<c012e618>] ? __mod_timer+0xc9/0xd3
 [<c012abcf>] ? tasklet_action+0x63/0xa8
 [<c012b0d7>] ? __do_softirq+0x8e/0x135
 [<c012b1ac>] ? do_softirq+0x2e/0x38
 [<c012b28f>] ? irq_exit+0x26/0x53
 [<c01105c6>] ? smp_apic_timer_interrupt+0x6c/0x76
 [<c0103966>] ? apic_timer_interrupt+0x2a/0x30
 [<c01100d8>] ? lapic_suspend+0x47/0x15c
 [<f8ab68df>] ? drm_clflush_pages+0x3b/0x68 [drm]
 [<f8b0ad19>] ? i915_gem_execbuffer+0x6cf/0xbdd [i915]
 [<f8b08b88>] ? i915_gem_busy_ioctl+0x73/0x7a [i915]
 [<f8ab7667>] ? drm_ioctl+0x1ca/0x24b [drm]
 [<f8b0a64a>] ? i915_gem_execbuffer+0x0/0xbdd [i915]
 [<c011cc82>] ? update_curr+0x58/0x178
 [<c0138b88>] ? hrtimer_forward+0x10c/0x124
 [<c013d424>] ? getnstimeofday+0x4d/0xca
 [<c0197064>] ? vfs_ioctl+0x49/0x5f
 [<c01974be>] ? do_vfs_ioctl+0x444/0x47f
 [<c01052e6>] ? timer_interrupt+0x32/0x38
 [<c015a9e5>] ? handle_IRQ_event+0x4e/0x101
 [<c015bbdf>] ? handle_edge_irq+0xc6/0xe6
 [<c019753a>] ? sys_ioctl+0x41/0x58
 [<c0103014>] ? sysenter_do_call+0x12/0x28
---[ end trace 56450801255ccacd ]---

Signed-off-by: Bob Copeland <me@bobcopeland.com>
---

Luis, what do you think of this for the time being?

I also tried just calling the tasklet so that we don't lose this
information.  This makes the locking a bit more complicated since
reset can run in process or softirq context and I didn't quite get
it working right, though it would be a worthy avenue to persue.

This seems to work ok though -- it artificially dropped about 50
packets while running iperf in parallel with continual scans for
10 minutes, but I still got decent iperf numbers.

 drivers/net/wireless/ath/ath5k/base.c |   53 ++++++++++++++++++++------------
 1 files changed, 33 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 9c6ab53..1f62325 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -548,6 +548,8 @@ ath5k_pci_probe(struct pci_dev *pdev,
 
 	sc->iobase = mem; /* So we can unmap it on detach */
 	sc->common.cachelsz = csz << 2; /* convert to bytes */
+	sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
+
 	sc->opmode = NL80211_IFTYPE_STATION;
 	sc->bintval = 1000;
 	mutex_init(&sc->lock);
@@ -1221,6 +1223,32 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
 	return 0;
 }
 
+/*
+ * Clear out any unprocessed RX buffers and reset the buffers to
+ * their initial state.
+ */
+static int
+ath5k_rxbuf_init(struct ath5k_softc *sc)
+{
+	int ret;
+	struct ath5k_buf *bf;
+
+	spin_lock_bh(&sc->rxbuflock);
+	sc->rxlink = NULL;
+	list_for_each_entry(bf, &sc->rxbuf, list) {
+		ret = ath5k_rxbuf_setup(sc, bf);
+		if (ret)
+			goto err;
+	}
+	bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
+	ath5k_hw_set_rxdp(sc->ah, bf->daddr);
+	ret = 0;
+err:
+	spin_unlock_bh(&sc->rxbuflock);
+	return ret;
+}
+
+
 static int
 ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
 		  struct ath5k_txq *txq)
@@ -1606,32 +1634,17 @@ static int
 ath5k_rx_start(struct ath5k_softc *sc)
 {
 	struct ath5k_hw *ah = sc->ah;
-	struct ath5k_buf *bf;
 	int ret;
 
-	sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
-
-	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
-		sc->common.cachelsz, sc->rxbufsize);
-
-	spin_lock_bh(&sc->rxbuflock);
-	sc->rxlink = NULL;
-	list_for_each_entry(bf, &sc->rxbuf, list) {
-		ret = ath5k_rxbuf_setup(sc, bf);
-		if (ret != 0) {
-			spin_unlock_bh(&sc->rxbuflock);
-			goto err;
-		}
-	}
-	bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
-	ath5k_hw_set_rxdp(ah, bf->daddr);
-	spin_unlock_bh(&sc->rxbuflock);
+	ret = ath5k_rxbuf_init(sc);
+	if (ret)
+		goto err;
 
 	ath5k_hw_start_rx_dma(ah);	/* enable recv descriptors */
 	ath5k_mode_setup(sc);		/* set filters, etc. */
 	ath5k_hw_start_rx_pcu(ah);	/* re-enable PCU/DMA engine */
 
-	return 0;
+	ret = 0;
 err:
 	return ret;
 }
@@ -1650,7 +1663,7 @@ ath5k_rx_stop(struct ath5k_softc *sc)
 
 	ath5k_debug_printrxbuffs(sc, ah);
 
-	sc->rxlink = NULL;		/* just in case */
+	ath5k_rxbuf_init(sc);		/* clear rx buffers */
 }
 
 static unsigned int
-- 
1.6.2.5

-- 
Bob Copeland %% www.bobcopeland.com


^ permalink raw reply related

* [PATCH] cfg80211: add missing #include <linux/kmemleak.h>
From: Holger Schurig @ 2009-09-07 14:34 UTC (permalink / raw)
  To: linux-wireless; +Cc: John W Linville

Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>

---

Fixes this error:

  CC [M]  net/wireless/scan.o
net/wireless/scan.c: In function 'cfg80211_inform_bss':
net/wireless/scan.c:499: error: implicit declaration of function 'kmemleak_ignore'

Index: linux-wl/net/wireless/scan.c
===================================================================
--- linux-wl.orig/net/wireless/scan.c   2009-09-07 15:25:01.000000000 +0200
+++ linux-wl/net/wireless/scan.c        2009-09-07 15:25:09.000000000 +0200
@@ -9,6 +9,7 @@
 #include <linux/wireless.h>
 #include <linux/nl80211.h>
 #include <linux/etherdevice.h>
+#include <linux/kmemleak.h>
 #include <net/arp.h>
 #include <net/cfg80211.h>
 #include <net/iw_handler.h>



^ permalink raw reply

* iw: strange output
From: Holger Schurig @ 2009-09-07 15:11 UTC (permalink / raw)
  To: linux-wireless

I'm using

* wpasupplicant: hostap_0_6_7-490-g52eb293
* iw: v0.9.17-1-gdbaabba
* linux-wl: v2.6.31-rc8-34797-g4910edb
* some ath5k.ko supported card


For wpa_supplicant, I'm currently using the wext driver.

When I associate while "iw event" is running, I see the following
strange output:

eth1 (phy #0): scan finished: 2412, "g\xc6isQ\xffJ\xec)\xcd\xba\xab\xf2\xfb\xe3F|\xc2T\xf8\x1b\xe8\xe7\x8dvZ.c3\x9f\xc9\x9a"

Is that garbage at the end intentional?




P.S.: when I'm using nl80211 driver for wpa_supplicant, I seem
to be associated, but no ping goes throught.

-- 
http://www.holgerschurig.de

^ permalink raw reply

* Re: iw: strange output
From: Johannes Berg @ 2009-09-07 16:30 UTC (permalink / raw)
  To: Holger Schurig; +Cc: linux-wireless
In-Reply-To: <200909071711.18632.hs4233@mail.mn-solutions.de>

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

On Mon, 2009-09-07 at 17:11 +0200, Holger Schurig wrote:

> For wpa_supplicant, I'm currently using the wext driver.

> eth1 (phy #0): scan finished: 2412, "g\xc6isQ\xffJ\xec)\xcd\xba\xab
> \xf2\xfb\xe3F|\xc2T\xf8\x1b\xe8\xe7\x8dvZ.c3\x9f\xc9\x9a"

the wext driver sets a random SSID to "disconnect".

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH] cfg80211: add missing #include <linux/kmemleak.h>
From: Johannes Berg @ 2009-09-07 16:31 UTC (permalink / raw)
  To: Holger Schurig; +Cc: linux-wireless, John W Linville
In-Reply-To: <200909071634.33669.hs4233@mail.mn-solutions.de>

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

On Mon, 2009-09-07 at 16:34 +0200, Holger Schurig wrote:
> Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>

> +#include <linux/kmemleak.h>

As we've been saying, the change that added the kmemleak annotation
needs to be reverted instead.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: iw: strange output
From: Gábor Stefanik @ 2009-09-07 18:08 UTC (permalink / raw)
  To: Holger Schurig; +Cc: linux-wireless
In-Reply-To: <200909071711.18632.hs4233@mail.mn-solutions.de>

On Mon, Sep 7, 2009 at 5:11 PM, Holger
Schurig<hs4233@mail.mn-solutions.de> wrote:
> I'm using
>
> * wpasupplicant: hostap_0_6_7-490-g52eb293
> * iw: v0.9.17-1-gdbaabba
> * linux-wl: v2.6.31-rc8-34797-g4910edb
> * some ath5k.ko supported card
>
>
> For wpa_supplicant, I'm currently using the wext driver.
>
> When I associate while "iw event" is running, I see the following
> strange output:
>
> eth1 (phy #0): scan finished: 2412, "g\xc6isQ\xffJ\xec)\xcd\xba\xab\xf2\xfb\xe3F|\xc2T\xf8\x1b\xe8\xe7\x8dvZ.c3\x9f\xc9\x9a"
>
> Is that garbage at the end intentional?
>
>
>
>
> P.S.: when I'm using nl80211 driver for wpa_supplicant, I seem
> to be associated, but no ping goes throught.

I can also confirm that. It appears to be a regression from the "big
state machine monster is no more" change.

>
> --
> http://www.holgerschurig.de
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

^ permalink raw reply

* [PATCH V2] MAINTAINERS: Add Atheros Linux wireless drivers home page
From: Joe Perches @ 2009-09-07 18:34 UTC (permalink / raw)
  To: Luis R. Rodriguez
  Cc: linux-kernel, devel, Len Widra, linux-wireless, Nick Kossifidis,
	Bob Copeland, Greg KH, Stephen Chen, Andrew Morton,
	Senthil Balasubramanian, Jiri Slaby, Jouni Malinen,
	Sujith Manoharan, Vasanthakumar Thiagarajan,
	Senthil Balasubramanian
In-Reply-To: <43e72e890909061226w743e84e6p17fe0d097316678e@mail.gmail.com>

On Sun, 2009-09-06 at 12:26 -0700, Luis R. Rodriguez wrote:
> On Sun, Sep 6, 2009 at 10:59 AM, Joe Perches<joe@perches.com> wrote:
> > On Thu, 2009-09-03 at 15:54 -0700, Luis R. Rodriguez wrote:
> >> I'm pleased to announce the new home page to Atheros Linux wireless drivers:
> >> http://wireless.kernel.org/en/users/Drivers/Atheros
> > Perhaps add this to MAINTAINERS?
> Fine by me, except ath5k and ath9k also have their own respective page
> so those can also be added.

(cc's trimmed and maintainers added)

Perhaps this instead:

Signed-off-by: Joe Perches <joe@perches.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 8dca9d8..b0ef9c7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -876,6 +876,7 @@ M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
 M:	Bob Copeland <me@bobcopeland.com>
 L:	linux-wireless@vger.kernel.org
 L:	ath5k-devel@lists.ath5k.org
+W:	http://wireless.kernel.org/en/users/Drivers/ath5k
 S:	Maintained
 F:	drivers/net/wireless/ath/ath5k/
 
@@ -887,6 +888,7 @@ M:	Vasanthakumar Thiagarajan <vasanth@atheros.com>
 M:	Senthil Balasubramanian <senthilkumar@atheros.com>
 L:	linux-wireless@vger.kernel.org
 L:	ath9k-devel@lists.ath9k.org
+W:	http://wireless.kernel.org/en/users/Drivers/ath9k
 S:	Supported
 F:	drivers/net/wireless/ath/ath9k/
 




^ permalink raw reply related

* [PATCH RFC 0/3] summary: ssb: add support for ssb over sdio
From: Albert Herranz @ 2009-09-07 18:46 UTC (permalink / raw)
  To: bcm43xx-dev; +Cc: linux-wireless

Hi,

The following patchset against wireless-testing enable support for the Sonics Silicon Backplane over Secure Digital IO as found in the SDIO-based b43 wireless network card present in the Nintendo Wii video game console. (This same infrastructure _may_ be used for other SDIO-based b43 cards aswell).

[PATCH RFC 1/3] sdio: recognize io card without powercycle
[PATCH RFC 2/3] sdio: pass unknown cis tuples to sdio drivers
[PATCH RFC 3/3] ssb: add support for ssb over sdio

Cheers,
Albert



      

^ permalink raw reply

* [PATCH RFC 1/3] sdio: recognize io card without powercycle
From: Albert Herranz @ 2009-09-07 18:46 UTC (permalink / raw)
  To: bcm43xx-dev; +Cc: linux-mmc, linux-wireless

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




      

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0116-sdio-recognize-io-card-without-powercycle.patch --]
[-- Type: text/x-patch; name="0116-sdio-recognize-io-card-without-powercycle.patch", Size: 3949 bytes --]

From 5c97462ae9188524faa0c57fa8b5bf8e9e0c125c Mon Sep 17 00:00:00 2001
From: Albert Herranz <albert_herranz@yahoo.es>
Date: Tue, 18 Aug 2009 21:06:32 +0200
Subject: [PATCH] sdio: recognize io card without powercycle

SDIO Simplified Specification (at least V2.00) states that it is strongly
recommended that the host executes either a power reset or issues a CMD52
(I/O Reset) to re-initialize an I/O card.
Additionally, the CMD52 must be issued first because it cannot be issued
after a CMD0.

With this patch the Nintendo Wii SDIO-based WLAN card is detected after a
system reset, without requiring a complete system powercycle.

Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
 drivers/mmc/core/core.c     |    1 +
 drivers/mmc/core/sdio_ops.c |   36 ++++++++++++++++++++++++++++++------
 drivers/mmc/core/sdio_ops.h |    1 +
 3 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d84c880..c768f70 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -890,6 +890,7 @@ void mmc_rescan(struct work_struct *work)
 	mmc_claim_host(host);
 
 	mmc_power_up(host);
+	sdio_go_idle(host);
 	mmc_go_idle(host);
 
 	mmc_send_if_cond(host, host->ocr_avail);
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index 4eb7825..14d3204 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -67,13 +67,13 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 	return err;
 }
 
-int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
-	unsigned addr, u8 in, u8* out)
+static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
+	unsigned addr, u8 in, u8 *out)
 {
 	struct mmc_command cmd;
 	int err;
 
-	BUG_ON(!card);
+	BUG_ON(!host);
 	BUG_ON(fn > 7);
 
 	/* sanity check */
@@ -90,11 +90,11 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
 	cmd.arg |= in;
 	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
 
-	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	err = mmc_wait_for_cmd(host, &cmd, 0);
 	if (err)
 		return err;
 
-	if (mmc_host_is_spi(card->host)) {
+	if (mmc_host_is_spi(host)) {
 		/* host driver already reported errors */
 	} else {
 		if (cmd.resp[0] & R5_ERROR)
@@ -106,7 +106,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
 	}
 
 	if (out) {
-		if (mmc_host_is_spi(card->host))
+		if (mmc_host_is_spi(host))
 			*out = (cmd.resp[0] >> 8) & 0xFF;
 		else
 			*out = cmd.resp[0] & 0xFF;
@@ -115,6 +115,13 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
 	return 0;
 }
 
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+	unsigned addr, u8 in, u8 *out)
+{
+	BUG_ON(!card);
+	return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
+}
+
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
 {
@@ -182,3 +189,20 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 	return 0;
 }
 
+int sdio_go_idle(struct mmc_host *host)
+{
+	int ret;
+	u8 abort;
+
+	/* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */
+
+	ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
+	if (ret)
+		abort = 0x08;
+	else
+		abort |= 0x08;
+
+	ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
+	return ret;
+}
+
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
index e2e74b0..9b546c7 100644
--- a/drivers/mmc/core/sdio_ops.h
+++ b/drivers/mmc/core/sdio_ops.h
@@ -17,6 +17,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
 	unsigned addr, u8 in, u8* out);
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
+int sdio_go_idle(struct mmc_host *host);
 
 #endif
 
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH RFC 2/3] sdio: pass unknown cis tuples to sdio drivers
From: Albert Herranz @ 2009-09-07 18:47 UTC (permalink / raw)
  To: bcm43xx-dev; +Cc: linux-mmc, linux-wireless

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




      

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0117-sdio-pass-unknown-cis-tuples-to-sdio-drivers.patch --]
[-- Type: text/x-patch; name="0117-sdio-pass-unknown-cis-tuples-to-sdio-drivers.patch", Size: 3405 bytes --]

From bb888461dceb85e43b9c1fc9559f012dfeb19688 Mon Sep 17 00:00:00 2001
From: Albert Herranz <albert_herranz@yahoo.es>
Date: Tue, 18 Aug 2009 21:24:11 +0200
Subject: [PATCH] sdio: pass unknown cis tuples to sdio drivers

Some manufactures provide vendor information in non-vendor specific CIS
tuples. For example, Broadcom uses an Extended Function tuple to provide
the MAC address on some of their network cards, as in the case of the
Nintendo Wii WLAN daughter card.

This patch allows passing correct tuples unknown to the SDIO core to
a matching SDIO driver instead of rejecting them and failing.

Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
 drivers/mmc/core/sdio_cis.c |   46 +++++++++++++++++++++++-------------------
 1 files changed, 25 insertions(+), 21 deletions(-)

diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index 963f293..87934ac 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -123,8 +123,9 @@ static int cistpl_funce_func(struct sdio_func *func,
 	vsn = func->card->cccr.sdio_vsn;
 	min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
 
+	/* let the SDIO driver take care of unknown tuples */
 	if (size < min_size || buf[0] != 1)
-		return -EINVAL;
+		return -EILSEQ;
 
 	/* TPLFE_MAX_BLK_SIZE */
 	func->max_blksize = buf[12] | (buf[13] << 8);
@@ -154,13 +155,7 @@ static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
 	else
 		ret = cistpl_funce_common(card, buf, size);
 
-	if (ret) {
-		printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
-		       "type %u\n", mmc_hostname(card->host), size, buf[0]);
-		return ret;
-	}
-
-	return 0;
+	return ret;
 }
 
 typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
@@ -253,21 +248,12 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
 		for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
 			if (cis_tpl_list[i].code == tpl_code)
 				break;
-		if (i >= ARRAY_SIZE(cis_tpl_list)) {
-			/* this tuple is unknown to the core */
-			this->next = NULL;
-			this->code = tpl_code;
-			this->size = tpl_link;
-			*prev = this;
-			prev = &this->next;
-			printk(KERN_DEBUG
-			       "%s: queuing CIS tuple 0x%02x length %u\n",
-			       mmc_hostname(card->host), tpl_code, tpl_link);
-		} else {
+		if (i < ARRAY_SIZE(cis_tpl_list)) {
 			const struct cis_tpl *tpl = cis_tpl_list + i;
 			if (tpl_link < tpl->min_size) {
 				printk(KERN_ERR
-				       "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
+				       "%s: bad CIS tuple 0x%02x"
+				       " (length = %u, expected >= %u)\n",
 				       mmc_hostname(card->host),
 				       tpl_code, tpl_link, tpl->min_size);
 				ret = -EINVAL;
@@ -275,7 +261,25 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
 				ret = tpl->parse(card, func,
 						 this->data, tpl_link);
 			}
-			kfree(this);
+			/* already successfully parsed, not needed anymore */
+			if (!ret)
+				kfree(this);
+		} else {
+			/* unknown tuple */
+			ret = -EILSEQ;
+		}
+
+		if (ret == -EILSEQ) {
+			/* this tuple is unknown to the core */
+			this->next = NULL;
+			this->code = tpl_code;
+			this->size = tpl_link;
+			*prev = this;
+			prev = &this->next;
+			pr_debug("%s: queuing CIS tuple 0x%02x length %u\n",
+				 mmc_hostname(card->host), tpl_code, tpl_link);
+			/* keep on analyzing tuples */
+			ret = 0;
 		}
 
 		ptr += tpl_link;
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH RFC 3/3] ssb: add support for ssb over sdio
From: Albert Herranz @ 2009-09-07 18:47 UTC (permalink / raw)
  To: bcm43xx-dev; +Cc: linux-wireless

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




      

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0118-ssb-add-support-for-ssb-over-sdio.patch --]
[-- Type: text/x-patch; name="0118-ssb-add-support-for-ssb-over-sdio.patch", Size: 28041 bytes --]

From c0f5e5002b69d5cc226a0c31d791bccefc2c92e3 Mon Sep 17 00:00:00 2001
From: Albert Herranz <albert_herranz@yahoo.es>
Date: Tue, 18 Aug 2009 21:39:06 +0200
Subject: [PATCH] ssb: add support for ssb over sdio

Add support for communicating with a Sonics Silicon Backplane through a
SDIO interface, as found in the Nintendo Wii WLAN daughter card.

The Nintendo Wii WLAN card includes a custom Broadcom 4318 chip with
a SDIO host interface.

Signed-off-by: Albert Herranz <albert_herranz@yahoo.es>
---
 drivers/ssb/Kconfig       |   14 +
 drivers/ssb/Makefile      |    1 +
 drivers/ssb/main.c        |   58 +++++-
 drivers/ssb/scan.c        |   11 +
 drivers/ssb/sdio.c        |  611 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/ssb/ssb_private.h |   40 +++
 include/linux/ssb/ssb.h   |   32 +++
 7 files changed, 766 insertions(+), 1 deletions(-)
 create mode 100644 drivers/ssb/sdio.c

diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
index 540a294..2d8cc45 100644
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -66,6 +66,20 @@ config SSB_PCMCIAHOST
 
 	  If unsure, say N
 
+config SSB_SDIOHOST_POSSIBLE
+	bool
+	depends on SSB && (MMC = y || MMC = SSB)
+	default y
+
+config SSB_SDIOHOST
+	bool "Support for SSB on SDIO-bus host"
+	depends on SSB_SDIOHOST_POSSIBLE
+	help
+	  Support for a Sonics Silicon Backplane on top
+	  of a SDIO device.
+
+	  If unsure, say N
+
 config SSB_SILENT
 	bool "No SSB kernel messages"
 	depends on SSB && EMBEDDED
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile
index cfbb74f..656e58b 100644
--- a/drivers/ssb/Makefile
+++ b/drivers/ssb/Makefile
@@ -6,6 +6,7 @@ ssb-$(CONFIG_SSB_SPROM)			+= sprom.o
 # host support
 ssb-$(CONFIG_SSB_PCIHOST)		+= pci.o pcihost_wrapper.o
 ssb-$(CONFIG_SSB_PCMCIAHOST)		+= pcmcia.o
+ssb-$(CONFIG_SSB_SDIOHOST)		+= sdio.o
 
 # built-in drivers
 ssb-y					+= driver_chipcommon.o
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 65a1ed9..cfbfd5b 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -17,6 +17,7 @@
 #include <linux/ssb/ssb_driver_gige.h>
 #include <linux/dma-mapping.h>
 #include <linux/pci.h>
+#include <linux/mmc/sdio_func.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
@@ -88,6 +89,25 @@ found:
 }
 #endif /* CONFIG_SSB_PCMCIAHOST */
 
+#ifdef CONFIG_SSB_SDIOHOST
+struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func)
+{
+	struct ssb_bus *bus;
+
+	ssb_buses_lock();
+	list_for_each_entry(bus, &buses, list) {
+		if (bus->bustype == SSB_BUSTYPE_SDIO &&
+		    bus->sdio_func == func)
+			goto found;
+	}
+	bus = NULL;
+found:
+	ssb_buses_unlock();
+
+	return bus;
+}
+#endif /* CONFIG_SSB_SDIOHOST */
+
 int ssb_for_each_bus_call(unsigned long data,
 			  int (*func)(struct ssb_bus *bus, unsigned long data))
 {
@@ -469,6 +489,12 @@ static int ssb_devices_register(struct ssb_bus *bus)
 			dev->parent = &bus->host_pcmcia->dev;
 #endif
 			break;
+		case SSB_BUSTYPE_SDIO:
+#ifdef CONFIG_SSB_SDIO
+			sdev->irq = bus->sdio_func->dev.irq;
+			dev->parent = &bus->sdio_func->dev;
+#endif
+			break;
 		case SSB_BUSTYPE_SSB:
 			dev->dma_mask = &dev->coherent_dma_mask;
 			break;
@@ -724,12 +750,18 @@ static int ssb_bus_register(struct ssb_bus *bus,
 	err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
 	if (err)
 		goto out;
+
+	/* Init SDIO-host device (if any), before the scan */
+	err = ssb_sdio_init(bus);
+	if (err)
+		goto err_disable_xtal;
+
 	ssb_buses_lock();
 	bus->busnumber = next_busnumber;
 	/* Scan for devices (cores) */
 	err = ssb_bus_scan(bus, baseaddr);
 	if (err)
-		goto err_disable_xtal;
+		goto err_sdio_exit;
 
 	/* Init PCI-host device (if any) */
 	err = ssb_pci_init(bus);
@@ -776,6 +808,8 @@ err_pci_exit:
 	ssb_pci_exit(bus);
 err_unmap:
 	ssb_iounmap(bus);
+err_sdio_exit:
+	ssb_sdio_exit(bus);
 err_disable_xtal:
 	ssb_buses_unlock();
 	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
@@ -825,6 +859,28 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
 EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
 #endif /* CONFIG_SSB_PCMCIAHOST */
 
+#ifdef CONFIG_SSB_SDIOHOST
+int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
+			     unsigned int quirks)
+{
+	int err;
+
+	bus->bustype = SSB_BUSTYPE_SDIO;
+	bus->sdio_func = func;
+	bus->ops = &ssb_sdio_ops;
+	bus->quirks = quirks;
+
+	err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0);
+	if (!err) {
+		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+			   "SDIO device %s\n", sdio_func_id(func));
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(ssb_bus_sdiobus_register);
+#endif /* CONFIG_SSB_PCMCIAHOST */
+
 int ssb_bus_ssbbus_register(struct ssb_bus *bus,
 			    unsigned long baseaddr,
 			    ssb_invariants_func_t get_invariants)
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 63ee5cf..b74212d 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -175,6 +175,9 @@ static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
 		} else
 			ssb_pcmcia_switch_segment(bus, 0);
 		break;
+	case SSB_BUSTYPE_SDIO:
+		offset += current_coreidx * SSB_CORE_SIZE;
+		return ssb_sdio_scan_read32(bus, offset);
 	}
 	return readl(bus->mmio + offset);
 }
@@ -188,6 +191,8 @@ static int scan_switchcore(struct ssb_bus *bus, u8 coreidx)
 		return ssb_pci_switch_coreidx(bus, coreidx);
 	case SSB_BUSTYPE_PCMCIA:
 		return ssb_pcmcia_switch_coreidx(bus, coreidx);
+	case SSB_BUSTYPE_SDIO:
+		return ssb_sdio_scan_switch_coreidx(bus, coreidx);
 	}
 	return 0;
 }
@@ -206,6 +211,8 @@ void ssb_iounmap(struct ssb_bus *bus)
 		SSB_BUG_ON(1); /* Can't reach this code. */
 #endif
 		break;
+	case SSB_BUSTYPE_SDIO:
+		break;
 	}
 	bus->mmio = NULL;
 	bus->mapped_device = NULL;
@@ -230,6 +237,10 @@ static void __iomem *ssb_ioremap(struct ssb_bus *bus,
 		SSB_BUG_ON(1); /* Can't reach this code. */
 #endif
 		break;
+	case SSB_BUSTYPE_SDIO:
+		/* Nothing to ioremap in the SDIO case, just fake it */
+		mmio = (void __iomem *)baseaddr;
+		break;
 	}
 
 	return mmio;
diff --git a/drivers/ssb/sdio.c b/drivers/ssb/sdio.c
new file mode 100644
index 0000000..0c01c94
--- /dev/null
+++ b/drivers/ssb/sdio.c
@@ -0,0 +1,611 @@
+/*
+ * Sonics Silicon Backplane
+ * SDIO-Hostbus related functions
+ *
+ * Copyright 2009 Albert Herranz <albert_herranz@yahoo.es>
+ *
+ * Based on drivers/ssb/pcmcia.c
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ *
+ */
+
+#define pr_fmt(fmt) "ssb-sdio: " fmt
+
+#include <linux/ssb/ssb.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/etherdevice.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "ssb_private.h"
+
+/* Define the following to 1 to enable a printk on each coreswitch. */
+#define SSB_VERBOSE_SDIOCORESWITCH_DEBUG		1
+
+
+/* Hardware invariants CIS tuples */
+#define SSB_SDIO_CIS			0x80
+#define  SSB_SDIO_CIS_SROMREV		0x00
+#define  SSB_SDIO_CIS_ID		0x01
+#define  SSB_SDIO_CIS_BOARDREV		0x02
+#define  SSB_SDIO_CIS_PA		0x03
+#define   SSB_SDIO_CIS_PA_PA0B0_LO	0
+#define   SSB_SDIO_CIS_PA_PA0B0_HI	1
+#define   SSB_SDIO_CIS_PA_PA0B1_LO	2
+#define   SSB_SDIO_CIS_PA_PA0B1_HI	3
+#define   SSB_SDIO_CIS_PA_PA0B2_LO	4
+#define   SSB_SDIO_CIS_PA_PA0B2_HI	5
+#define   SSB_SDIO_CIS_PA_ITSSI		6
+#define   SSB_SDIO_CIS_PA_MAXPOW	7
+#define  SSB_SDIO_CIS_OEMNAME		0x04
+#define  SSB_SDIO_CIS_CCODE		0x05
+#define  SSB_SDIO_CIS_ANTENNA		0x06
+#define  SSB_SDIO_CIS_ANTGAIN		0x07
+#define  SSB_SDIO_CIS_BFLAGS		0x08
+#define  SSB_SDIO_CIS_LEDS		0x09
+
+#define CISTPL_FUNCE_LAN_NODE_ID        0x04	/* same as in PCMCIA */
+
+
+/*
+ * Function 1 miscellaneous registers.
+ *
+ * Definitions match src/include/sbsdio.h from the
+ * Android Open Source Project
+ * http://android.git.kernel.org/?p=platform/system/wlan/broadcom.git
+ *
+ */
+#define SBSDIO_FUNC1_SBADDRLOW	0x1000a	/* SB Address window Low (b15) */
+#define SBSDIO_FUNC1_SBADDRMID	0x1000b	/* SB Address window Mid (b23-b16) */
+#define SBSDIO_FUNC1_SBADDRHIGH	0x1000c	/* SB Address window High (b24-b31) */
+
+/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
+#define SBSDIO_SBADDRLOW_MASK	0x80	/* Valid address bits in SBADDRLOW */
+#define SBSDIO_SBADDRMID_MASK	0xff	/* Valid address bits in SBADDRMID */
+#define SBSDIO_SBADDRHIGH_MASK	0xff	/* Valid address bits in SBADDRHIGH */
+
+#define SBSDIO_SB_OFT_ADDR_MASK	0x7FFF	/* sb offset addr is <= 15 bits, 32k */
+
+/* REVISIT: this flag doesn't seem to matter */
+#define SBSDIO_SB_ACCESS_2_4B_FLAG	0x8000	/* forces 32-bit SB access */
+
+
+/*
+ * Address map within the SDIO function address space (128K).
+ *
+ *   Start   End     Description
+ *   ------- ------- ------------------------------------------
+ *   0x00000 0x0ffff selected backplane address window (64K)
+ *   0x10000 0x1ffff backplane control registers (max 64K)
+ *
+ * The current address window is configured by writing to registers
+ * SBADDRLOW, SBADDRMID and SBADDRHIGH.
+ *
+ * In order to access the contents of a 32-bit Silicon Backplane address
+ * the backplane address window must be first loaded with the highest
+ * 16 bits of the target address. Then, an access must be done to the
+ * SDIO function address space using the lower 15 bits of the address.
+ * Bit 15 of the address must be set when doing 32 bit accesses.
+ *
+ * 10987654321098765432109876543210
+ * WWWWWWWWWWWWWWWWW                 SB Address Window
+ *                 OOOOOOOOOOOOOOOO  Offset within SB Address Window
+ *                 a                 32-bit access flag
+ */
+
+
+/*
+ * SSB I/O via SDIO.
+ *
+ * NOTE: SDIO address @addr is 17 bits long (SDIO address space is 128K).
+ */
+
+static struct device *ssb_sdio_dev(struct ssb_bus *bus)
+{
+	return &bus->sdio_func->dev;
+}
+
+/* host claimed */
+static int ssb_sdio_writeb(struct ssb_bus *bus, unsigned int addr, u8 val)
+{
+	int error = 0;
+
+	sdio_writeb(bus->sdio_func, val, addr, &error);
+	if (unlikely(error))
+		dev_dbg(ssb_sdio_dev(bus), "%08X <- %02x, error %d\n",
+			addr, val, error);
+	return error;
+}
+
+#if 0
+static u8 ssb_sdio_readb(struct ssb_bus *bus, unsigned int addr)
+{
+	u8 val;
+	int error = 0;
+
+	val = sdio_readb(bus->sdio_func, addr, &error);
+	if (unlikely(error))
+		dev_dbg(ssb_sdio_dev(bus), "%08X -> %02x, error %d\n",
+			addr, val, error);
+	return val;
+}
+#endif
+
+/* host claimed */
+static int ssb_sdio_set_sbaddr_window(struct ssb_bus *bus, u32 address)
+{
+	int error;
+
+	error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRLOW,
+				(address >> 8) & SBSDIO_SBADDRLOW_MASK);
+	if (error)
+		goto out;
+	error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRMID,
+				(address >> 16) & SBSDIO_SBADDRMID_MASK);
+	if (error)
+		goto out;
+	error = ssb_sdio_writeb(bus, SBSDIO_FUNC1_SBADDRHIGH,
+				(address >> 24) & SBSDIO_SBADDRHIGH_MASK);
+	if (error)
+		goto out;
+	bus->sbaddr = address;
+out:
+	if (error)
+		dev_dbg(ssb_sdio_dev(bus), "failed to set address window"
+			" to 0x%08x, error %d\n", address, error);
+	return error;
+}
+
+/* for enumeration use only */
+u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset)
+{
+	u32 val;
+	int error;
+
+	sdio_claim_host(bus->sdio_func);
+	val = sdio_readl(bus->sdio_func, offset, &error);
+	sdio_release_host(bus->sdio_func);
+	if (unlikely(error))
+		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n",
+			bus->sbaddr >> 16, offset, val, error);
+	return val;
+}
+
+/* for enumeration use only */
+int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
+{
+	u32 sbaddr;
+	int error;
+
+	sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
+	sdio_claim_host(bus->sdio_func);
+	error = ssb_sdio_set_sbaddr_window(bus, sbaddr);
+	sdio_release_host(bus->sdio_func);
+	if (error) {
+		dev_err(ssb_sdio_dev(bus), "failed to switch to core %u,"
+			" error %d\n", coreidx, error);
+		goto out;
+	}
+out:
+	return error;
+}
+
+/* host must be already claimed */
+int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev)
+{
+	u8 coreidx = dev->core_index;
+	u32 sbaddr;
+	int error = 0;
+
+	sbaddr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
+	if (unlikely(bus->sbaddr != sbaddr)) {
+#if SSB_VERBOSE_SDIOCORESWITCH_DEBUG
+		dev_info(ssb_sdio_dev(bus),
+			   "switching to %s core, index %d\n",
+			   ssb_core_name(dev->id.coreid), coreidx);
+#endif
+		error = ssb_sdio_set_sbaddr_window(bus, sbaddr);
+		if (error) {
+			dev_dbg(ssb_sdio_dev(bus), "failed to switch to"
+				" core %u, error %d\n", coreidx, error);
+			goto out;
+		}
+		bus->mapped_device = dev;
+	}
+
+out:
+	return error;
+}
+
+static u8 ssb_sdio_read8(struct ssb_device *dev, u16 offset)
+{
+	struct ssb_bus *bus = dev->bus;
+	u8 val = 0xff;
+	int error = 0;
+
+	sdio_claim_host(bus->sdio_func);
+	if (unlikely(ssb_sdio_switch_core(bus, dev)))
+		goto out;
+	offset |= bus->sbaddr & 0xffff;
+	offset &= SBSDIO_SB_OFT_ADDR_MASK;
+	val = sdio_readb(bus->sdio_func, offset, &error);
+	if (error) {
+		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %02x, error %d\n",
+			bus->sbaddr >> 16, offset, val, error);
+	}
+out:
+	sdio_release_host(bus->sdio_func);
+	return val;
+}
+
+static u16 ssb_sdio_read16(struct ssb_device *dev, u16 offset)
+{
+	struct ssb_bus *bus = dev->bus;
+	u16 val = 0xffff;
+	int error = 0;
+
+	sdio_claim_host(bus->sdio_func);
+	if (unlikely(ssb_sdio_switch_core(bus, dev)))
+		goto out;
+	offset |= bus->sbaddr & 0xffff;
+	offset &= SBSDIO_SB_OFT_ADDR_MASK;
+	val = sdio_readw(bus->sdio_func, offset, &error);
+	if (error) {
+		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %04x, error %d\n",
+			bus->sbaddr >> 16, offset, val, error);
+	}
+out:
+	sdio_release_host(bus->sdio_func);
+	return val;
+}
+
+static u32 ssb_sdio_read32(struct ssb_device *dev, u16 offset)
+{
+	struct ssb_bus *bus = dev->bus;
+	u32 val = 0xffffffff;
+	int error = 0;
+
+	sdio_claim_host(bus->sdio_func);
+	if (unlikely(ssb_sdio_switch_core(bus, dev)))
+		goto out;
+	offset |= bus->sbaddr & 0xffff;
+	offset &= SBSDIO_SB_OFT_ADDR_MASK;
+	offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;	/* 32 bit data access */
+	val = sdio_readl(bus->sdio_func, offset, &error);
+	if (error) {
+		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X > %08x, error %d\n",
+			bus->sbaddr >> 16, offset, val, error);
+	}
+out:
+	sdio_release_host(bus->sdio_func);
+	return val;
+}
+
+#ifdef CONFIG_SSB_BLOCKIO
+static void ssb_sdio_block_read(struct ssb_device *dev, void *buffer,
+				  size_t count, u16 offset, u8 reg_width)
+{
+	size_t saved_count = count;
+	struct ssb_bus *bus = dev->bus;
+	int error = 0;
+
+	sdio_claim_host(bus->sdio_func);
+	if (unlikely(ssb_sdio_switch_core(bus, dev))) {
+		error = -EIO;
+		memset(buffer, 0xff, count);
+		goto err_out;
+	}
+	offset |= bus->sbaddr & 0xffff;
+	offset &= SBSDIO_SB_OFT_ADDR_MASK;
+
+	switch (reg_width) {
+	case sizeof(u8): {
+		/* REVISIT: untested code path */
+		error = sdio_readsb(bus->sdio_func, buffer, offset, count);
+		break;
+	}
+	case sizeof(u16): {
+		/* REVISIT: untested code path */
+		SSB_WARN_ON(count & 1);
+		error = sdio_readsb(bus->sdio_func, buffer, offset, count);
+		break;
+	}
+	case sizeof(u32): {
+		SSB_WARN_ON(count & 3);
+		offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;	/* 32 bit data access */
+		error = sdio_readsb(bus->sdio_func, buffer, offset, count);
+		break;
+	}
+	default:
+		SSB_WARN_ON(1);
+	}
+	if (!error)
+		goto out;
+
+err_out:
+	dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n",
+		bus->sbaddr >> 16, offset, reg_width, saved_count, error);
+out:
+	sdio_release_host(bus->sdio_func);
+}
+#endif /* CONFIG_SSB_BLOCKIO */
+
+static void ssb_sdio_write8(struct ssb_device *dev, u16 offset, u8 val)
+{
+	struct ssb_bus *bus = dev->bus;
+	int error = 0;
+
+	sdio_claim_host(bus->sdio_func);
+	if (unlikely(ssb_sdio_switch_core(bus, dev)))
+		goto out;
+	offset |= bus->sbaddr & 0xffff;
+	offset &= SBSDIO_SB_OFT_ADDR_MASK;
+	sdio_writeb(bus->sdio_func, val, offset, &error);
+	if (error) {
+		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %02x, error %d\n",
+			bus->sbaddr >> 16, offset, val, error);
+	}
+out:
+	sdio_release_host(bus->sdio_func);
+}
+
+static void ssb_sdio_write16(struct ssb_device *dev, u16 offset, u16 val)
+{
+	struct ssb_bus *bus = dev->bus;
+	int error = 0;
+
+	sdio_claim_host(bus->sdio_func);
+	if (unlikely(ssb_sdio_switch_core(bus, dev)))
+		goto out;
+	offset |= bus->sbaddr & 0xffff;
+	offset &= SBSDIO_SB_OFT_ADDR_MASK;
+	sdio_writew(bus->sdio_func, val, offset, &error);
+	if (error) {
+		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %04x, error %d\n",
+			bus->sbaddr >> 16, offset, val, error);
+	}
+out:
+	sdio_release_host(bus->sdio_func);
+}
+
+static void ssb_sdio_write32(struct ssb_device *dev, u16 offset, u32 val)
+{
+	struct ssb_bus *bus = dev->bus;
+	int error = 0;
+
+	sdio_claim_host(bus->sdio_func);
+	if (unlikely(ssb_sdio_switch_core(bus, dev)))
+		goto out;
+	offset |= bus->sbaddr & 0xffff;
+	offset &= SBSDIO_SB_OFT_ADDR_MASK;
+	offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;	/* 32 bit data access */
+	sdio_writel(bus->sdio_func, val, offset, &error);
+	if (error) {
+		dev_dbg(ssb_sdio_dev(bus), "%04X:%04X < %08x, error %d\n",
+			bus->sbaddr >> 16, offset, val, error);
+	}
+	if (bus->quirks & SSB_QUIRK_SDIO_READ_AFTER_WRITE32) {
+		/*
+		 * The Nintendo Wii WLAN card needs a dummy read after each
+		 * write, otherwise we get garbage on subsequent reads.
+		 */
+		sdio_readl(bus->sdio_func, 0, &error);
+	}
+out:
+	sdio_release_host(bus->sdio_func);
+}
+
+#ifdef CONFIG_SSB_BLOCKIO
+static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer,
+				   size_t count, u16 offset, u8 reg_width)
+{
+	size_t saved_count = count;
+	struct ssb_bus *bus = dev->bus;
+	int error = 0;
+
+	sdio_claim_host(bus->sdio_func);
+	if (unlikely(ssb_sdio_switch_core(bus, dev))) {
+		error = -EIO;
+		memset((void *)buffer, 0xff, count);
+		goto err_out;
+	}
+	offset |= bus->sbaddr & 0xffff;
+	offset &= SBSDIO_SB_OFT_ADDR_MASK;
+
+	switch (reg_width) {
+	case sizeof(u8):
+		/* REVISIT: untested code path */
+		error = sdio_writesb(bus->sdio_func, offset,
+				     (void *)buffer, count);
+		break;
+	case sizeof(u16):
+		/* REVISIT: untested code path */
+		SSB_WARN_ON(count & 1);
+		error = sdio_writesb(bus->sdio_func, offset,
+				     (void *)buffer, count);
+		break;
+	case sizeof(u32):
+		SSB_WARN_ON(count & 3);
+		offset |= SBSDIO_SB_ACCESS_2_4B_FLAG;	/* 32 bit data access */
+		error = sdio_writesb(bus->sdio_func, offset,
+				     (void *)buffer, count);
+		break;
+	default:
+		SSB_WARN_ON(1);
+	}
+	if (!error)
+		goto out;
+
+err_out:
+	dev_dbg(ssb_sdio_dev(bus), "%04X:%04X (width=%u, len=%u), error %d\n",
+		bus->sbaddr >> 16, offset, reg_width, saved_count, error);
+out:
+	sdio_release_host(bus->sdio_func);
+}
+
+#endif /* CONFIG_SSB_BLOCKIO */
+
+/* Not "static", as it's used in main.c */
+const struct ssb_bus_ops ssb_sdio_ops = {
+	.read8		= ssb_sdio_read8,
+	.read16		= ssb_sdio_read16,
+	.read32		= ssb_sdio_read32,
+	.write8		= ssb_sdio_write8,
+	.write16	= ssb_sdio_write16,
+	.write32	= ssb_sdio_write32,
+#ifdef CONFIG_SSB_BLOCKIO
+	.block_read	= ssb_sdio_block_read,
+	.block_write	= ssb_sdio_block_write,
+#endif
+};
+
+#define GOTO_ERROR_ON(condition, description) do {	\
+	if (unlikely(condition)) {			\
+		error_description = description;	\
+		goto error;				\
+	}						\
+  } while (0)
+
+int ssb_sdio_get_invariants(struct ssb_bus *bus,
+			    struct ssb_init_invariants *iv)
+{
+	struct ssb_sprom *sprom = &iv->sprom;
+	struct ssb_boardinfo *bi = &iv->boardinfo;
+	const char *error_description = "none";
+	struct sdio_func_tuple *tuple;
+	void *mac;
+
+	memset(sprom, 0xFF, sizeof(*sprom));
+	sprom->boardflags_lo = 0;
+	sprom->boardflags_hi = 0;
+
+	tuple = bus->sdio_func->tuples;
+	while (tuple) {
+		switch (tuple->code) {
+		case 0x22: /* extended function */
+			switch (tuple->data[0]) {
+			case CISTPL_FUNCE_LAN_NODE_ID:
+				GOTO_ERROR_ON((tuple->size != 7) &&
+					      (tuple->data[1] != 6),
+					      "mac tpl size");
+				/* fetch the MAC address. */
+				mac = tuple->data + 2;
+				memcpy(sprom->il0mac, mac, ETH_ALEN);
+				memcpy(sprom->et1mac, mac, ETH_ALEN);
+				break;
+			default:
+				break;
+			}
+			break;
+		case 0x80: /* vendor specific tuple */
+			switch (tuple->data[0]) {
+			case SSB_SDIO_CIS_SROMREV:
+				GOTO_ERROR_ON(tuple->size != 2,
+					      "sromrev tpl size");
+				sprom->revision = tuple->data[1];
+				break;
+			case SSB_SDIO_CIS_ID:
+				GOTO_ERROR_ON((tuple->size != 5) &&
+					      (tuple->size != 7),
+					      "id tpl size");
+				bi->vendor = tuple->data[1] |
+					     (tuple->data[2]<<8);
+				break;
+			case SSB_SDIO_CIS_BOARDREV:
+				GOTO_ERROR_ON(tuple->size != 2,
+					      "boardrev tpl size");
+				sprom->board_rev = tuple->data[1];
+				break;
+			case SSB_SDIO_CIS_PA:
+				GOTO_ERROR_ON((tuple->size != 9) &&
+					      (tuple->size != 10),
+					      "pa tpl size");
+				sprom->pa0b0 = tuple->data[1] |
+					 ((u16)tuple->data[2] << 8);
+				sprom->pa0b1 = tuple->data[3] |
+					 ((u16)tuple->data[4] << 8);
+				sprom->pa0b2 = tuple->data[5] |
+					 ((u16)tuple->data[6] << 8);
+				sprom->itssi_a = tuple->data[7];
+				sprom->itssi_bg = tuple->data[7];
+				sprom->maxpwr_a = tuple->data[8];
+				sprom->maxpwr_bg = tuple->data[8];
+				break;
+			case SSB_SDIO_CIS_OEMNAME:
+				/* Not present */
+				break;
+			case SSB_SDIO_CIS_CCODE:
+				GOTO_ERROR_ON(tuple->size != 2,
+					      "ccode tpl size");
+				sprom->country_code = tuple->data[1];
+				break;
+			case SSB_SDIO_CIS_ANTENNA:
+				GOTO_ERROR_ON(tuple->size != 2,
+					      "ant tpl size");
+				sprom->ant_available_a = tuple->data[1];
+				sprom->ant_available_bg = tuple->data[1];
+				break;
+			case SSB_SDIO_CIS_ANTGAIN:
+				GOTO_ERROR_ON(tuple->size != 2,
+					      "antg tpl size");
+				sprom->antenna_gain.ghz24.a0 = tuple->data[1];
+				sprom->antenna_gain.ghz24.a1 = tuple->data[1];
+				sprom->antenna_gain.ghz24.a2 = tuple->data[1];
+				sprom->antenna_gain.ghz24.a3 = tuple->data[1];
+				sprom->antenna_gain.ghz5.a0 = tuple->data[1];
+				sprom->antenna_gain.ghz5.a1 = tuple->data[1];
+				sprom->antenna_gain.ghz5.a2 = tuple->data[1];
+				sprom->antenna_gain.ghz5.a3 = tuple->data[1];
+				break;
+			case SSB_SDIO_CIS_BFLAGS:
+				GOTO_ERROR_ON((tuple->size != 3) &&
+					      (tuple->size != 5),
+					      "bfl tpl size");
+				sprom->boardflags_lo = tuple->data[1] |
+						 ((u16)tuple->data[2] << 8);
+				break;
+			case SSB_SDIO_CIS_LEDS:
+				GOTO_ERROR_ON(tuple->size != 5,
+					      "leds tpl size");
+				sprom->gpio0 = tuple->data[1];
+				sprom->gpio1 = tuple->data[2];
+				sprom->gpio2 = tuple->data[3];
+				sprom->gpio3 = tuple->data[4];
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+		tuple = tuple->next;
+	}
+
+	return 0;
+error:
+	dev_err(ssb_sdio_dev(bus), "failed to fetch device invariants: %s\n",
+		error_description);
+	return -ENODEV;
+}
+
+void ssb_sdio_exit(struct ssb_bus *bus)
+{
+	if (bus->bustype != SSB_BUSTYPE_SDIO)
+		return;
+}
+
+int ssb_sdio_init(struct ssb_bus *bus)
+{
+	if (bus->bustype != SSB_BUSTYPE_SDIO)
+		goto out;
+
+	bus->sbaddr = ~0;
+	bus->sprom_size = 0;
+
+out:
+	return 0;
+}
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index 57fa482..2543356 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -114,6 +114,46 @@ static inline int ssb_pcmcia_init(struct ssb_bus *bus)
 }
 #endif /* CONFIG_SSB_PCMCIAHOST */
 
+/* sdio.c */
+#ifdef CONFIG_SSB_SDIOHOST
+extern int ssb_sdio_get_invariants(struct ssb_bus *bus,
+				     struct ssb_init_invariants *iv);
+
+extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset);
+extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev);
+extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx);
+extern int ssb_sdio_hardware_setup(struct ssb_bus *bus);
+extern void ssb_sdio_exit(struct ssb_bus *bus);
+extern int ssb_sdio_init(struct ssb_bus *bus);
+
+extern const struct ssb_bus_ops ssb_sdio_ops;
+#else /* CONFIG_SSB_SDIOHOST */
+static inline u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset)
+{
+	return 0;
+}
+static inline int ssb_sdio_switch_core(struct ssb_bus *bus,
+					 struct ssb_device *dev)
+{
+	return 0;
+}
+static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
+{
+	return 0;
+}
+static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus)
+{
+	return 0;
+}
+static inline void ssb_sdio_exit(struct ssb_bus *bus)
+{
+}
+static inline int ssb_sdio_init(struct ssb_bus *bus)
+{
+	return 0;
+}
+#endif /* CONFIG_SSB_SDIOHOST */
+
 
 /* scan.c */
 extern const char *ssb_core_name(u16 coreid);
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 17ffc1f..771da21 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -238,6 +238,7 @@ enum ssb_bustype {
 	SSB_BUSTYPE_SSB,	/* This SSB bus is the system bus */
 	SSB_BUSTYPE_PCI,	/* SSB is connected to PCI bus */
 	SSB_BUSTYPE_PCMCIA,	/* SSB is connected to PCMCIA bus */
+	SSB_BUSTYPE_SDIO,	/* SSB is connected to SDIO bus */
 };
 
 /* board_vendor */
@@ -283,6 +284,17 @@ struct ssb_bus {
 	/* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */
 	struct pcmcia_device *host_pcmcia;
 
+	unsigned int quirks;
+
+/* card requires performing a read after writing a 32-bit value */
+#define SSB_QUIRK_SDIO_READ_AFTER_WRITE32	(1<<0)
+
+	/* Pointer to the SDIO device (only if bustype == SSB_BUSTYPE_SDIO). */
+	struct sdio_func *sdio_func;
+
+	/* Current SSB base address window for SDIO. */
+	u32	sbaddr;
+
 #ifdef CONFIG_SSB_SPROM
 	/* Mutex to protect the SPROM writing. */
 	struct mutex sprom_mutex;
@@ -366,6 +378,12 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
 				      struct pcmcia_device *pcmcia_dev,
 				      unsigned long baseaddr);
 #endif /* CONFIG_SSB_PCMCIAHOST */
+#ifdef CONFIG_SSB_SDIOHOST
+extern int ssb_bus_sdiobus_register(struct ssb_bus *bus,
+				    struct sdio_func *sdio_func,
+				    unsigned int quirks);
+#endif /* CONFIG_SSB_SDIOHOST */
+
 
 extern void ssb_bus_unregister(struct ssb_bus *bus);
 
@@ -465,6 +483,8 @@ static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr)
 		return pci_dma_mapping_error(dev->bus->host_pci, addr);
 #endif
 		break;
+	case SSB_BUSTYPE_SDIO:
+		/* FALL THROUGH */
 	case SSB_BUSTYPE_SSB:
 		return dma_mapping_error(dev->dev, addr);
 	default:
@@ -483,6 +503,8 @@ static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p,
 		return pci_map_single(dev->bus->host_pci, p, size, dir);
 #endif
 		break;
+	case SSB_BUSTYPE_SDIO:
+		/* FALL THROUGH */
 	case SSB_BUSTYPE_SSB:
 		return dma_map_single(dev->dev, p, size, dir);
 	default:
@@ -502,6 +524,8 @@ static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_a
 		return;
 #endif
 		break;
+	case SSB_BUSTYPE_SDIO:
+		/* FALL THROUGH */
 	case SSB_BUSTYPE_SSB:
 		dma_unmap_single(dev->dev, dma_addr, size, dir);
 		return;
@@ -524,6 +548,8 @@ static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev,
 		return;
 #endif
 		break;
+	case SSB_BUSTYPE_SDIO:
+		/* FALL THROUGH */
 	case SSB_BUSTYPE_SSB:
 		dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir);
 		return;
@@ -546,6 +572,8 @@ static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev,
 		return;
 #endif
 		break;
+	case SSB_BUSTYPE_SDIO:
+		/* FALL THROUGH */
 	case SSB_BUSTYPE_SSB:
 		dma_sync_single_for_device(dev->dev, dma_addr, size, dir);
 		return;
@@ -570,6 +598,8 @@ static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev,
 		return;
 #endif
 		break;
+	case SSB_BUSTYPE_SDIO:
+		/* FALL THROUGH */
 	case SSB_BUSTYPE_SSB:
 		dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset,
 					      size, dir);
@@ -595,6 +625,8 @@ static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev,
 		return;
 #endif
 		break;
+	case SSB_BUSTYPE_SDIO:
+		/* FALL THROUGH */
 	case SSB_BUSTYPE_SSB:
 		dma_sync_single_range_for_device(dev->dev, dma_addr, offset,
 						 size, dir);
-- 
1.6.0.4


^ permalink raw reply related

* Re: [PATCH RFC 1/3] sdio: recognize io card without powercycle
From: Michael Buesch @ 2009-09-07 18:55 UTC (permalink / raw)
  To: Albert Herranz; +Cc: bcm43xx-dev, linux-mmc, linux-wireless
In-Reply-To: <369914.76148.qm@web28315.mail.ukl.yahoo.com>

On Monday 07 September 2009 20:46:58 Albert Herranz wrote:
> 
>       

Please submit this to the SDIO maintainer.

-- 
Greetings, Michael.

^ permalink raw reply

* Re: [PATCH RFC 2/3] sdio: pass unknown cis tuples to sdio drivers
From: Michael Buesch @ 2009-09-07 18:55 UTC (permalink / raw)
  To: Albert Herranz; +Cc: bcm43xx-dev, linux-mmc, linux-wireless
In-Reply-To: <80555.93921.qm@web28308.mail.ukl.yahoo.com>

On Monday 07 September 2009 20:47:12 Albert Herranz wrote:
> 
>       

Please also submit to the SDIO maintainer.

-- 
Greetings, Michael.

^ permalink raw reply

* Re: [PATCH RFC 3/3] ssb: add support for ssb over sdio
From: Michael Buesch @ 2009-09-07 18:57 UTC (permalink / raw)
  To: Albert Herranz; +Cc: bcm43xx-dev, linux-wireless
In-Reply-To: <143541.29987.qm@web28309.mail.ukl.yahoo.com>

On Monday 07 September 2009 20:47:27 Albert Herranz wrote:
> 
>       

(next time please inline the patch)

Thanks a lot for the patch. I'll do more cleanups on it and submit it to john later.

-- 
Greetings, Michael.

^ permalink raw reply

* Re: [PATCH RFC 1/3] sdio: recognize io card without powercycle
From: Michael Buesch @ 2009-09-07 19:05 UTC (permalink / raw)
  To: Chris Ball; +Cc: Albert Herranz, bcm43xx-dev, linux-mmc, linux-wireless
In-Reply-To: <m3hbvey40u.fsf@pullcord.laptop.org>

On Monday 07 September 2009 20:59:45 Chris Ball wrote:
> Hi Michael,
> 
>    > Please submit this to the SDIO maintainer.
> 
> MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
> S:  Orphan
> L:  linux-mmc@vger.kernel.org
> F:  drivers/mmc/
> F:  include/linux/mmc/
> 
> So, these patches are in the right place.

So who is going to pick it up? Just sending them to a random list is not
going to magically merge them into the kernel.

-- 
Greetings, Michael.

^ permalink raw reply

* Re: [PATCH RFC 1/3] sdio: recognize io card without powercycle
From: Ehud Gavron @ 2009-09-07 19:10 UTC (permalink / raw)
  To: Michael Buesch
  Cc: Chris Ball, linux-wireless, Albert Herranz, linux-mmc,
	bcm43xx-dev
In-Reply-To: <200909072105.31439.mb@bu3sch.de>



Michael Buesch wrote:
> On Monday 07 September 2009 20:59:45 Chris Ball wrote:
>   
>> Hi Michael,
>>
>>    > Please submit this to the SDIO maintainer.
>>
>> MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
>> S:  Orphan
>> L:  linux-mmc@vger.kernel.org
>> F:  drivers/mmc/
>> F:  include/linux/mmc/
>>
>> So, these patches are in the right place.
>>     
>
> So who is going to pick it up? Just sending them to a random list is not
> going to magically merge them into the kernel.
>
>   
This wouldn't happen if you were more human.

Did you see Stefanik crying at the bottom the stairway last night?

E

^ permalink raw reply

* Re: [PATCH RFC 1/3] sdio: recognize io card without powercycle
From: Chris Ball @ 2009-09-07 18:59 UTC (permalink / raw)
  To: Michael Buesch; +Cc: Albert Herranz, bcm43xx-dev, linux-mmc, linux-wireless
In-Reply-To: <200909072055.24589.mb@bu3sch.de>

Hi Michael,

   > Please submit this to the SDIO maintainer.

MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
S:  Orphan
L:  linux-mmc@vger.kernel.org
F:  drivers/mmc/
F:  include/linux/mmc/

So, these patches are in the right place.

- Chris.
-- 
Chris Ball   <cjb@laptop.org>
One Laptop Per Child

^ permalink raw reply

* Re: iw: strange output
From: Johannes Berg @ 2009-09-07 20:55 UTC (permalink / raw)
  To: Gábor Stefanik; +Cc: Holger Schurig, linux-wireless
In-Reply-To: <69e28c910909071108t1956b0dfj7f96cac84d9088d6@mail.gmail.com>

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

On Mon, 2009-09-07 at 20:08 +0200, Gábor Stefanik wrote:

> > P.S.: when I'm using nl80211 driver for wpa_supplicant, I seem
> > to be associated, but no ping goes throught.
> 
> I can also confirm that. It appears to be a regression from the "big
> state machine monster is no more" change.

Works fine here in a whole bunch of cases, you're both going to have to
be more specific.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH V2] MAINTAINERS: Add Atheros Linux wireless drivers home page
From: Luis R. Rodriguez @ 2009-09-07 21:31 UTC (permalink / raw)
  To: Joe Perches
  Cc: linux-kernel, devel, Len Widra, linux-wireless, Nick Kossifidis,
	Bob Copeland, Greg KH, Stephen Chen, Andrew Morton,
	Senthil Balasubramanian, Jiri Slaby, Jouni Malinen,
	Sujith Manoharan, Vasanthakumar Thiagarajan
In-Reply-To: <1252348470.3394.30.camel@Joe-Laptop.home>

On Mon, Sep 7, 2009 at 11:34 AM, Joe Perches<joe@perches.com> wrote:
> On Sun, 2009-09-06 at 12:26 -0700, Luis R. Rodriguez wrote:
>> On Sun, Sep 6, 2009 at 10:59 AM, Joe Perches<joe@perches.com> wrote:
>> > On Thu, 2009-09-03 at 15:54 -0700, Luis R. Rodriguez wrote:
>> >> I'm pleased to announce the new home page to Atheros Linux wireless drivers:
>> >> http://wireless.kernel.org/en/users/Drivers/Atheros
>> > Perhaps add this to MAINTAINERS?
>> Fine by me, except ath5k and ath9k also have their own respective page
>> so those can also be added.
>
> (cc's trimmed and maintainers added)
>
> Perhaps this instead:
>
> Signed-off-by: Joe Perches <joe@perches.com>

Acked-by: Luis R. Rodriguez

think you have to send this to John.

  Luis

^ permalink raw reply

* Re: compat-wireless-old for ARM
From: Luis R. Rodriguez @ 2009-09-07 21:36 UTC (permalink / raw)
  To: AMAR SAHUKAR; +Cc: linux-wireless
In-Reply-To: <b55cabb00909070639s4a6f3c1cl8c3e2eccceaf81e8@mail.gmail.com>

On Mon, Sep 7, 2009 at 6:39 AM, AMAR SAHUKAR<amarsahu7@gmail.com> wrote:
> Hi,
>          I wanted to know the procedure to follow for installing
> compat-wireless-old on ARM platform. I am using a Netgear WG111V3 usb dongle
> which uses a rtl8187 chipset. I will be pleased if you can help me with
> this.

compat-wireless-old has not been updated for ages. Today is possible
to bring compat-wireless (instead of compat-wireless-old) down to
older kernels we previously could not since we no longer are using the
netdevice multiqueue support. I was able to bring compat-wireless down
to 2.6.25 -- at least compile-wise, there is also code present to help
bring it down to older kernels, we just need someone to test/help
finish the rest.

  Luis

^ permalink raw reply

* Re: [ath5k-devel] [PATCH/RFC] ath5k: clear rx queue on reset
From: Luis R. Rodriguez @ 2009-09-07 22:23 UTC (permalink / raw)
  To: Bob Copeland, Matt Smith; +Cc: ath5k-devel, linux-wireless, jirislaby
In-Reply-To: <43e72e890909071522i461ca821m703f6e2eeb2d0385@mail.gmail.com>

On Mon, Sep 7, 2009 at 3:22 PM, Luis R. Rodriguez<lrodriguez@atheros.com> wrote:
> Cc'ing Matt just for his information.
>
> Note: this e-mail is on a public mailing list.
>
> On Mon, Sep 7, 2009 at 5:45 AM, Bob Copeland<me@bobcopeland.com> wrote:
>>
>> When changing channels or otherwise resetting the card, dump
>> any queued rx buffers so that we don't use the wrong channel
>> information when reporting the packets.  This should fix the
>> remaining instances of this warning:
>>
>> WARNING: at /build/buildd-linux-2.6_2.6.30-1-i386-06t6n0/linux-2.6-2.6.30/debian/build/source_i386_none/drivers/net/wireless/ath5k/base.c:1096 ath5k_hw_to_driver_rix+0x52/0x58 [ath5k]()
>> Hardware name: MacBook1,1
>> invalid hw_rix: 1b
>> Modules linked in: i915 drm i2c_algo_bit binfmt_misc uvcvideo videodev v4l1_compat btusb rfcomm l2cap bluetooth ppdev parport_pc lp parport acpi_cpufreq cpufreq_powersave cpufreq_conservative cpufreq_userspace cpufreq_stats ext4 jbd2 crc16 ext2 fuse arc4 ecb ath5k mac80211 cfg80211 firewire_sbp2 loop joydev applesmc led_class input_polldev snd_hda_codec_idt isight_firmware pcspkr i2c_i801 i2c_core rng_core appletouch evdev iTCO_wdt snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq snd_timer snd_seq_device tpm_infineon tpm tpm_bios video output battery processor ac button snd soundcore snd_page_alloc intel_agp agpgart ext3 jbd mbcache usbhid dm_mirror dm_region_hash dm_log dm_snapshot dm_mod sd_mod crc_t10dif ide_cd_mod cdrom ata_piix ata_generic libata scsi_mod firewire_ohci firewire_core crc_itu_t ehci_hcd uhci_hcd ide_pci_generic piix ide_core sky2 usbcore thermal fan thermal_sys hid_apple hid
>> Pid: 5218, comm: euphoria Tainted: G        W  2.6.30-1-686 #1
>> Call Trace:
>>  [<c0126ff8>] ? warn_slowpath_common+0x5e/0x8a
>>  [<c0127056>] ? warn_slowpath_fmt+0x26/0x2a
>>  [<f86c139b>] ? ath5k_hw_to_driver_rix+0x52/0x58 [ath5k]
>>  [<f86c1899>] ? ath5k_tasklet_rx+0x2b7/0x42e [ath5k]
>>  [<c012e618>] ? __mod_timer+0xc9/0xd3
>>  [<c012abcf>] ? tasklet_action+0x63/0xa8
>>  [<c012b0d7>] ? __do_softirq+0x8e/0x135
>>  [<c012b1ac>] ? do_softirq+0x2e/0x38
>>  [<c012b28f>] ? irq_exit+0x26/0x53
>>  [<c01105c6>] ? smp_apic_timer_interrupt+0x6c/0x76
>>  [<c0103966>] ? apic_timer_interrupt+0x2a/0x30
>>  [<c01100d8>] ? lapic_suspend+0x47/0x15c
>>  [<f8ab68df>] ? drm_clflush_pages+0x3b/0x68 [drm]
>>  [<f8b0ad19>] ? i915_gem_execbuffer+0x6cf/0xbdd [i915]
>>  [<f8b08b88>] ? i915_gem_busy_ioctl+0x73/0x7a [i915]
>>  [<f8ab7667>] ? drm_ioctl+0x1ca/0x24b [drm]
>>  [<f8b0a64a>] ? i915_gem_execbuffer+0x0/0xbdd [i915]
>>  [<c011cc82>] ? update_curr+0x58/0x178
>>  [<c0138b88>] ? hrtimer_forward+0x10c/0x124
>>  [<c013d424>] ? getnstimeofday+0x4d/0xca
>>  [<c0197064>] ? vfs_ioctl+0x49/0x5f
>>  [<c01974be>] ? do_vfs_ioctl+0x444/0x47f
>>  [<c01052e6>] ? timer_interrupt+0x32/0x38
>>  [<c015a9e5>] ? handle_IRQ_event+0x4e/0x101
>>  [<c015bbdf>] ? handle_edge_irq+0xc6/0xe6
>>  [<c019753a>] ? sys_ioctl+0x41/0x58
>>  [<c0103014>] ? sysenter_do_call+0x12/0x28
>> ---[ end trace 56450801255ccacd ]---
>>
>> Signed-off-by: Bob Copeland <me@bobcopeland.com>
>> ---
>>
>> Luis, what do you think of this for the time being?
>>
>> I also tried just calling the tasklet so that we don't lose this
>> information.  This makes the locking a bit more complicated since
>> reset can run in process or softirq context and I didn't quite get
>> it working right, though it would be a worthy avenue to persue.
>
> I wonder if we can just use process context for our bottom halves. Of
> course that's another topic though, but good to know using the rx
> tasklet was tried and that using it requires some more work.
>
>> This seems to work ok though -- it artificially dropped about 50
>> packets while running iperf in parallel with continual scans for
>> 10 minutes, but I still got decent iperf numbers.
>
> I'd really rather we try to keep the frames instead of dropping them
> and since the number of frames on the wrong channel are scarce it
> seems better to drop just those frames instead of all pending frames
> for now.

That is without issuing a warning - as we are already handling it, are
aware of the issue and plan on resolving it somehow.

  Luis

^ permalink raw reply

* Re: [ath5k-devel] [PATCH/RFC] ath5k: clear rx queue on reset
From: Luis R. Rodriguez @ 2009-09-07 22:22 UTC (permalink / raw)
  To: Bob Copeland, Matt Smith; +Cc: ath5k-devel, linux-wireless, jirislaby
In-Reply-To: <20090907124548.GA5351@hash.localnet>

Cc'ing Matt just for his information.

Note: this e-mail is on a public mailing list.

On Mon, Sep 7, 2009 at 5:45 AM, Bob Copeland<me@bobcopeland.com> wrote:
>
> When changing channels or otherwise resetting the card, dump
> any queued rx buffers so that we don't use the wrong channel
> information when reporting the packets.  This should fix the
> remaining instances of this warning:
>
> WARNING: at /build/buildd-linux-2.6_2.6.30-1-i386-06t6n0/linux-2.6-2.6.30/debian/build/source_i386_none/drivers/net/wireless/ath5k/base.c:1096 ath5k_hw_to_driver_rix+0x52/0x58 [ath5k]()
> Hardware name: MacBook1,1
> invalid hw_rix: 1b
> Modules linked in: i915 drm i2c_algo_bit binfmt_misc uvcvideo videodev v4l1_compat btusb rfcomm l2cap bluetooth ppdev parport_pc lp parport acpi_cpufreq cpufreq_powersave cpufreq_conservative cpufreq_userspace cpufreq_stats ext4 jbd2 crc16 ext2 fuse arc4 ecb ath5k mac80211 cfg80211 firewire_sbp2 loop joydev applesmc led_class input_polldev snd_hda_codec_idt isight_firmware pcspkr i2c_i801 i2c_core rng_core appletouch evdev iTCO_wdt snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq snd_timer snd_seq_device tpm_infineon tpm tpm_bios video output battery processor ac button snd soundcore snd_page_alloc intel_agp agpgart ext3 jbd mbcache usbhid dm_mirror dm_region_hash dm_log dm_snapshot dm_mod sd_mod crc_t10dif ide_cd_mod cdrom ata_piix ata_generic libata scsi_mod firewire_ohci firewire_core crc_itu_t ehci_hcd uhci_hcd ide_pci_generic piix ide_core sky2 usbcore thermal fan thermal_sys hid_apple hid
> Pid: 5218, comm: euphoria Tainted: G        W  2.6.30-1-686 #1
> Call Trace:
>  [<c0126ff8>] ? warn_slowpath_common+0x5e/0x8a
>  [<c0127056>] ? warn_slowpath_fmt+0x26/0x2a
>  [<f86c139b>] ? ath5k_hw_to_driver_rix+0x52/0x58 [ath5k]
>  [<f86c1899>] ? ath5k_tasklet_rx+0x2b7/0x42e [ath5k]
>  [<c012e618>] ? __mod_timer+0xc9/0xd3
>  [<c012abcf>] ? tasklet_action+0x63/0xa8
>  [<c012b0d7>] ? __do_softirq+0x8e/0x135
>  [<c012b1ac>] ? do_softirq+0x2e/0x38
>  [<c012b28f>] ? irq_exit+0x26/0x53
>  [<c01105c6>] ? smp_apic_timer_interrupt+0x6c/0x76
>  [<c0103966>] ? apic_timer_interrupt+0x2a/0x30
>  [<c01100d8>] ? lapic_suspend+0x47/0x15c
>  [<f8ab68df>] ? drm_clflush_pages+0x3b/0x68 [drm]
>  [<f8b0ad19>] ? i915_gem_execbuffer+0x6cf/0xbdd [i915]
>  [<f8b08b88>] ? i915_gem_busy_ioctl+0x73/0x7a [i915]
>  [<f8ab7667>] ? drm_ioctl+0x1ca/0x24b [drm]
>  [<f8b0a64a>] ? i915_gem_execbuffer+0x0/0xbdd [i915]
>  [<c011cc82>] ? update_curr+0x58/0x178
>  [<c0138b88>] ? hrtimer_forward+0x10c/0x124
>  [<c013d424>] ? getnstimeofday+0x4d/0xca
>  [<c0197064>] ? vfs_ioctl+0x49/0x5f
>  [<c01974be>] ? do_vfs_ioctl+0x444/0x47f
>  [<c01052e6>] ? timer_interrupt+0x32/0x38
>  [<c015a9e5>] ? handle_IRQ_event+0x4e/0x101
>  [<c015bbdf>] ? handle_edge_irq+0xc6/0xe6
>  [<c019753a>] ? sys_ioctl+0x41/0x58
>  [<c0103014>] ? sysenter_do_call+0x12/0x28
> ---[ end trace 56450801255ccacd ]---
>
> Signed-off-by: Bob Copeland <me@bobcopeland.com>
> ---
>
> Luis, what do you think of this for the time being?
>
> I also tried just calling the tasklet so that we don't lose this
> information.  This makes the locking a bit more complicated since
> reset can run in process or softirq context and I didn't quite get
> it working right, though it would be a worthy avenue to persue.

I wonder if we can just use process context for our bottom halves. Of
course that's another topic though, but good to know using the rx
tasklet was tried and that using it requires some more work.

> This seems to work ok though -- it artificially dropped about 50
> packets while running iperf in parallel with continual scans for
> 10 minutes, but I still got decent iperf numbers.

I'd really rather we try to keep the frames instead of dropping them
and since the number of frames on the wrong channel are scarce it
seems better to drop just those frames instead of all pending frames
for now. If we get to actually process all pending frames prior to a
reset / channel change we then eventually won't loose the other stray
frames. The solution I'd like to see is to avoid those stray frames in
the first place.

I'm expecting to review avoiding dropping stale frames a little more
next week at work with Matt, will let you know how that goes.

  Luis

>  drivers/net/wireless/ath/ath5k/base.c |   53 ++++++++++++++++++++------------
>  1 files changed, 33 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
> index 9c6ab53..1f62325 100644
> --- a/drivers/net/wireless/ath/ath5k/base.c
> +++ b/drivers/net/wireless/ath/ath5k/base.c
> @@ -548,6 +548,8 @@ ath5k_pci_probe(struct pci_dev *pdev,
>
>        sc->iobase = mem; /* So we can unmap it on detach */
>        sc->common.cachelsz = csz << 2; /* convert to bytes */
> +       sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
> +
>        sc->opmode = NL80211_IFTYPE_STATION;
>        sc->bintval = 1000;
>        mutex_init(&sc->lock);
> @@ -1221,6 +1223,32 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
>        return 0;
>  }
>
> +/*
> + * Clear out any unprocessed RX buffers and reset the buffers to
> + * their initial state.
> + */
> +static int
> +ath5k_rxbuf_init(struct ath5k_softc *sc)
> +{
> +       int ret;
> +       struct ath5k_buf *bf;
> +
> +       spin_lock_bh(&sc->rxbuflock);
> +       sc->rxlink = NULL;
> +       list_for_each_entry(bf, &sc->rxbuf, list) {
> +               ret = ath5k_rxbuf_setup(sc, bf);
> +               if (ret)
> +                       goto err;
> +       }
> +       bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
> +       ath5k_hw_set_rxdp(sc->ah, bf->daddr);
> +       ret = 0;
> +err:
> +       spin_unlock_bh(&sc->rxbuflock);
> +       return ret;
> +}
> +
> +
>  static int
>  ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
>                  struct ath5k_txq *txq)
> @@ -1606,32 +1634,17 @@ static int
>  ath5k_rx_start(struct ath5k_softc *sc)
>  {
>        struct ath5k_hw *ah = sc->ah;
> -       struct ath5k_buf *bf;
>        int ret;
>
> -       sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
> -
> -       ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
> -               sc->common.cachelsz, sc->rxbufsize);
> -
> -       spin_lock_bh(&sc->rxbuflock);
> -       sc->rxlink = NULL;
> -       list_for_each_entry(bf, &sc->rxbuf, list) {
> -               ret = ath5k_rxbuf_setup(sc, bf);
> -               if (ret != 0) {
> -                       spin_unlock_bh(&sc->rxbuflock);
> -                       goto err;
> -               }
> -       }
> -       bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
> -       ath5k_hw_set_rxdp(ah, bf->daddr);
> -       spin_unlock_bh(&sc->rxbuflock);
> +       ret = ath5k_rxbuf_init(sc);
> +       if (ret)
> +               goto err;
>
>        ath5k_hw_start_rx_dma(ah);      /* enable recv descriptors */
>        ath5k_mode_setup(sc);           /* set filters, etc. */
>        ath5k_hw_start_rx_pcu(ah);      /* re-enable PCU/DMA engine */
>
> -       return 0;
> +       ret = 0;
>  err:
>        return ret;
>  }
> @@ -1650,7 +1663,7 @@ ath5k_rx_stop(struct ath5k_softc *sc)
>
>        ath5k_debug_printrxbuffs(sc, ah);
>
> -       sc->rxlink = NULL;              /* just in case */
> +       ath5k_rxbuf_init(sc);           /* clear rx buffers */
>  }
>
>  static unsigned int
> --
> 1.6.2.5
>
> --
> Bob Copeland %% www.bobcopeland.com
>
> _______________________________________________
> ath5k-devel mailing list
> ath5k-devel@lists.ath5k.org
> https://lists.ath5k.org/mailman/listinfo/ath5k-devel
>

^ permalink raw reply

* Stop using tasklets for bottom halves
From: Luis R. Rodriguez @ 2009-09-07 22:58 UTC (permalink / raw)
  To: Steven Rostedt, Ingo Molnar, Michael Buesch, John W. Linville
  Cc: linux-wireless, linux-kernel, netdev, Matt Smith, Kevin Hayes,
	Bob Copeland, Jouni Malinen, Ivan Seskar, ic.felix

A while ago I had read about an effort to consider removing tasklets
[1] or at least trying to not use them. I'm unaware of the progress in
this respect but since reading that article have always tried to
evaluate whether or not we need tasklets on wireless drivers. I have
also wondered whether work in irq context in other parts of the kernel
can be moved to process context, a curious example being timers. I'll
personally be trying to using only process context on bottom halves on
future drivers but I figured it may be a good time to ask how serious
was avoiding tasklets or using wrappers in the future to avoid irq
context is or is it advised. Do we have a general agreement this is a
good step forward to take? Has anyone made tests or changes on a
specific driver from irq context to process context and proven there
are no significant advantages of using irq context where you would
have expected it?

Wireless in particular should IMHO not require taskets for anything
time sensitive that I can think about except perhaps changing channels
quickly and to do that appropriately also process pending RX frames
prior to a switch. It remains to be seen experimentally whether or not
using a workqueue for RX processing would affect the time to switch
channels negatively but I doubt it would be significant. I hope to
test that with ath9k_htc.

What about gigabit or 10 Gigabit Ethernet drivers ? Do they face any
challenges which would yet need to be proven would not face issues
when processing bottom halves in process context?

[1] http://lwn.net/Articles/239633/

  Luis

^ permalink raw reply

* Re: [ath5k-devel] [PATCH/RFC] ath5k: clear rx queue on reset
From: Bob Copeland @ 2009-09-07 23:07 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: Matt Smith, ath5k-devel, linux-wireless, jirislaby
In-Reply-To: <43e72e890909071523q2994b123i15eb1b6991dc073a@mail.gmail.com>

On Mon, Sep 7, 2009 at 6:23 PM, Luis R. Rodriguez<lrodriguez@atheros.com> wrote:
> On Mon, Sep 7, 2009 at 3:22 PM, Luis R. Rodriguez<lrodriguez@atheros.com> wrote:
>> Cc'ing Matt just for his information.
>>
>> I'd really rather we try to keep the frames instead of dropping them
>> and since the number of frames on the wrong channel are scarce it
>> seems better to drop just those frames instead of all pending frames
>> for now.

Ok, sounds like a better plan.  In fact we could keep and report those
frames with a base rate (we do that now) but one problem with that is we
might think we got a beacon on a channel that we really didn't, and
that could confuse the regulatory system.

-- 
Bob Copeland %% www.bobcopeland.com

^ permalink raw reply

* Re: Stop using tasklets for bottom halves
From: Stephen Hemminger @ 2009-09-08  0:14 UTC (permalink / raw)
  To: Luis R. Rodriguez
  Cc: Steven Rostedt, Ingo Molnar, Michael Buesch, John W. Linville,
	linux-wireless, linux-kernel, netdev, Matt Smith, Kevin Hayes,
	Bob Copeland, Jouni Malinen, Ivan Seskar, ic.felix
In-Reply-To: <43e72e890909071558s637b45c7i10807587dc40e8c4@mail.gmail.com>

On Mon, 7 Sep 2009 15:58:50 -0700
"Luis R. Rodriguez" <mcgrof@gmail.com> wrote:

> A while ago I had read about an effort to consider removing tasklets
> [1] or at least trying to not use them. I'm unaware of the progress in
> this respect but since reading that article have always tried to
> evaluate whether or not we need tasklets on wireless drivers. I have
> also wondered whether work in irq context in other parts of the kernel
> can be moved to process context, a curious example being timers. I'll
> personally be trying to using only process context on bottom halves on
> future drivers but I figured it may be a good time to ask how serious
> was avoiding tasklets or using wrappers in the future to avoid irq
> context is or is it advised. Do we have a general agreement this is a
> good step forward to take? Has anyone made tests or changes on a
> specific driver from irq context to process context and proven there
> are no significant advantages of using irq context where you would
> have expected it?
> 
> Wireless in particular should IMHO not require taskets for anything
> time sensitive that I can think about except perhaps changing channels
> quickly and to do that appropriately also process pending RX frames
> prior to a switch. It remains to be seen experimentally whether or not
> using a workqueue for RX processing would affect the time to switch
> channels negatively but I doubt it would be significant. I hope to
> test that with ath9k_htc.
> 
> What about gigabit or 10 Gigabit Ethernet drivers ? Do they face any
> challenges which would yet need to be proven would not face issues
> when processing bottom halves in process context?
> 
> [1] http://lwn.net/Articles/239633/
> 
>   Luis
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Why not use NAPI, which is soft irq? Almost all 1G and 10G drivers
use NAPI.

Process context is too slow.

-- 

^ permalink raw reply


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