2010-02-22 06:41:19

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 00/22] wl1271: driver implementation patch blast (2/3)

These patches progressively add implementation and fix bugs in the wl1271
driver. This patch set is the second of three.

First of all apologies for the huge number of patches - quite a few have
accumulated since our last contribution. The good news in this is that these
patches have now received relatively good verification against the
wireless-testing mac80211/cfg80211 stack.

For those who wonder who I am: I am the co-maintainer of the wl1271 driver,
submitting these patches now in place of Luciano Coelho, while he is enjoying
the last moments of his well deserved vacation.

Executive summary of the changes of this patch set:
- SDIO support
- Optimizations of the TX and RX paths

Juuso Oikarinen (12):
wl1271: Improvements to the TX path
wl1271: Fix ad-hoc mode neighborhood detection
wl1271: Fix queue stopping/waking for TX path
wl1271: Remove annoying PSM entry/exit kernel traces
wl1271: Aggregate RX acknowledgements to FW
wl1271: Don't mask interrupts while handling interrupt
wl1271: Implement looped IRQ handling
wl1271: Update TX packet life time handling with higher resolution
time
wl1271: Clean up firmware block allocation calculation
wl1271: Clean up TX security sequence number handling
wl1271: Disable host TX rate control
wl1271: Remove tx-power level workaround

Kalle Valo (1):
wl1271: don't get received frames from hardware in PLT mode

Teemu Paasikivi (9):
wl1271: Moved module basics to wl1271_spi.c
wl1271: Added functions to enable/disable interrupt handling
wl1271: Implemented abstraction of IO functions.
wl1271: Inlined IO functions
wl1271: Removed wl1271_spi.h and made some functions static
wl1271: Divided driver to two separate modules
wl1271: Initial SDIO implementation
wl1271: Changed access to fw status register to use raw read
wl1271: Fixed unloading of the wl1271_sdio module

drivers/net/wireless/wl12xx/Kconfig | 24 ++
drivers/net/wireless/wl12xx/Makefile | 6 +-
drivers/net/wireless/wl12xx/wl1271.h | 33 ++-
drivers/net/wireless/wl12xx/wl1271_acx.c | 8 +-
drivers/net/wireless/wl12xx/wl1271_boot.c | 3 +-
drivers/net/wireless/wl12xx/wl1271_cmd.c | 8 +-
drivers/net/wireless/wl12xx/wl1271_cmd.h | 2 +-
drivers/net/wireless/wl12xx/wl1271_event.c | 1 -
drivers/net/wireless/wl12xx/wl1271_io.c | 87 ++-----
drivers/net/wireless/wl12xx/wl1271_io.h | 122 ++++++++--
drivers/net/wireless/wl12xx/wl1271_main.c | 336 ++++++------------------
drivers/net/wireless/wl12xx/wl1271_ps.c | 1 -
drivers/net/wireless/wl12xx/wl1271_rx.c | 11 +-
drivers/net/wireless/wl12xx/wl1271_sdio.c | 307 ++++++++++++++++++++++
drivers/net/wireless/wl12xx/wl1271_spi.c | 267 +++++++++++++++++++-
drivers/net/wireless/wl12xx/wl1271_spi.h | 96 -------
drivers/net/wireless/wl12xx/wl1271_testmode.c | 1 -
drivers/net/wireless/wl12xx/wl1271_tx.c | 94 ++++----
drivers/net/wireless/wl12xx/wl1271_tx.h | 4 +-
19 files changed, 893 insertions(+), 518 deletions(-)
create mode 100644 drivers/net/wireless/wl12xx/wl1271_sdio.c
delete mode 100644 drivers/net/wireless/wl12xx/wl1271_spi.h



2010-02-22 06:41:30

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 21/22] wl1271: Disable host TX rate control

Disable host TX rate control. The wl1271 firmware is already managing rate
control, so this eliminate unnecessary host processing.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Teemu Paasikivi <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_main.c | 3 ++-
drivers/net/wireless/wl12xx/wl1271_tx.c | 2 ++
2 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index f10ba84..0a4ff7b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -1973,7 +1973,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_BEACON_FILTER |
- IEEE80211_HW_SUPPORTS_PS;
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_HAS_RATE_CONTROL;

wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 1b11e2c..6d109df 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -350,6 +350,8 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
result->id, skb, result->ack_failures,
result->rate_class_index, result->status);

+ /* FIXME: do we need to tell the stack about the used rate? */
+
/* return the packet to the stack */
ieee80211_tx_status(wl->hw, skb);
wl->tx_frames[result->id] = NULL;
--
1.6.3.3


2010-02-22 10:44:53

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 15/22] wl1271: Aggregate RX acknowledgements to FW

On Mon, 2010-02-22 at 12:33 +0200, Juuso Oikarinen wrote:

> > > wl->rx_counter++;
> > > drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
> > > - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
> > > }
> > > +
> > > + wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
> > > }
> >
> > What if the counter overflows and you got the & to change it?
> >
> > johannes
> >
>
> The rx_counter itself is never changed with & - it's just incremented
> for each frame. It's supposed to overflow when the u32 is full - it
> will
> then still behave sane when a delta is calculated inside the firmware
> against its corresponding counter. That's a very common way to handle
> counters for this particular chipset.

Ok.

> Did I miss the point?

No ... I did. I thought the second quoted line was the same counter,
didn't see it was a different variable because it looked so similar.
That and I wasn't sure the firmware would really do the right thing when
an overflow happened since it looked like before it wouldn't have to :)

johannes


2010-02-22 06:41:26

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 03/22] wl1271: Implemented abstraction of IO functions.

From: Teemu Paasikivi <[email protected]>

Changed the driver to use if_ops structure to abstract access to the IO
layer (SPI or SDIO).

Signed-off-by: Teemu Paasikivi <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271.h | 16 +++++++++++-
drivers/net/wireless/wl12xx/wl1271_io.c | 21 ++++++++++------
drivers/net/wireless/wl12xx/wl1271_io.h | 2 +
drivers/net/wireless/wl12xx/wl1271_main.c | 6 ++--
drivers/net/wireless/wl12xx/wl1271_spi.c | 37 ++++++++++++++++++++++------
5 files changed, 62 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 97ea509..10135c9 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -334,11 +334,25 @@ struct wl1271_scan {
u8 probe_requests;
};

+struct wl1271_if_operations {
+ void (*read)(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+ void (*write)(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+ void (*reset)(struct wl1271 *wl);
+ void (*init)(struct wl1271 *wl);
+ struct device* (*dev)(struct wl1271 *wl);
+ void (*enable_irq)(struct wl1271 *wl);
+ void (*disable_irq)(struct wl1271 *wl);
+};
+
struct wl1271 {
struct ieee80211_hw *hw;
bool mac80211_registered;

- struct spi_device *spi;
+ void *if_priv;
+
+ struct wl1271_if_operations *if_ops;

void (*set_power)(bool enable);
int irq;
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.c b/drivers/net/wireless/wl12xx/wl1271_io.c
index b825cfa..d00f7ed 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.c
+++ b/drivers/net/wireless/wl12xx/wl1271_io.c
@@ -31,14 +31,19 @@
#include "wl1271_spi.h"
#include "wl1271_io.h"

+struct device *wl1271_wl_to_dev(struct wl1271 *wl)
+{
+ return wl->if_ops->dev(wl);
+}
+
void wl1271_disable_interrupts(struct wl1271 *wl)
{
- wl1271_spi_disable_interrupts(wl);
+ wl->if_ops->disable_irq(wl);
}

void wl1271_enable_interrupts(struct wl1271 *wl)
{
- wl1271_spi_enable_interrupts(wl);
+ wl->if_ops->enable_irq(wl);
}

static int wl1271_translate_addr(struct wl1271 *wl, int addr)
@@ -127,24 +132,24 @@ int wl1271_set_partition(struct wl1271 *wl,

void wl1271_io_reset(struct wl1271 *wl)
{
- wl1271_spi_reset(wl);
+ wl->if_ops->reset(wl);
}

void wl1271_io_init(struct wl1271 *wl)
{
- wl1271_spi_init(wl);
+ wl->if_ops->init(wl);
}

void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
- wl1271_spi_raw_write(wl, addr, buf, len, fixed);
+ wl->if_ops->write(wl, addr, buf, len, fixed);
}

void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
- wl1271_spi_raw_read(wl, addr, buf, len, fixed);
+ wl->if_ops->read(wl, addr, buf, len, fixed);
}

void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,
@@ -154,7 +159,7 @@ void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,

physical = wl1271_translate_addr(wl, addr);

- wl1271_spi_raw_read(wl, physical, buf, len, fixed);
+ wl1271_raw_read(wl, physical, buf, len, fixed);
}

void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,
@@ -164,7 +169,7 @@ void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,

physical = wl1271_translate_addr(wl, addr);

- wl1271_spi_raw_write(wl, physical, buf, len, fixed);
+ wl1271_raw_write(wl, physical, buf, len, fixed);
}

u32 wl1271_read32(struct wl1271 *wl, int addr)
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h
index c8b0971..f2b6325 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.h
+++ b/drivers/net/wireless/wl12xx/wl1271_io.h
@@ -33,6 +33,8 @@ void wl1271_enable_interrupts(struct wl1271 *wl);
void wl1271_io_reset(struct wl1271 *wl);
void wl1271_io_init(struct wl1271 *wl);

+struct device *wl1271_wl_to_dev(struct wl1271 *wl);
+
/* Raw target IO, address is not translated */
void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 18347c3..6b3fd00 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -480,7 +480,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
const struct firmware *fw;
int ret;

- ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
+ ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));

if (ret < 0) {
wl1271_error("could not get firmware: %d", ret);
@@ -552,7 +552,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
const struct firmware *fw;
int ret;

- ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
+ ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));

if (ret < 0) {
wl1271_error("could not get nvs file: %d", ret);
@@ -1973,7 +1973,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
if (wl1271_11a_enabled())
wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;

- SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
+ SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));

return 0;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index b422c9f..a0f4169 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -33,6 +33,15 @@
#include "wl1271_spi.h"
#include "wl1271_io.h"

+static struct spi_device *wl_to_spi(struct wl1271 *wl)
+{
+ return wl->if_priv;
+}
+
+static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl)
+{
+ return &(wl_to_spi(wl)->dev);
+}

void wl1271_spi_disable_interrupts(struct wl1271 *wl)
{
@@ -65,7 +74,7 @@ void wl1271_spi_reset(struct wl1271 *wl)
t.len = WSPI_INIT_CMD_LEN;
spi_message_add_tail(&t, &m);

- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);

wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
}
@@ -119,7 +128,7 @@ void wl1271_spi_init(struct wl1271 *wl)
t.len = WSPI_INIT_CMD_LEN;
spi_message_add_tail(&t, &m);

- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);

wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
}
@@ -151,7 +160,7 @@ static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
t[0].rx_buf = buf + (len - num_busy_bytes);
t[0].len = num_busy_bytes;
spi_message_add_tail(&t[0], &m);
- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);
return;
}
}
@@ -171,7 +180,7 @@ static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
t[0].rx_buf = busy_buf;
t[0].len = sizeof(u32);
spi_message_add_tail(&t[0], &m);
- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);

if (*busy_buf & 0x1) {
spi_message_init(&m);
@@ -179,7 +188,7 @@ static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
t[0].rx_buf = buf;
t[0].len = len;
spi_message_add_tail(&t[0], &m);
- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);
return;
}
}
@@ -225,7 +234,7 @@ void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
t[2].len = len;
spi_message_add_tail(&t[2], &m);

- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);

/* FIXME: Check busy words, removed due to SPI bug */
/* if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1))
@@ -263,7 +272,7 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
t[1].len = len;
spi_message_add_tail(&t[1], &m);

- spi_sync(wl->spi, &m);
+ spi_sync(wl_to_spi(wl), &m);

wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
@@ -306,6 +315,16 @@ static struct platform_device wl1271_device = {
},
};

+static struct wl1271_if_operations spi_ops = {
+ .read = wl1271_spi_raw_read,
+ .write = wl1271_spi_raw_write,
+ .reset = wl1271_spi_reset,
+ .init = wl1271_spi_init,
+ .dev = wl1271_spi_wl_to_dev,
+ .enable_irq = wl1271_spi_enable_interrupts,
+ .disable_irq = wl1271_spi_disable_interrupts
+};
+
static int __devinit wl1271_probe(struct spi_device *spi)
{
struct wl12xx_platform_data *pdata;
@@ -326,7 +345,9 @@ static int __devinit wl1271_probe(struct spi_device *spi)
wl = hw->priv;

dev_set_drvdata(&spi->dev, wl);
- wl->spi = spi;
+ wl->if_priv = spi;
+
+ wl->if_ops = &spi_ops;

/* This is the only SPI value that we need to set here, the rest
* comes from the board-peripherals file */
--
1.6.3.3


2010-02-22 06:41:27

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 05/22] wl1271: Removed wl1271_spi.h and made some functions static

From: Teemu Paasikivi <[email protected]>

Removed wl1271_spi.h header as there's no more need to access functions
declared there outside of wl1271_spi.c. Also made those SPI access
functions static.

Signed-off-by: Teemu Paasikivi <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_acx.c | 1 -
drivers/net/wireless/wl12xx/wl1271_boot.c | 1 -
drivers/net/wireless/wl12xx/wl1271_cmd.c | 1 -
drivers/net/wireless/wl12xx/wl1271_event.c | 1 -
drivers/net/wireless/wl12xx/wl1271_io.c | 14 +++-
drivers/net/wireless/wl12xx/wl1271_io.h | 17 ++++
drivers/net/wireless/wl12xx/wl1271_main.c | 1 -
drivers/net/wireless/wl12xx/wl1271_ps.c | 1 -
drivers/net/wireless/wl12xx/wl1271_rx.c | 1 -
drivers/net/wireless/wl12xx/wl1271_spi.c | 44 +++++++++--
drivers/net/wireless/wl12xx/wl1271_spi.h | 99 -------------------------
drivers/net/wireless/wl12xx/wl1271_testmode.c | 1 -
drivers/net/wireless/wl12xx/wl1271_tx.c | 1 -
13 files changed, 67 insertions(+), 116 deletions(-)
delete mode 100644 drivers/net/wireless/wl12xx/wl1271_spi.h

diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index 60f10dc..f41f886 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -31,7 +31,6 @@
#include "wl1271.h"
#include "wl12xx_80211.h"
#include "wl1271_reg.h"
-#include "wl1271_spi.h"
#include "wl1271_ps.h"

int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index 7d6d2e6..f88d52e 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -26,7 +26,6 @@
#include "wl1271_acx.h"
#include "wl1271_reg.h"
#include "wl1271_boot.h"
-#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_event.h"

diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index 36a64e0..6759aa1 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -29,7 +29,6 @@

#include "wl1271.h"
#include "wl1271_reg.h"
-#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_acx.h"
#include "wl12xx_80211.h"
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index 7468ef1..5533519 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -23,7 +23,6 @@

#include "wl1271.h"
#include "wl1271_reg.h"
-#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_event.h"
#include "wl1271_ps.h"
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.c b/drivers/net/wireless/wl12xx/wl1271_io.c
index c082658..c8759ac 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.c
+++ b/drivers/net/wireless/wl12xx/wl1271_io.c
@@ -28,9 +28,21 @@

#include "wl1271.h"
#include "wl12xx_80211.h"
-#include "wl1271_spi.h"
#include "wl1271_io.h"

+#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
+
void wl1271_disable_interrupts(struct wl1271 *wl)
{
wl->if_ops->disable_irq(wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h
index 8501898..95d2168 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.h
+++ b/drivers/net/wireless/wl12xx/wl1271_io.h
@@ -25,6 +25,23 @@
#ifndef __WL1271_IO_H__
#define __WL1271_IO_H__

+#include "wl1271_reg.h"
+
+#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
+
+#define HW_PARTITION_REGISTERS_ADDR 0x1FFC0
+#define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR)
+#define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4)
+#define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8)
+#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12)
+#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16)
+#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20)
+#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24)
+
+#define HW_ACCESS_REGISTER_SIZE 4
+
+#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
+
struct wl1271;

void wl1271_disable_interrupts(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 6b3fd00..54bc1e9 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -33,7 +33,6 @@
#include "wl1271.h"
#include "wl12xx_80211.h"
#include "wl1271_reg.h"
-#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_event.h"
#include "wl1271_tx.h"
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c
index e2b1ebf..5a04482 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.c
@@ -23,7 +23,6 @@

#include "wl1271_reg.h"
#include "wl1271_ps.h"
-#include "wl1271_spi.h"
#include "wl1271_io.h"

#define WL1271_WAKEUP_TIMEOUT 500
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index 6730f5b..b7a7c06 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -25,7 +25,6 @@
#include "wl1271_acx.h"
#include "wl1271_reg.h"
#include "wl1271_rx.h"
-#include "wl1271_spi.h"
#include "wl1271_io.h"

static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index f89e1b3..51171d7 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -30,9 +30,39 @@

#include "wl1271.h"
#include "wl12xx_80211.h"
-#include "wl1271_spi.h"
#include "wl1271_io.h"

+#include "wl1271_reg.h"
+
+#define WSPI_CMD_READ 0x40000000
+#define WSPI_CMD_WRITE 0x00000000
+#define WSPI_CMD_FIXED 0x20000000
+#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000
+#define WSPI_CMD_BYTE_LENGTH_OFFSET 17
+#define WSPI_CMD_BYTE_ADDR 0x0001FFFF
+
+#define WSPI_INIT_CMD_CRC_LEN 5
+
+#define WSPI_INIT_CMD_START 0x00
+#define WSPI_INIT_CMD_TX 0x40
+/* the extra bypass bit is sampled by the TNET as '1' */
+#define WSPI_INIT_CMD_BYPASS_BIT 0x80
+#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07
+#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80
+#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00
+#define WSPI_INIT_CMD_IOD 0x40
+#define WSPI_INIT_CMD_IP 0x20
+#define WSPI_INIT_CMD_CS 0x10
+#define WSPI_INIT_CMD_WS 0x08
+#define WSPI_INIT_CMD_WSPI 0x01
+#define WSPI_INIT_CMD_END 0x01
+
+#define WSPI_INIT_CMD_LEN 8
+
+#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
+ ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
+#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
+
static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
{
return wl->if_priv;
@@ -43,17 +73,17 @@ static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl)
return &(wl_to_spi(wl)->dev);
}

-void wl1271_spi_disable_interrupts(struct wl1271 *wl)
+static void wl1271_spi_disable_interrupts(struct wl1271 *wl)
{
disable_irq(wl->irq);
}

-void wl1271_spi_enable_interrupts(struct wl1271 *wl)
+static void wl1271_spi_enable_interrupts(struct wl1271 *wl)
{
enable_irq(wl->irq);
}

-void wl1271_spi_reset(struct wl1271 *wl)
+static void wl1271_spi_reset(struct wl1271 *wl)
{
u8 *cmd;
struct spi_transfer t;
@@ -79,7 +109,7 @@ void wl1271_spi_reset(struct wl1271 *wl)
wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
}

-void wl1271_spi_init(struct wl1271 *wl)
+static void wl1271_spi_init(struct wl1271 *wl)
{
u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
struct spi_transfer t;
@@ -199,7 +229,7 @@ static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
}
#endif

-void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
+static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
struct spi_transfer t[3];
@@ -244,7 +274,7 @@ void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
}

-void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
+static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
struct spi_transfer t[2];
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h
deleted file mode 100644
index 86ff161..0000000
--- a/drivers/net/wireless/wl12xx/wl1271_spi.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * This file is part of wl1271
- *
- * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Contact: Luciano Coelho <[email protected]>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __WL1271_SPI_H__
-#define __WL1271_SPI_H__
-
-#include "wl1271_reg.h"
-
-#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
-
-#define HW_PARTITION_REGISTERS_ADDR 0x1ffc0
-#define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR)
-#define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4)
-#define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8)
-#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12)
-#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16)
-#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20)
-#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24)
-
-#define HW_ACCESS_REGISTER_SIZE 4
-
-#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000
-
-#define WSPI_CMD_READ 0x40000000
-#define WSPI_CMD_WRITE 0x00000000
-#define WSPI_CMD_FIXED 0x20000000
-#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000
-#define WSPI_CMD_BYTE_LENGTH_OFFSET 17
-#define WSPI_CMD_BYTE_ADDR 0x0001FFFF
-
-#define WSPI_INIT_CMD_CRC_LEN 5
-
-#define WSPI_INIT_CMD_START 0x00
-#define WSPI_INIT_CMD_TX 0x40
-/* the extra bypass bit is sampled by the TNET as '1' */
-#define WSPI_INIT_CMD_BYPASS_BIT 0x80
-#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07
-#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80
-#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00
-#define WSPI_INIT_CMD_IOD 0x40
-#define WSPI_INIT_CMD_IP 0x20
-#define WSPI_INIT_CMD_CS 0x10
-#define WSPI_INIT_CMD_WS 0x08
-#define WSPI_INIT_CMD_WSPI 0x01
-#define WSPI_INIT_CMD_END 0x01
-
-#define WSPI_INIT_CMD_LEN 8
-
-#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
- ((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
-
-void wl1271_spi_disable_interrupts(struct wl1271 *wl);
-void wl1271_spi_enable_interrupts(struct wl1271 *wl);
-
-/* Raw target IO, address is not translated */
-void wl1271_spi_raw_write(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);
-
-/* INIT and RESET words */
-void wl1271_spi_reset(struct wl1271 *wl);
-void wl1271_spi_init(struct wl1271 *wl);
-#endif /* __WL1271_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c
index 3919102..2401e60 100644
--- a/drivers/net/wireless/wl12xx/wl1271_testmode.c
+++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c
@@ -25,7 +25,6 @@
#include <net/genetlink.h>

#include "wl1271.h"
-#include "wl1271_spi.h"
#include "wl1271_acx.h"

#define WL1271_TM_MAX_DATA_LENGTH 1024
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 811e739..2b7dd9b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -25,7 +25,6 @@
#include <linux/module.h>

#include "wl1271.h"
-#include "wl1271_spi.h"
#include "wl1271_io.h"
#include "wl1271_reg.h"
#include "wl1271_ps.h"
--
1.6.3.3


2010-02-22 06:41:21

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 17/22] wl1271: Implement looped IRQ handling

This patch implements looped IRQ handling. In essence, if a new interrupt is
asserted by the FW while the host is processing the previous one, the host
will directly proceed processing the new IRQ without leaving the handling
function.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Teemu Paasikivi <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271.h | 2 +
drivers/net/wireless/wl12xx/wl1271_main.c | 76 ++++++++++++++++++-----------
drivers/net/wireless/wl12xx/wl1271_sdio.c | 4 +-
drivers/net/wireless/wl12xx/wl1271_spi.c | 4 +-
4 files changed, 55 insertions(+), 31 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 7f03f89..457ce72 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -371,6 +371,8 @@ struct wl1271 {
#define WL1271_FLAG_IN_ELP (6)
#define WL1271_FLAG_PSM (7)
#define WL1271_FLAG_PSM_REQUESTED (8)
+#define WL1271_FLAG_IRQ_PENDING (9)
+#define WL1271_FLAG_IRQ_RUNNING (10)
unsigned long flags;

struct wl1271_partition_set part;
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index a46d323..9f74168 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -406,10 +406,14 @@ static void wl1271_fw_status(struct wl1271 *wl,
le32_to_cpu(status->fw_localtime);
}

+#define WL1271_IRQ_MAX_LOOPS 10
+
static void wl1271_irq_work(struct work_struct *work)
{
int ret;
u32 intr;
+ int loopcount = WL1271_IRQ_MAX_LOOPS;
+ unsigned long flags;
struct wl1271 *wl =
container_of(work, struct wl1271, irq_work);

@@ -417,51 +421,65 @@ static void wl1271_irq_work(struct work_struct *work)

wl1271_debug(DEBUG_IRQ, "IRQ work");

- if (wl->state == WL1271_STATE_OFF)
+ if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;

ret = wl1271_ps_elp_wakeup(wl, true);
if (ret < 0)
goto out;

- wl1271_fw_status(wl, wl->fw_status);
- intr = le32_to_cpu(wl->fw_status->intr);
- if (!intr) {
- wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
- goto out_sleep;
- }
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
+ clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ loopcount--;

- intr &= WL1271_INTR_MASK;
+ wl1271_fw_status(wl, wl->fw_status);
+ intr = le32_to_cpu(wl->fw_status->intr);
+ if (!intr) {
+ wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
+ continue;
+ }

- if (intr & WL1271_ACX_INTR_EVENT_A) {
- wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
- wl1271_event_handle(wl, 0);
- }
+ intr &= WL1271_INTR_MASK;

- if (intr & WL1271_ACX_INTR_EVENT_B) {
- wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
- wl1271_event_handle(wl, 1);
- }
+ if (intr & WL1271_ACX_INTR_DATA) {
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");

- if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
- wl1271_debug(DEBUG_IRQ,
- "WL1271_ACX_INTR_INIT_COMPLETE");
+ /* check for tx results */
+ if (wl->fw_status->tx_results_counter !=
+ (wl->tx_results_count & 0xff))
+ wl1271_tx_complete(wl);

- if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
- wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
+ wl1271_rx(wl, wl->fw_status);
+ }
+
+ if (intr & WL1271_ACX_INTR_EVENT_A) {
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
+ wl1271_event_handle(wl, 0);
+ }
+
+ if (intr & WL1271_ACX_INTR_EVENT_B) {
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
+ wl1271_event_handle(wl, 1);
+ }

- if (intr & WL1271_ACX_INTR_DATA) {
- wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
+ if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
+ wl1271_debug(DEBUG_IRQ,
+ "WL1271_ACX_INTR_INIT_COMPLETE");

- /* check for tx results */
- if (wl->fw_status->tx_results_counter !=
- (wl->tx_results_count & 0xff))
- wl1271_tx_complete(wl);
+ if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");

- wl1271_rx(wl, wl->fw_status);
+ spin_lock_irqsave(&wl->wl_lock, flags);
}

-out_sleep:
+ if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
+ else
+ clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
wl1271_ps_elp_sleep(wl);

out:
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
index 7d7c850..1f204db 100644
--- a/drivers/net/wireless/wl12xx/wl1271_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -75,7 +75,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl->elp_compl = NULL;
}

- ieee80211_queue_work(wl->hw, &wl->irq_work);
+ if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
+ set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
spin_unlock_irqrestore(&wl->wl_lock, flags);

return IRQ_HANDLED;
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 51171d7..ed285fe 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -324,7 +324,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl->elp_compl = NULL;
}

- ieee80211_queue_work(wl->hw, &wl->irq_work);
+ if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
+ set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
spin_unlock_irqrestore(&wl->wl_lock, flags);

return IRQ_HANDLED;
--
1.6.3.3


2010-02-22 06:41:32

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 14/22] wl1271: Remove annoying PSM entry/exit kernel traces

Remove the annoying and dmesg-flooding WLAN PSM entry/exit traces. Instead,
only output them if PSM traces are enabled.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_main.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 184264a..4d091eb 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -1235,13 +1235,13 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
* through the bss_info_changed() hook.
*/
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
- wl1271_info("psm enabled");
+ wl1271_debug(DEBUG_PSM, "psm enabled");
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
true);
}
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
- wl1271_info("psm disabled");
+ wl1271_debug(DEBUG_PSM, "psm disabled");

clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);

--
1.6.3.3


2010-02-22 10:36:42

by Juuso Oikarinen

[permalink] [raw]
Subject: Re: [PATCH 15/22] wl1271: Aggregate RX acknowledgements to FW

On Mon, 2010-02-22 at 09:35 +0100, ext Johannes Berg wrote:
> On Mon, 2010-02-22 at 08:38 +0200, Juuso Oikarinen wrote:
>
> > wl->rx_counter++;
> > drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
> > - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
> > }
> > +
> > + wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
> > }
>
> What if the counter overflows and you got the & to change it?
>
> johannes
>

The rx_counter itself is never changed with & - it's just incremented
for each frame. It's supposed to overflow when the u32 is full - it will
then still behave sane when a delta is calculated inside the firmware
against its corresponding counter. That's a very common way to handle
counters for this particular chipset.

Did I miss the point?

-Juuso



2010-02-22 06:41:31

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 10/22] wl1271: don't get received frames from hardware in PLT mode

From: Kalle Valo <[email protected]>

Most probably patch "wl1271: add most of the normal initialization commands
to PLT mode" enabled the RX path in firmware so that now driver received
frames and passed them to mac80211, which warned about them.

Workaround this by not retrieving frames from the hardware, just ignore them.

Signed-off-by: Kalle Valo <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_rx.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index b7a7c06..2df7852 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -159,6 +159,13 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
u8 *buf;
u8 beacon = 0;

+ /*
+ * In PLT mode we seem to get frames and mac80211 warns about them,
+ * workaround this by not retrieving them at all.
+ */
+ if (unlikely(wl->state == WL1271_STATE_PLT))
+ return;
+
skb = __dev_alloc_skb(length, GFP_KERNEL);
if (!skb) {
wl1271_error("Couldn't allocate RX frame");
--
1.6.3.3


2010-02-22 18:42:32

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 06/22] wl1271: Divided driver to two separate modules

On Mon, 2010-02-22 at 10:05 -0800, Luis R. Rodriguez wrote:
> On Sun, Feb 21, 2010 at 10:38 PM, Juuso Oikarinen
> <[email protected]> wrote:
> > From: Teemu Paasikivi <[email protected]>
> >
> > Divided wl1271 driver to wl1271 "core" and wl1271_spi modules in
> preparation
> > of integration of the SDIO implementation.
> >
> > Signed-off-by: Teemu Paasikivi <[email protected]>
> > Reviewed-by: Juuso Oikarinen <[email protected]>
> > Signed-off-by: Juuso Oikarinen <[email protected]>
>
> Which one is it, Reviewed or SOB? If both then just use SOB.

I disagree. I think we should allow for people just sending on patches
(say as part of a company hierarchy) w/o giving them the careful review
the reviewed-by tag should imply.

johannes


Attachments:
signature.asc (801.00 B)
This is a digitally signed message part

2010-02-22 06:41:32

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 19/22] wl1271: Clean up firmware block allocation calculation

This patch simplifies the required block count calculation. Though it
introduces a division operator, it greatly simplifies the formula.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Teemu Paasikivi <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_tx.c | 10 +++-------
drivers/net/wireless/wl12xx/wl1271_tx.h | 2 +-
2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index a32d301..d3ed63e 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -46,7 +46,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
{
struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
- u32 total_blocks, excluded;
+ u32 total_blocks;
int id, ret = -EBUSY;

/* allocate free identifier for the packet */
@@ -56,12 +56,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)

/* approximate the number of blocks required for this packet
in the firmware */
- /* FIXME: try to figure out what is done here and make it cleaner */
- total_blocks = (total_len + 20) >> TX_HW_BLOCK_SHIFT_DIV;
- excluded = (total_blocks << 2) + ((total_len + 20) & 0xff) + 34;
- total_blocks += (excluded > 252) ? 2 : 1;
- total_blocks += TX_HW_BLOCK_SPARE;
-
+ total_blocks = total_len + TX_HW_BLOCK_SIZE - 1;
+ total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE;
if (total_blocks <= wl->tx_blocks_available) {
desc = (struct wl1271_tx_hw_descr *)skb_push(
skb, total_len - skb->len);
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index ca92bd8..8b9f6b4 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -26,7 +26,7 @@
#define __WL1271_TX_H__

#define TX_HW_BLOCK_SPARE 2
-#define TX_HW_BLOCK_SHIFT_DIV 8
+#define TX_HW_BLOCK_SIZE 252

#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
/* The chipset reference driver states, that the "aid" value 1
--
1.6.3.3


2010-02-22 06:41:28

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 08/22] wl1271: Changed access to fw status register to use raw read

From: Teemu Paasikivi <[email protected]>

Changed access to fw status register to use raw read instead of
translated addressing. On SDIO access by translated addressing was not
working and raw access is working also on SPI.

Signed-off-by: Teemu Paasikivi <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_main.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index ea49ced..310f58c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -377,7 +377,7 @@ static void wl1271_fw_status(struct wl1271 *wl,
u32 total = 0;
int i;

- wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
+ wl1271_raw_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)",
--
1.6.3.3


2010-02-22 06:41:22

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 07/22] wl1271: Initial SDIO implementation

From: Teemu Paasikivi <[email protected]>

Added initial implementation of SDIO interfacte to the wl1271 driver.
When selected, this adds new module called "wl1271_sdio".

Signed-off-by: Teemu Paasikivi <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/Kconfig | 12 ++
drivers/net/wireless/wl12xx/Makefile | 1 +
drivers/net/wireless/wl12xx/wl1271_sdio.c | 302 +++++++++++++++++++++++++++++
3 files changed, 315 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/wireless/wl12xx/wl1271_sdio.c

diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 9c6fdcc..2f67335 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -63,3 +63,15 @@ config WL1271_SPI
If you choose to build a module, it'll be called wl1251_spi.
Say N if unsure.

+config WL1271_SDIO
+ tristate "TI wl1271 SDIO support"
+ depends on WL1271 && MMC
+ ---help---
+ This module adds support for the SDIO interface of adapters using
+ TI wl1271 chipset. Select this if your platform is using
+ the SDIO bus.
+
+ If you choose to build a module, it'll be called
+ wl1271_sdio. Say N if unsure.
+
+
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index 473a1e2..27ddd2b 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -15,3 +15,4 @@ wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \
wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o
obj-$(CONFIG_WL1271) += wl1271.o
obj-$(CONFIG_WL1271_SPI) += wl1271_spi.o
+obj-$(CONFIG_WL1271_SDIO) += wl1271_sdio.o
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
new file mode 100644
index 0000000..be5c149
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -0,0 +1,302 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/vmalloc.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/card.h>
+#include <plat/gpio.h>
+
+#include "wl1271.h"
+#include "wl12xx_80211.h"
+#include "wl1271_io.h"
+
+
+#define RX71_WL1271_IRQ_GPIO 42
+
+#ifndef SDIO_VENDOR_ID_TI
+#define SDIO_VENDOR_ID_TI 0x0097
+#endif
+
+#ifndef SDIO_DEVICE_ID_TI_WL1271
+#define SDIO_DEVICE_ID_TI_WL1271 0x4076
+#endif
+
+static const struct sdio_device_id wl1271_devices[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
+ {}
+};
+MODULE_DEVICE_TABLE(sdio, wl1271_devices);
+
+static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
+{
+ return wl->if_priv;
+}
+
+static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
+{
+ return &(wl_to_func(wl)->dev);
+}
+
+static irqreturn_t wl1271_irq(int irq, void *cookie)
+{
+ struct wl1271 *wl = cookie;
+ unsigned long flags;
+
+ wl1271_debug(DEBUG_IRQ, "IRQ");
+
+ /* complete the ELP completion */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ if (wl->elp_compl) {
+ complete(wl->elp_compl);
+ wl->elp_compl = NULL;
+ }
+
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static void wl1271_sdio_disable_interrupts(struct wl1271 *wl)
+{
+ disable_irq(wl->irq);
+}
+
+static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
+{
+ enable_irq(wl->irq);
+}
+
+static void wl1271_sdio_reset(struct wl1271 *wl)
+{
+}
+
+static void wl1271_sdio_init(struct wl1271 *wl)
+{
+}
+
+static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ int ret;
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
+ ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
+ wl1271_debug(DEBUG_SPI, "sdio read 52 addr 0x%x, byte 0x%02x",
+ addr, ((u8 *)buf)[0]);
+ } else {
+ if (fixed)
+ ret = sdio_readsb(func, buf, addr, len);
+ else
+ ret = sdio_memcpy_fromio(func, buf, addr, len);
+
+ wl1271_debug(DEBUG_SPI, "sdio read 53 addr 0x%x, %d bytes",
+ addr, len);
+ wl1271_dump_ascii(DEBUG_SPI, "data: ", buf, len);
+ }
+
+ if (ret)
+ wl1271_error("sdio read failed (%d)", ret);
+
+ sdio_release_host(func);
+}
+
+static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ int ret;
+ struct sdio_func *func = wl_to_func(wl);
+
+ sdio_claim_host(func);
+ if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
+ sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
+ wl1271_debug(DEBUG_SPI, "sdio write 52 addr 0x%x, byte 0x%02x",
+ addr, ((u8 *)buf)[0]);
+ } else {
+ wl1271_debug(DEBUG_SPI, "sdio write 53 addr 0x%x, %d bytes",
+ addr, len);
+ wl1271_dump_ascii(DEBUG_SPI, "data: ", buf, len);
+
+ if (fixed)
+ ret = sdio_writesb(func, addr, buf, len);
+ else
+ ret = sdio_memcpy_toio(func, addr, buf, len);
+ }
+ if (ret)
+ wl1271_error("sdio write failed (%d)", ret);
+
+ sdio_release_host(func);
+}
+
+static struct wl1271_if_operations sdio_ops = {
+ .read = wl1271_sdio_raw_read,
+ .write = wl1271_sdio_raw_write,
+ .reset = wl1271_sdio_reset,
+ .init = wl1271_sdio_init,
+ .dev = wl1271_sdio_wl_to_dev,
+ .enable_irq = wl1271_sdio_enable_interrupts,
+ .disable_irq = wl1271_sdio_disable_interrupts
+};
+
+static void wl1271_sdio_set_power(bool enable)
+{
+}
+
+static int __devinit wl1271_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct ieee80211_hw *hw;
+ struct wl1271 *wl;
+ int ret;
+
+ /* We are only able to handle the wlan function */
+ if (func->num != 0x02)
+ return -ENODEV;
+
+ hw = wl1271_alloc_hw();
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ wl = hw->priv;
+
+ wl->if_priv = func;
+ wl->if_ops = &sdio_ops;
+
+ wl->set_power = wl1271_sdio_set_power;
+
+ /* Grab access to FN0 for ELP reg. */
+ func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+
+ wl->irq = gpio_to_irq(RX71_WL1271_IRQ_GPIO);
+ if (wl->irq < 0) {
+ ret = wl->irq;
+ wl1271_error("could not get irq!");
+ goto out_free;
+ }
+
+ ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
+ if (ret < 0) {
+ wl1271_error("request_irq() failed: %d", ret);
+ goto out_free;
+ }
+
+ set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+
+ disable_irq(wl->irq);
+
+ ret = wl1271_init_ieee80211(wl);
+ if (ret)
+ goto out_irq;
+
+ ret = wl1271_register_hw(wl);
+ if (ret)
+ goto out_irq;
+
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret)
+ goto out_release;
+
+ sdio_release_host(func);
+
+ wl1271_notice("initialized");
+
+ return 0;
+
+ out_release:
+ sdio_release_host(func);
+
+ out_irq:
+ free_irq(wl->irq, wl);
+
+
+ out_free:
+ ieee80211_free_hw(hw);
+
+ return ret;
+}
+
+static void __devexit wl1271_remove(struct sdio_func *func)
+{
+ struct wl1271 *wl = sdio_get_drvdata(func);
+
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ ieee80211_unregister_hw(wl->hw);
+
+ free_irq(wl->irq, wl);
+
+ kfree(wl->target_mem_map);
+ vfree(wl->fw);
+ wl->fw = NULL;
+ kfree(wl->nvs);
+ wl->nvs = NULL;
+
+ kfree(wl->fw_status);
+ kfree(wl->tx_res_if);
+
+ ieee80211_free_hw(wl->hw);
+}
+
+static struct sdio_driver wl1271_sdio_driver = {
+ .name = "wl1271",
+ .id_table = wl1271_devices,
+ .probe = wl1271_probe,
+ .remove = __devexit_p(wl1271_remove),
+};
+
+static int __init wl1271_init(void)
+{
+ int ret;
+
+ ret = sdio_register_driver(&wl1271_sdio_driver);
+ if (ret < 0) {
+ wl1271_error("failed to register sdio driver: %d", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit wl1271_exit(void)
+{
+ sdio_unregister_driver(&wl1271_sdio_driver);
+
+ wl1271_notice("unloaded");
+}
+
+module_init(wl1271_init);
+module_exit(wl1271_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luciano Coelho <[email protected]>");
+MODULE_AUTHOR("Juuso Oikarinen <[email protected]>");
+MODULE_FIRMWARE(WL1271_FW_NAME);
--
1.6.3.3


2010-02-22 08:35:53

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 15/22] wl1271: Aggregate RX acknowledgements to FW

On Mon, 2010-02-22 at 08:38 +0200, Juuso Oikarinen wrote:

> wl->rx_counter++;
> drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
> - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
> }
> +
> + wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
> }

What if the counter overflows and you got the & to change it?

johannes


2010-02-22 06:41:15

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 01/22] wl1271: Moved module basics to wl1271_spi.c

From: Teemu Paasikivi <[email protected]>

Moved wl1271 drivers probe, remove etc. functions and structres to
wl1271_spi.c from wl1271_main.c in preparation of implementing SDIO interface.

Signed-off-by: Teemu Paasikivi <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_io.h | 8 ++
drivers/net/wireless/wl12xx/wl1271_main.c | 191 +----------------------------
drivers/net/wireless/wl12xx/wl1271_spi.c | 180 +++++++++++++++++++++++++++
3 files changed, 193 insertions(+), 186 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h
index fa9a0b3..38fce4c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.h
+++ b/drivers/net/wireless/wl12xx/wl1271_io.h
@@ -65,4 +65,12 @@ static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
wl1271_raw_write(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
}
+
+/* Functions from wl1271_main.c */
+
+int wl1271_register_hw(struct wl1271 *wl);
+int wl1271_init_ieee80211(struct wl1271 *wl);
+struct ieee80211_hw *wl1271_alloc_hw(void);
+int wl1271_free_hw(struct wl1271 *wl);
+
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 2a864b2..66319aa 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -22,16 +22,12 @@
*/

#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/delay.h>
-#include <linux/irq.h>
#include <linux/spi/spi.h>
#include <linux/crc32.h>
#include <linux/etherdevice.h>
#include <linux/vmalloc.h>
-#include <linux/spi/wl12xx.h>
#include <linux/inetdevice.h>

#include "wl1271.h"
@@ -484,28 +480,6 @@ out:
mutex_unlock(&wl->mutex);
}

-static irqreturn_t wl1271_irq(int irq, void *cookie)
-{
- struct wl1271 *wl;
- unsigned long flags;
-
- wl1271_debug(DEBUG_IRQ, "IRQ");
-
- wl = cookie;
-
- /* complete the ELP completion */
- spin_lock_irqsave(&wl->wl_lock, flags);
- if (wl->elp_compl) {
- complete(wl->elp_compl);
- wl->elp_compl = NULL;
- }
-
- ieee80211_queue_work(wl->hw, &wl->irq_work);
- spin_unlock_irqrestore(&wl->wl_lock, flags);
-
- return IRQ_HANDLED;
-}
-
static int wl1271_fetch_firmware(struct wl1271 *wl)
{
const struct firmware *fw;
@@ -1959,7 +1933,7 @@ static const struct ieee80211_ops wl1271_ops = {
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};

-static int wl1271_register_hw(struct wl1271 *wl)
+int wl1271_register_hw(struct wl1271 *wl)
{
int ret;

@@ -1981,7 +1955,7 @@ static int wl1271_register_hw(struct wl1271 *wl)
return 0;
}

-static int wl1271_init_ieee80211(struct wl1271 *wl)
+int wl1271_init_ieee80211(struct wl1271 *wl)
{
/* The tx descriptor buffer and the TKIP space. */
wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
@@ -2009,24 +1983,9 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
return 0;
}

-static void wl1271_device_release(struct device *dev)
-{
-
-}
-
-static struct platform_device wl1271_device = {
- .name = "wl1271",
- .id = -1,
-
- /* device model insists to have a release function */
- .dev = {
- .release = wl1271_device_release,
- },
-};
-
#define WL1271_DEFAULT_CHANNEL 0

-static struct ieee80211_hw *wl1271_alloc_hw(void)
+struct ieee80211_hw *wl1271_alloc_hw(void)
{
struct ieee80211_hw *hw;
struct wl1271 *wl;
@@ -2073,6 +2032,8 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
/* Apply default driver configuration. */
wl1271_conf_init(wl);

+ wl1271_debugfs_init(wl);
+
return hw;
}

@@ -2095,145 +2056,3 @@ int wl1271_free_hw(struct wl1271 *wl)

return 0;
}
-
-static int __devinit wl1271_probe(struct spi_device *spi)
-{
- struct wl12xx_platform_data *pdata;
- struct ieee80211_hw *hw;
- struct wl1271 *wl;
- int ret;
-
- pdata = spi->dev.platform_data;
- if (!pdata) {
- wl1271_error("no platform data");
- return -ENODEV;
- }
-
- hw = wl1271_alloc_hw();
- if (IS_ERR(hw))
- return PTR_ERR(hw);
-
- wl = hw->priv;
-
- dev_set_drvdata(&spi->dev, wl);
- wl->spi = spi;
-
- /* This is the only SPI value that we need to set here, the rest
- * comes from the board-peripherals file */
- spi->bits_per_word = 32;
-
- ret = spi_setup(spi);
- if (ret < 0) {
- wl1271_error("spi_setup failed");
- goto out_free;
- }
-
- wl->set_power = pdata->set_power;
- if (!wl->set_power) {
- wl1271_error("set power function missing in platform data");
- ret = -ENODEV;
- goto out_free;
- }
-
- wl->irq = spi->irq;
- if (wl->irq < 0) {
- wl1271_error("irq missing in platform data");
- ret = -ENODEV;
- goto out_free;
- }
-
- ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
- if (ret < 0) {
- wl1271_error("request_irq() failed: %d", ret);
- goto out_free;
- }
-
- set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
-
- disable_irq(wl->irq);
-
- ret = platform_device_register(&wl1271_device);
- if (ret) {
- wl1271_error("couldn't register platform device");
- goto out_irq;
- }
- dev_set_drvdata(&wl1271_device.dev, wl);
-
- ret = wl1271_init_ieee80211(wl);
- if (ret)
- goto out_platform;
-
- ret = wl1271_register_hw(wl);
- if (ret)
- goto out_platform;
-
- wl1271_debugfs_init(wl);
-
- wl1271_notice("initialized");
-
- return 0;
-
- out_platform:
- platform_device_unregister(&wl1271_device);
-
- out_irq:
- free_irq(wl->irq, wl);
-
- out_free:
- ieee80211_free_hw(hw);
-
- return ret;
-}
-
-static int __devexit wl1271_remove(struct spi_device *spi)
-{
- struct wl1271 *wl = dev_get_drvdata(&spi->dev);
-
- platform_device_unregister(&wl1271_device);
- free_irq(wl->irq, wl);
-
- wl1271_free_hw(wl);
-
- return 0;
-}
-
-
-static struct spi_driver wl1271_spi_driver = {
- .driver = {
- .name = "wl1271",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
-
- .probe = wl1271_probe,
- .remove = __devexit_p(wl1271_remove),
-};
-
-static int __init wl1271_init(void)
-{
- int ret;
-
- ret = spi_register_driver(&wl1271_spi_driver);
- if (ret < 0) {
- wl1271_error("failed to register spi driver: %d", ret);
- goto out;
- }
-
-out:
- return ret;
-}
-
-static void __exit wl1271_exit(void)
-{
- spi_unregister_driver(&wl1271_spi_driver);
-
- wl1271_notice("unloaded");
-}
-
-module_init(wl1271_init);
-module_exit(wl1271_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Luciano Coelho <[email protected]>");
-MODULE_AUTHOR("Juuso Oikarinen <[email protected]>");
-MODULE_FIRMWARE(WL1271_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 67a8293..c26726a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -21,14 +21,17 @@
*
*/

+#include <linux/irq.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/crc7.h>
#include <linux/spi/spi.h>
+#include <linux/spi/wl12xx.h>

#include "wl1271.h"
#include "wl12xx_80211.h"
#include "wl1271_spi.h"
+#include "wl1271_io.h"


void wl1271_spi_reset(struct wl1271 *wl)
@@ -255,3 +258,180 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
+
+static irqreturn_t wl1271_irq(int irq, void *cookie)
+{
+ struct wl1271 *wl;
+ unsigned long flags;
+
+ wl1271_debug(DEBUG_IRQ, "IRQ");
+
+ wl = cookie;
+
+ /* complete the ELP completion */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ if (wl->elp_compl) {
+ complete(wl->elp_compl);
+ wl->elp_compl = NULL;
+ }
+
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static void wl1271_device_release(struct device *dev)
+{
+
+}
+
+static struct platform_device wl1271_device = {
+ .name = "wl1271",
+ .id = -1,
+
+ /* device model insists to have a release function */
+ .dev = {
+ .release = wl1271_device_release,
+ },
+};
+
+static int __devinit wl1271_probe(struct spi_device *spi)
+{
+ struct wl12xx_platform_data *pdata;
+ struct ieee80211_hw *hw;
+ struct wl1271 *wl;
+ int ret;
+
+ pdata = spi->dev.platform_data;
+ if (!pdata) {
+ wl1271_error("no platform data");
+ return -ENODEV;
+ }
+
+ hw = wl1271_alloc_hw();
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ wl = hw->priv;
+
+ dev_set_drvdata(&spi->dev, wl);
+ wl->spi = spi;
+
+ /* This is the only SPI value that we need to set here, the rest
+ * comes from the board-peripherals file */
+ spi->bits_per_word = 32;
+
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ wl1271_error("spi_setup failed");
+ goto out_free;
+ }
+
+ wl->set_power = pdata->set_power;
+ if (!wl->set_power) {
+ wl1271_error("set power function missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
+ }
+
+ wl->irq = spi->irq;
+ if (wl->irq < 0) {
+ wl1271_error("irq missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
+ }
+
+ ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
+ if (ret < 0) {
+ wl1271_error("request_irq() failed: %d", ret);
+ goto out_free;
+ }
+
+ set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+
+ disable_irq(wl->irq);
+
+ ret = platform_device_register(&wl1271_device);
+ if (ret) {
+ wl1271_error("couldn't register platform device");
+ goto out_irq;
+ }
+ dev_set_drvdata(&wl1271_device.dev, wl);
+
+ ret = wl1271_init_ieee80211(wl);
+ if (ret)
+ goto out_platform;
+
+ ret = wl1271_register_hw(wl);
+ if (ret)
+ goto out_platform;
+
+ wl1271_notice("initialized");
+
+ return 0;
+
+ out_platform:
+ platform_device_unregister(&wl1271_device);
+
+ out_irq:
+ free_irq(wl->irq, wl);
+
+ out_free:
+ ieee80211_free_hw(hw);
+
+ return ret;
+}
+
+static int __devexit wl1271_remove(struct spi_device *spi)
+{
+ struct wl1271 *wl = dev_get_drvdata(&spi->dev);
+
+ platform_device_unregister(&wl1271_device);
+ free_irq(wl->irq, wl);
+
+ wl1271_free_hw(wl);
+
+ return 0;
+}
+
+
+static struct spi_driver wl1271_spi_driver = {
+ .driver = {
+ .name = "wl1271",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = wl1271_probe,
+ .remove = __devexit_p(wl1271_remove),
+};
+
+static int __init wl1271_init(void)
+{
+ int ret;
+
+ ret = spi_register_driver(&wl1271_spi_driver);
+ if (ret < 0) {
+ wl1271_error("failed to register spi driver: %d", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit wl1271_exit(void)
+{
+ spi_unregister_driver(&wl1271_spi_driver);
+
+ wl1271_notice("unloaded");
+}
+
+module_init(wl1271_init);
+module_exit(wl1271_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luciano Coelho <[email protected]>");
+MODULE_AUTHOR("Juuso Oikarinen <[email protected]>");
+MODULE_FIRMWARE(WL1271_FW_NAME);
--
1.6.3.3


2010-02-22 06:41:30

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 12/22] wl1271: Fix ad-hoc mode neighborhood detection

This patch fixes a bug in ad-hoc mode preventing mac80211 from properly
detecting other ad-hoc networks with the same SSID.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_cmd.c | 4 ++--
drivers/net/wireless/wl12xx/wl1271_cmd.h | 2 +-
drivers/net/wireless/wl12xx/wl1271_main.c | 15 +++++++--------
3 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index 6759aa1..e029bf0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -247,7 +247,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
return ret;
}

-int wl1271_cmd_join(struct wl1271 *wl)
+int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
{
static bool do_cal = true;
struct wl1271_cmd_join *join;
@@ -278,7 +278,7 @@ int wl1271_cmd_join(struct wl1271 *wl)

join->rx_config_options = cpu_to_le32(wl->rx_config);
join->rx_filter_options = cpu_to_le32(wl->rx_filter);
- join->bss_type = wl->bss_type;
+ join->bss_type = bss_type;

/*
* FIXME: disable temporarily all filters because after commit
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index 2dc06c7..4297205 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -33,7 +33,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len);
int wl1271_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl);
-int wl1271_cmd_join(struct wl1271 *wl);
+int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 5cc778f..81fb02e 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -1093,7 +1093,7 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,

memcpy(wl->bssid, conf->bssid, ETH_ALEN);

- ret = wl1271_cmd_join(wl);
+ ret = wl1271_cmd_join(wl, wl->bss_type);
if (ret < 0)
goto out_sleep;

@@ -1142,17 +1142,16 @@ static int wl1271_join_channel(struct wl1271 *wl, int channel)
static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
0xad, 0xbe, 0xef };

- /* the dummy join is not required for ad-hoc */
- if (wl->bss_type == BSS_TYPE_IBSS)
- goto out;
-
/* disable mac filter, so we hear everything */
wl->rx_config &= ~CFG_BSSID_FILTER_EN;

wl->channel = channel;
memcpy(wl->bssid, dummy_bssid, ETH_ALEN);

- ret = wl1271_cmd_join(wl);
+ /* the dummy join is performed always with STATION BSS type to allow
+ also ad-hoc mode to listen to the surroundings without sending any
+ beacons yet. */
+ ret = wl1271_cmd_join(wl, BSS_TYPE_STA_BSS);
if (ret < 0)
goto out;

@@ -1221,7 +1220,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
wl->channel = channel;
/* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
- ret = wl1271_cmd_join(wl);
+ ret = wl1271_cmd_join(wl, wl->bss_type);
if (ret < 0)
wl1271_warning("cmd join to update channel failed %d",
ret);
@@ -1704,7 +1703,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}

if (do_join) {
- ret = wl1271_cmd_join(wl);
+ ret = wl1271_cmd_join(wl, wl->bss_type);
if (ret < 0) {
wl1271_warning("cmd join failed %d", ret);
goto out_sleep;
--
1.6.3.3


2010-02-22 06:41:34

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 13/22] wl1271: Fix queue stopping/waking for TX path

The queue stopping/waking functionality was broken in a way that could
cause huge latencies in TX transfers and even cause the TX to stall in the
right circumstances. Correct these problems.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271.h | 3 ++-
drivers/net/wireless/wl12xx/wl1271_main.c | 12 +++++-------
drivers/net/wireless/wl12xx/wl1271_tx.c | 28 +++++++++++++++-------------
3 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index cc974ea..7f03f89 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -491,7 +491,8 @@ int wl1271_plt_stop(struct wl1271 *wl);

#define WL1271_DEFAULT_POWER_LEVEL 0

-#define WL1271_TX_QUEUE_MAX_LENGTH 20
+#define WL1271_TX_QUEUE_LOW_WATERMARK 10
+#define WL1271_TX_QUEUE_HIGH_WATERMARK 25

/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
on in case is has been shut down shortly before */
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 81fb02e..184264a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -791,15 +791,13 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
- ieee80211_stop_queues(wl->hw);
+ if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
+ wl1271_debug(DEBUG_TX, "op_tx: stopping queues");

- /*
- * FIXME: this is racy, the variable is not properly
- * protected. Maybe fix this by removing the stupid
- * variable altogether and checking the real queue state?
- */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ ieee80211_stop_queues(wl->hw);
set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
}

return NETDEV_TX_OK;
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 2e057b0..7926471 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -278,22 +278,12 @@ void wl1271_tx_work(struct work_struct *work)

ret = wl1271_tx_frame(wl, skb);
if (ret == -EBUSY) {
- /* firmware buffer is full, stop queues */
- wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, "
- "stop queues");
- ieee80211_stop_queues(wl->hw);
- set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+ /* firmware buffer is full, lets stop transmitting. */
skb_queue_head(&wl->tx_queue, skb);
goto out_ack;
} else if (ret < 0) {
dev_kfree_skb(skb);
goto out_ack;
- } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED,
- &wl->flags)) {
- /* firmware buffer has space, restart queues */
- wl1271_debug(DEBUG_TX,
- "complete_packet: waking queues");
- ieee80211_wake_queues(wl->hw);
}
}

@@ -380,8 +370,6 @@ void wl1271_tx_complete(struct wl1271 *wl)
u32 count, fw_counter;
u32 i;

- wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
-
/* read the tx results from the chipset */
wl1271_read(wl, le32_to_cpu(memmap->tx_result),
wl->tx_res_if, sizeof(*wl->tx_res_if), false);
@@ -393,6 +381,7 @@ void wl1271_tx_complete(struct wl1271 *wl)
tx_result_host_counter), fw_counter);

count = fw_counter - wl->tx_results_count;
+ wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);

/* verify that the result buffer is not getting overrun */
if (unlikely(count > TX_HW_RESULT_QUEUE_LEN))
@@ -409,6 +398,19 @@ void wl1271_tx_complete(struct wl1271 *wl)

wl->tx_results_count++;
}
+
+ if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
+ skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) {
+ unsigned long flags;
+
+ /* firmware buffer has space, restart queues */
+ wl1271_debug(DEBUG_TX, "tx_complete: waking queues");
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ ieee80211_wake_queues(wl->hw);
+ clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
+ }
}

/* caller must hold wl->mutex */
--
1.6.3.3


2010-02-22 06:41:32

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 18/22] wl1271: Update TX packet life time handling with higher resolution time

This patch uses a higher precision timer to synchronize with the firmware
clock. Improved precision is needed as on some platforms a jiffy may be up to
tens of milliseconds, and the required precision is closer to TU's.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Teemu Paasikivi <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271.h | 2 +-
drivers/net/wireless/wl12xx/wl1271_main.c | 6 ++++--
drivers/net/wireless/wl12xx/wl1271_tx.c | 7 +++++--
3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 457ce72..41de47c 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -404,7 +404,7 @@ struct wl1271 {
u32 tx_packets_count;

/* Time-offset between host and chipset clocks */
- int time_offset;
+ s64 time_offset;

/* Session counter for the chipset */
int session_counter;
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 9f74168..4c4d22a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -374,6 +374,7 @@ static void wl1271_power_on(struct wl1271 *wl)
static void wl1271_fw_status(struct wl1271 *wl,
struct wl1271_fw_status *status)
{
+ struct timespec ts;
u32 total = 0;
int i;

@@ -402,8 +403,9 @@ static void wl1271_fw_status(struct wl1271 *wl,
ieee80211_queue_work(wl->hw, &wl->tx_work);

/* update the host-chipset time offset */
- wl->time_offset = jiffies_to_usecs(jiffies) -
- le32_to_cpu(status->fw_localtime);
+ getnstimeofday(&ts);
+ wl->time_offset = (timespec_to_ns(&ts) >> 10) -
+ (s64)le32_to_cpu(status->fw_localtime);
}

#define WL1271_IRQ_MAX_LOOPS 10
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 7926471..a32d301 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -86,8 +86,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
u32 extra, struct ieee80211_tx_info *control)
{
+ struct timespec ts;
struct wl1271_tx_hw_descr *desc;
int pad, ac;
+ s64 hosttime;
u16 tx_attr;

desc = (struct wl1271_tx_hw_descr *) skb->data;
@@ -101,8 +103,9 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
}

/* configure packet life time */
- desc->start_time = cpu_to_le32(jiffies_to_usecs(jiffies) -
- wl->time_offset);
+ getnstimeofday(&ts);
+ hosttime = (timespec_to_ns(&ts) >> 10);
+ desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);

/* configure the tx attributes */
--
1.6.3.3


2010-02-22 06:41:24

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 15/22] wl1271: Aggregate RX acknowledgements to FW

This patch will ack RX frames read from the firmware in one single write,
instead of acking all the frames separately. This will reduce the amount of
required communication per frame.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Teemu Paasikivi <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_rx.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index 2df7852..b824c6c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -224,6 +224,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)

wl->rx_counter++;
drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
- wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
}
+
+ wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
}
--
1.6.3.3


2010-02-22 06:41:30

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 20/22] wl1271: Clean up TX security sequence number handling

Instead of managing the TX security sequence number as two variables, use
one 64 bit variable. This greatly simplifies the handling of the number.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Teemu Paasikivi <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271.h | 6 ++++--
drivers/net/wireless/wl12xx/wl1271_cmd.c | 3 +--
drivers/net/wireless/wl12xx/wl1271_main.c | 11 +++++------
drivers/net/wireless/wl12xx/wl1271_tx.c | 10 ++--------
4 files changed, 12 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 41de47c..0deb4fd 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -110,6 +110,9 @@ enum {
#define WL1271_FW_NAME "wl1271-fw.bin"
#define WL1271_NVS_NAME "wl1271-nvs.bin"

+#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
+#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
+
/* NVS data structure */
#define WL1271_NVS_SECTION_SIZE 468

@@ -419,8 +422,7 @@ struct wl1271 {

/* Security sequence number counters */
u8 tx_security_last_seq;
- u16 tx_security_seq_16;
- u32 tx_security_seq_32;
+ s64 tx_security_seq;

/* FW Rx counter */
u32 rx_counter;
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index e029bf0..d59b383 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -318,8 +318,7 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)

/* reset TX security counters */
wl->tx_security_last_seq = 0;
- wl->tx_security_seq_16 = 0;
- wl->tx_security_seq_32 = 0;
+ wl->tx_security_seq = 0;

ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0);
if (ret < 0) {
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 4c4d22a..f10ba84 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -1020,8 +1020,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->tx_results_count = 0;
wl->tx_packets_count = 0;
wl->tx_security_last_seq = 0;
- wl->tx_security_seq_16 = 0;
- wl->tx_security_seq_32 = 0;
+ wl->tx_security_seq = 0;
wl->time_offset = 0;
wl->session_counter = 0;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
@@ -1428,15 +1427,15 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key_type = KEY_TKIP;

key_conf->hw_key_idx = key_conf->keyidx;
- tx_seq_32 = wl->tx_security_seq_32;
- tx_seq_16 = wl->tx_security_seq_16;
+ tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
+ tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
break;
case ALG_CCMP:
key_type = KEY_AES;

key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- tx_seq_32 = wl->tx_security_seq_32;
- tx_seq_16 = wl->tx_security_seq_16;
+ tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
+ tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
break;
default:
wl1271_error("Unknown key algo 0x%x", key_conf->alg);
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index d3ed63e..1b11e2c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -303,7 +303,6 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
{
struct ieee80211_tx_info *info;
struct sk_buff *skb;
- u16 seq;
int id = result->id;

/* check for id legality */
@@ -331,15 +330,10 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
wl->stats.retry_count += result->ack_failures;

/* update security sequence number */
- seq = wl->tx_security_seq_16 +
- (result->lsb_security_sequence_number -
- wl->tx_security_last_seq);
+ wl->tx_security_seq += (result->lsb_security_sequence_number -
+ wl->tx_security_last_seq);
wl->tx_security_last_seq = result->lsb_security_sequence_number;

- if (seq < wl->tx_security_seq_16)
- wl->tx_security_seq_32++;
- wl->tx_security_seq_16 = seq;
-
/* remove private header from packet */
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));

--
1.6.3.3


2010-02-22 06:41:26

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 11/22] wl1271: Improvements to the TX path

- Fix a TX result overflow problem that was present in the TX path and visible
with at least linksys AP's (probably any AP with high throughput capability.)
- Optimize TX by writing FW trigger for a group of TX frames instead of
each and every frame.
- Slightly optimize the TX path code.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271.h | 4 +-
drivers/net/wireless/wl12xx/wl1271_main.c | 8 ++----
drivers/net/wireless/wl12xx/wl1271_tx.c | 38 +++++++++++++++++-----------
drivers/net/wireless/wl12xx/wl1271_tx.h | 2 +-
4 files changed, 29 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 10135c9..cc974ea 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -396,10 +396,10 @@ struct wl1271 {
/* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed[NUM_TX_QUEUES];
u32 tx_blocks_available;
- u8 tx_results_count;
+ u32 tx_results_count;

/* Transmitted TX packets counter for chipset interface */
- int tx_packets_count;
+ u32 tx_packets_count;

/* Time-offset between host and chipset clocks */
int time_offset;
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 310f58c..5cc778f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -453,14 +453,12 @@ static void wl1271_irq_work(struct work_struct *work)
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;
-
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");

/* check for tx results */
- if (tx_res_cnt)
- wl1271_tx_complete(wl, tx_res_cnt);
+ if (wl->fw_status->tx_results_counter !=
+ (wl->tx_results_count & 0xff))
+ wl1271_tx_complete(wl);

wl1271_rx(wl, wl->fw_status);
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 2b7dd9b..2e057b0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -169,7 +169,6 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,

/* write packet new counter into the write access register */
wl->tx_packets_count++;
- wl1271_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)",
@@ -244,6 +243,7 @@ void wl1271_tx_work(struct work_struct *work)
struct sk_buff *skb;
bool woken_up = false;
u32 sta_rates = 0;
+ u32 prev_tx_packets_count;
int ret;

/* check if the rates supported by the AP have changed */
@@ -260,6 +260,8 @@ void wl1271_tx_work(struct work_struct *work)
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;

+ prev_tx_packets_count = wl->tx_packets_count;
+
/* if rates have changed, re-configure the rate policy */
if (unlikely(sta_rates)) {
wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
@@ -270,7 +272,7 @@ void wl1271_tx_work(struct work_struct *work)
if (!woken_up) {
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
- goto out;
+ goto out_ack;
woken_up = true;
}

@@ -282,10 +284,10 @@ void wl1271_tx_work(struct work_struct *work)
ieee80211_stop_queues(wl->hw);
set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
skb_queue_head(&wl->tx_queue, skb);
- goto out;
+ goto out_ack;
} else if (ret < 0) {
dev_kfree_skb(skb);
- goto out;
+ goto out_ack;
} else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED,
&wl->flags)) {
/* firmware buffer has space, restart queues */
@@ -295,6 +297,11 @@ void wl1271_tx_work(struct work_struct *work)
}
}

+out_ack:
+ /* interrupt the firmware with the new packets */
+ if (prev_tx_packets_count != wl->tx_packets_count)
+ wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+
out:
if (woken_up)
wl1271_ps_elp_sleep(wl);
@@ -311,7 +318,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
int id = result->id;

/* check for id legality */
- if (id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL) {
+ if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) {
wl1271_warning("TX result illegal id: %d", id);
return;
}
@@ -366,10 +373,11 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
}

/* Called upon reception of a TX complete interrupt */
-void wl1271_tx_complete(struct wl1271 *wl, u32 count)
+void wl1271_tx_complete(struct wl1271 *wl)
{
struct wl1271_acx_mem_map *memmap =
(struct wl1271_acx_mem_map *)wl->target_mem_map;
+ u32 count, fw_counter;
u32 i;

wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
@@ -377,12 +385,18 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
/* read the tx results from the chipset */
wl1271_read(wl, le32_to_cpu(memmap->tx_result),
wl->tx_res_if, sizeof(*wl->tx_res_if), false);
+ fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter);
+
+ /* write host counter to chipset (to ack) */
+ wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
+ offsetof(struct wl1271_tx_hw_res_if,
+ tx_result_host_counter), fw_counter);
+
+ count = fw_counter - wl->tx_results_count;

/* verify that the result buffer is not getting overrun */
- if (count > TX_HW_RESULT_QUEUE_LEN) {
+ if (unlikely(count > TX_HW_RESULT_QUEUE_LEN))
wl1271_warning("TX result overflow from chipset: %d", count);
- count = TX_HW_RESULT_QUEUE_LEN;
- }

/* process the results */
for (i = 0; i < count; i++) {
@@ -395,12 +409,6 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)

wl->tx_results_count++;
}
-
- /* write host counter to chipset (to ack) */
- wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
- offsetof(struct wl1271_tx_hw_res_if,
- tx_result_host_counter),
- le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
}

/* caller must hold wl->mutex */
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 17e405a..ca92bd8 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -160,7 +160,7 @@ static inline int wl1271_tx_ac_to_tid(int ac)
}

void wl1271_tx_work(struct work_struct *work);
-void wl1271_tx_complete(struct wl1271 *wl, u32 count);
+void wl1271_tx_complete(struct wl1271 *wl);
void wl1271_tx_flush(struct wl1271 *wl);

#endif
--
1.6.3.3


2010-02-22 06:41:21

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 06/22] wl1271: Divided driver to two separate modules

From: Teemu Paasikivi <[email protected]>

Divided wl1271 driver to wl1271 "core" and wl1271_spi modules in preparation
of integration of the SDIO implementation.

Signed-off-by: Teemu Paasikivi <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/Kconfig | 12 ++++++++++++
drivers/net/wireless/wl12xx/Makefile | 5 +++--
drivers/net/wireless/wl12xx/wl1271_main.c | 8 ++++++++
3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 785e024..9c6fdcc 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -51,3 +51,15 @@ config WL1271

If you choose to build a module, it'll be called wl1271. Say N if
unsure.
+
+config WL1271_SPI
+ tristate "TI wl1251 SPI support"
+ depends on WL1271 && SPI_MASTER
+ ---help---
+ This module adds support for the SPI interface of adapters using
+ TI wl1271 chipset. Select this if your platform is using
+ the SPI bus.
+
+ If you choose to build a module, it'll be called wl1251_spi.
+ Say N if unsure.
+
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index f47ec94..473a1e2 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -7,10 +7,11 @@ obj-$(CONFIG_WL1251) += wl1251.o
obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o
obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o

-wl1271-objs = wl1271_main.o wl1271_spi.o wl1271_cmd.o \
+wl1271-objs = wl1271_main.o wl1271_cmd.o wl1271_io.o \
wl1271_event.o wl1271_tx.o wl1271_rx.o \
wl1271_ps.o wl1271_acx.o wl1271_boot.o \
- wl1271_init.o wl1271_debugfs.o wl1271_io.o
+ wl1271_init.o wl1271_debugfs.o

wl1271-$(CONFIG_NL80211_TESTMODE) += wl1271_testmode.o
obj-$(CONFIG_WL1271) += wl1271.o
+obj-$(CONFIG_WL1271_SPI) += wl1271_spi.o
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 54bc1e9..ea49ced 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -1948,6 +1948,7 @@ int wl1271_register_hw(struct wl1271 *wl)

return 0;
}
+EXPORT_SYMBOL_GPL(wl1271_register_hw);

int wl1271_init_ieee80211(struct wl1271 *wl)
{
@@ -1976,6 +1977,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl)

return 0;
}
+EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);

#define WL1271_DEFAULT_CHANNEL 0

@@ -2030,6 +2032,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)

return hw;
}
+EXPORT_SYMBOL_GPL(wl1271_alloc_hw);

int wl1271_free_hw(struct wl1271 *wl)
{
@@ -2050,3 +2053,8 @@ int wl1271_free_hw(struct wl1271 *wl)

return 0;
}
+EXPORT_SYMBOL_GPL(wl1271_free_hw);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luciano Coelho <[email protected]>");
+MODULE_AUTHOR("Juuso Oikarinen <[email protected]>");
--
1.6.3.3


2010-02-22 06:41:25

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 04/22] wl1271: Inlined IO functions

From: Teemu Paasikivi <[email protected]>

Changed IO functions to static inline.

Signed-off-by: Teemu Paasikivi <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_io.c | 70 ----------------------
drivers/net/wireless/wl12xx/wl1271_io.h | 96 ++++++++++++++++++++++++------
drivers/net/wireless/wl12xx/wl1271_spi.c | 2 +-
3 files changed, 78 insertions(+), 90 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_io.c b/drivers/net/wireless/wl12xx/wl1271_io.c
index d00f7ed..c082658 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.c
+++ b/drivers/net/wireless/wl12xx/wl1271_io.c
@@ -31,11 +31,6 @@
#include "wl1271_spi.h"
#include "wl1271_io.h"

-struct device *wl1271_wl_to_dev(struct wl1271 *wl)
-{
- return wl->if_ops->dev(wl);
-}
-
void wl1271_disable_interrupts(struct wl1271 *wl)
{
wl->if_ops->disable_irq(wl);
@@ -46,29 +41,6 @@ void wl1271_enable_interrupts(struct wl1271 *wl)
wl->if_ops->enable_irq(wl);
}

-static int wl1271_translate_addr(struct wl1271 *wl, int addr)
-{
- /*
- * To translate, first check to which window of addresses the
- * particular address belongs. Then subtract the starting address
- * of that window from the address. Then, add offset of the
- * translated region.
- *
- * The translated regions occur next to each other in physical device
- * memory, so just add the sizes of the preceeding address regions to
- * get the offset to the new region.
- *
- * Currently, only the two first regions are addressed, and the
- * assumption is that all addresses will fall into either of those
- * two.
- */
- if ((addr >= wl->part.reg.start) &&
- (addr < wl->part.reg.start + wl->part.reg.size))
- return addr - wl->part.reg.start + wl->part.mem.size;
- else
- return addr - wl->part.mem.start;
-}
-
/* Set the SPI partitions to access the chip addresses
*
* To simplify driver code, a fixed (virtual) memory map is defined for
@@ -140,48 +112,6 @@ void wl1271_io_init(struct wl1271 *wl)
wl->if_ops->init(wl);
}

-void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
- size_t len, bool fixed)
-{
- wl->if_ops->write(wl, addr, buf, len, fixed);
-}
-
-void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
- size_t len, bool fixed)
-{
- wl->if_ops->read(wl, addr, buf, len, fixed);
-}
-
-void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed)
-{
- int physical;
-
- physical = wl1271_translate_addr(wl, addr);
-
- wl1271_raw_read(wl, physical, buf, len, fixed);
-}
-
-void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed)
-{
- int physical;
-
- physical = wl1271_translate_addr(wl, addr);
-
- wl1271_raw_write(wl, physical, buf, len, fixed);
-}
-
-u32 wl1271_read32(struct wl1271 *wl, int addr)
-{
- return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
-}
-
-void wl1271_write32(struct wl1271 *wl, int addr, u32 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 */
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h
index f2b6325..8501898 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.h
+++ b/drivers/net/wireless/wl12xx/wl1271_io.h
@@ -33,28 +33,24 @@ void wl1271_enable_interrupts(struct wl1271 *wl);
void wl1271_io_reset(struct wl1271 *wl);
void wl1271_io_init(struct wl1271 *wl);

-struct device *wl1271_wl_to_dev(struct wl1271 *wl);
-
-/* Raw target IO, address is not translated */
-void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
- size_t len, bool fixed);
-void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
- size_t len, bool fixed);
+static inline struct device *wl1271_wl_to_dev(struct wl1271 *wl)
+{
+ return wl->if_ops->dev(wl);
+}

-/* Translated target IO */
-void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed);
-void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed);
-u32 wl1271_read32(struct wl1271 *wl, int addr);
-void wl1271_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);
+/* Raw target IO, address is not translated */
+static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ wl->if_ops->write(wl, addr, buf, len, fixed);
+}

-int wl1271_set_partition(struct wl1271 *wl,
- struct wl1271_partition_set *p);
+static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ wl->if_ops->read(wl, addr, buf, len, fixed);
+}

static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
{
@@ -71,6 +67,68 @@ static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
sizeof(wl->buffer_32), false);
}

+/* Translated target IO */
+static inline int wl1271_translate_addr(struct wl1271 *wl, int addr)
+{
+ /*
+ * To translate, first check to which window of addresses the
+ * particular address belongs. Then subtract the starting address
+ * of that window from the address. Then, add offset of the
+ * translated region.
+ *
+ * The translated regions occur next to each other in physical device
+ * memory, so just add the sizes of the preceeding address regions to
+ * get the offset to the new region.
+ *
+ * Currently, only the two first regions are addressed, and the
+ * assumption is that all addresses will fall into either of those
+ * two.
+ */
+ if ((addr >= wl->part.reg.start) &&
+ (addr < wl->part.reg.start + wl->part.reg.size))
+ return addr - wl->part.reg.start + wl->part.mem.size;
+ else
+ return addr - wl->part.mem.start;
+}
+
+static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ int physical;
+
+ physical = wl1271_translate_addr(wl, addr);
+
+ wl1271_raw_read(wl, physical, buf, len, fixed);
+}
+
+static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
+{
+ int physical;
+
+ physical = wl1271_translate_addr(wl, addr);
+
+ wl1271_raw_write(wl, physical, buf, len, fixed);
+}
+
+static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
+{
+ return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
+}
+
+static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
+{
+ wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), 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);
+
+int wl1271_set_partition(struct wl1271 *wl,
+ struct wl1271_partition_set *p);
+
/* Functions from wl1271_main.c */

int wl1271_register_hw(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index a0f4169..f89e1b3 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -33,7 +33,7 @@
#include "wl1271_spi.h"
#include "wl1271_io.h"

-static struct spi_device *wl_to_spi(struct wl1271 *wl)
+static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
{
return wl->if_priv;
}
--
1.6.3.3


2010-02-22 06:41:42

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 02/22] wl1271: Added functions to enable/disable interrupt handling

From: Teemu Paasikivi <[email protected]>

Added/moved enable and disable interrupt handling functions.

Signed-off-by: Teemu Paasikivi <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_boot.c | 2 +-
drivers/net/wireless/wl12xx/wl1271_io.c | 10 ++++++++++
drivers/net/wireless/wl12xx/wl1271_io.h | 3 +++
drivers/net/wireless/wl12xx/wl1271_main.c | 5 -----
drivers/net/wireless/wl12xx/wl1271_spi.c | 10 ++++++++++
drivers/net/wireless/wl12xx/wl1271_spi.h | 3 +++
6 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index 2be76ee..7d6d2e6 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -299,7 +299,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)

static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
{
- enable_irq(wl->irq);
+ wl1271_enable_interrupts(wl);
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.c b/drivers/net/wireless/wl12xx/wl1271_io.c
index 5cd94d5..b825cfa 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.c
+++ b/drivers/net/wireless/wl12xx/wl1271_io.c
@@ -31,6 +31,16 @@
#include "wl1271_spi.h"
#include "wl1271_io.h"

+void wl1271_disable_interrupts(struct wl1271 *wl)
+{
+ wl1271_spi_disable_interrupts(wl);
+}
+
+void wl1271_enable_interrupts(struct wl1271 *wl)
+{
+ wl1271_spi_enable_interrupts(wl);
+}
+
static int wl1271_translate_addr(struct wl1271 *wl, int addr)
{
/*
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h
index 38fce4c..c8b0971 100644
--- a/drivers/net/wireless/wl12xx/wl1271_io.h
+++ b/drivers/net/wireless/wl12xx/wl1271_io.h
@@ -27,6 +27,9 @@

struct wl1271;

+void wl1271_disable_interrupts(struct wl1271 *wl);
+void wl1271_enable_interrupts(struct wl1271 *wl);
+
void wl1271_io_reset(struct wl1271 *wl);
void wl1271_io_init(struct wl1271 *wl);

diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 66319aa..18347c3 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -360,11 +360,6 @@ static int wl1271_plt_init(struct wl1271 *wl)
return ret;
}

-static void wl1271_disable_interrupts(struct wl1271 *wl)
-{
- disable_irq(wl->irq);
-}
-
static void wl1271_power_off(struct wl1271 *wl)
{
wl->set_power(false);
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index c26726a..b422c9f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -34,6 +34,16 @@
#include "wl1271_io.h"


+void wl1271_spi_disable_interrupts(struct wl1271 *wl)
+{
+ disable_irq(wl->irq);
+}
+
+void wl1271_spi_enable_interrupts(struct wl1271 *wl)
+{
+ enable_irq(wl->irq);
+}
+
void wl1271_spi_reset(struct wl1271 *wl)
{
u8 *cmd;
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h
index a803596..86ff161 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.h
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.h
@@ -84,6 +84,9 @@
#define OCP_STATUS_REQ_FAILED 0x20000
#define OCP_STATUS_RESP_ERROR 0x30000

+void wl1271_spi_disable_interrupts(struct wl1271 *wl);
+void wl1271_spi_enable_interrupts(struct wl1271 *wl);
+
/* Raw target IO, address is not translated */
void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
--
1.6.3.3


2010-02-22 06:41:43

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 22/22] wl1271: Remove tx-power level workaround

This patch removes the workaround limiting chipset TX power to 12dB, instead
using the value configured by the mac80211.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Teemu Paasikivi <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_acx.c | 7 +------
1 files changed, 1 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
index f41f886..60e2087 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -135,12 +135,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
goto out;
}

- /*
- * 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 = 120;
+ acx->current_tx_power = power * 10;

ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
if (ret < 0) {
--
1.6.3.3


2010-02-22 06:41:23

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 16/22] wl1271: Don't mask interrupts while handling interrupt

Don't mask firmware interrupts while processing interrupts. This allows the
interrupt handler looping to work efficiently thus reducing interrupt
processing latency.

Signed-off-by: Juuso Oikarinen <[email protected]>
Reviewed-by: Teemu Paasikivi <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_main.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 4d091eb..a46d323 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -424,8 +424,6 @@ static void wl1271_irq_work(struct work_struct *work)
if (ret < 0)
goto out;

- wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
-
wl1271_fw_status(wl, wl->fw_status);
intr = le32_to_cpu(wl->fw_status->intr);
if (!intr) {
@@ -464,8 +462,6 @@ static void wl1271_irq_work(struct work_struct *work)
}

out_sleep:
- wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
- WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_ps_elp_sleep(wl);

out:
--
1.6.3.3


2010-02-22 18:05:43

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [PATCH 06/22] wl1271: Divided driver to two separate modules

On Sun, Feb 21, 2010 at 10:38 PM, Juuso Oikarinen
<[email protected]> wrote:
> From: Teemu Paasikivi <[email protected]>
>
> Divided wl1271 driver to wl1271 "core" and wl1271_spi modules in preparation
> of integration of the SDIO implementation.
>
> Signed-off-by: Teemu Paasikivi <[email protected]>
> Reviewed-by: Juuso Oikarinen <[email protected]>
> Signed-off-by: Juuso Oikarinen <[email protected]>

Which one is it, Reviewed or SOB? If both then just use SOB.

Luis

2010-02-22 06:41:28

by Juuso Oikarinen

[permalink] [raw]
Subject: [PATCH 09/22] wl1271: Fixed unloading of the wl1271_sdio module

From: Teemu Paasikivi <[email protected]>

Fixed two bugs causing problems when unloding wl1271 module. First was
missing sdio_set_drvdata call from the probe function, second was order
of function calls in the remove function.

Signed-off-by: Teemu Paasikivi <[email protected]>
Reviewed-by: Juuso Oikarinen <[email protected]>
Signed-off-by: Juuso Oikarinen <[email protected]>
---
drivers/net/wireless/wl12xx/wl1271_sdio.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
index be5c149..7d7c850 100644
--- a/drivers/net/wireless/wl12xx/wl1271_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -219,6 +219,8 @@ static int __devinit wl1271_probe(struct sdio_func *func,
goto out_irq;

sdio_claim_host(func);
+ sdio_set_drvdata(func, wl);
+
ret = sdio_enable_func(func);
if (ret)
goto out_release;
@@ -246,10 +248,11 @@ static void __devexit wl1271_remove(struct sdio_func *func)
{
struct wl1271 *wl = sdio_get_drvdata(func);

+ ieee80211_unregister_hw(wl->hw);
+
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
- ieee80211_unregister_hw(wl->hw);

free_irq(wl->irq, wl);

--
1.6.3.3


2010-02-22 18:57:54

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [PATCH 06/22] wl1271: Divided driver to two separate modules

On Mon, Feb 22, 2010 at 10:42 AM, Johannes Berg
<[email protected]> wrote:
> On Mon, 2010-02-22 at 10:05 -0800, Luis R. Rodriguez wrote:
>> On Sun, Feb 21, 2010 at 10:38 PM, Juuso Oikarinen
>> <[email protected]> wrote:
>> > From: Teemu Paasikivi <[email protected]>
>> >
>> > Divided wl1271 driver to wl1271 "core" and wl1271_spi modules in
>> preparation
>> > of integration of the SDIO implementation.
>> >
>> > Signed-off-by: Teemu Paasikivi <[email protected]>
>> > Reviewed-by: Juuso Oikarinen <[email protected]>
>> > Signed-off-by: Juuso Oikarinen <[email protected]>
>>
>> Which one is it, Reviewed or SOB? If both then just use SOB.
>
> I disagree. I think we should allow for people just sending on patches
> (say as part of a company hierarchy) w/o giving them the careful review
> the reviewed-by tag should imply.

Technically I think that's right then, since the "Developer's
Certificate of Origin 1.1" does indeed not make mention to a technical
anal review of the code, which for some reason I thought did.

Luis

2010-03-09 20:46:00

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 20/22] wl1271: Clean up TX security sequence number handling

Juuso Oikarinen <[email protected]> writes:

> Instead of managing the TX security sequence number as two variables, use
> one 64 bit variable. This greatly simplifies the handling of the number.

[...]

> - u16 tx_security_seq_16;
> - u32 tx_security_seq_32;
> + s64 tx_security_seq;

I'm curious, why s64 and not u64? I'm sure there's a good reason, I
just wasn't able figure it out.

--
Kalle Valo

2010-03-10 05:50:21

by Juuso Oikarinen

[permalink] [raw]
Subject: Re: [PATCH 20/22] wl1271: Clean up TX security sequence number handling

On Tue, 2010-03-09 at 21:45 +0100, ext Kalle Valo wrote:
> Juuso Oikarinen <[email protected]> writes:
>
> > Instead of managing the TX security sequence number as two variables, use
> > one 64 bit variable. This greatly simplifies the handling of the number.
>
> [...]
>
> > - u16 tx_security_seq_16;
> > - u32 tx_security_seq_32;
> > + s64 tx_security_seq;
>
> I'm curious, why s64 and not u64? I'm sure there's a good reason, I
> just wasn't able figure it out.
>

Hi, good question. I don't remember the reasoning either.

Good news is that we only need the first 48 bits, so it shouldn't matter
so much.

-Juuso