The following series of patches adds an sdio driver to libertas_tf for the
support of the sd8686 thin firmware for OLPC. This driver and firmware are
used by OLPC's XO-1.5 and some Gumstix platforms.
The firmware can be pulled from OLPC's site:
http://dev.laptop.org/pub/firmware/libertas/thinfirm/lbtf_sdio-9.0.7.p3.bin
Full project documentation is on OLPC's wiki:
http://wiki.laptop.org/go/Thinfirm_1.5
Further patches will follow this series with various fixes given to me by
the community, fixes to the libertas_tf_usb driver, and fixes for mesh.
These have been tested on OLPC's XO-1.5 with the thin firmware.
- Steve
[PATCH 1/9] libertas_tf: Add a sdio driver to libertas_tf
[PATCH 2/9] libertas_tf: deb_defs.h: Fix include guard
[PATCH 3/9] libertas_tf: Added fullmac mode support so firmware supports libertas driver
[PATCH 4/9] libertas_tf: Add firmware reset to sdio driver and attempt firmware reload
[PATCH 5/9] libertas_tf: Moved firmware loading to probe in order to fetch MAC address
[PATCH 6/9] libertas_tf: Fix to enable interrupts even when firmware has already started
[PATCH 7/9] libertas_tf: Add tx feedback to libertas_tf_sdio
[PATCH 8/9] libertas_tf: updated with beacon code
[PATCH 9/9] libertas_tf: Allow tx up to full chip buffers
mac80211 requires that the MAC address be known and set before calling
ieee80211_register_hw(). If this isn't done, we see bad MAC addresses
in our packet headers. In order to make this happen, I had to restructure
to have if_sdio_probe load the firmware and get the hardware specs.
I had to add a if_sdio_update_hw_spec function as if_sdio can't use the standard
command as several required variables aren't setup yet.
if_sdio_update_hw_spec essentially uses polled io to get the hw spec
command response from the card.
Signed-off-by: Steve deRosier <[email protected]>
---
drivers/net/wireless/libertas_tf/if_sdio.c | 263 ++++++++++++++++++++----
drivers/net/wireless/libertas_tf/libertas_tf.h | 2 +-
drivers/net/wireless/libertas_tf/main.c | 38 +++--
3 files changed, 248 insertions(+), 55 deletions(-)
diff --git a/drivers/net/wireless/libertas_tf/if_sdio.c b/drivers/net/wireless/libertas_tf/if_sdio.c
index 1e72b4c..189b820 100644
--- a/drivers/net/wireless/libertas_tf/if_sdio.c
+++ b/drivers/net/wireless/libertas_tf/if_sdio.c
@@ -91,12 +91,15 @@ struct if_sdio_card {
struct workqueue_struct *workqueue;
struct work_struct packet_worker;
+ u8 hw_addr[ETH_ALEN];
+ u32 fwrelease;
+ u32 fwcapinfo;
+
u8 rx_unit;
};
-static int if_sdio_enable_interrupts(struct lbtf_private *priv)
+static int _if_sdio_enable_interrupts(struct if_sdio_card *card)
{
- struct if_sdio_card *card = priv->card;
int ret;
lbtf_deb_enter(LBTF_DEB_SDIO);
@@ -109,9 +112,14 @@ static int if_sdio_enable_interrupts(struct lbtf_private *priv)
return (ret);
}
-static int if_sdio_disable_interrupts(struct lbtf_private *priv)
+static int if_sdio_enable_interrupts(struct lbtf_private *priv)
{
struct if_sdio_card *card = priv->card;
+ return _if_sdio_enable_interrupts(card);
+}
+
+static int _if_sdio_disable_interrupts(struct if_sdio_card *card)
+{
int ret;
lbtf_deb_enter(LBTF_DEB_SDIO);
@@ -124,6 +132,12 @@ static int if_sdio_disable_interrupts(struct lbtf_private *priv)
return (ret);
}
+static int if_sdio_disable_interrupts(struct lbtf_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ return _if_sdio_disable_interrupts(card);
+}
+
/*
* For SD8385/SD8686, this function reads firmware status after
* the image is downloaded, or reads RX packet length when
@@ -187,7 +201,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
struct lbtf_private *priv = card->priv;
int ret;
unsigned long flags;
- u8 i;
lbtf_deb_enter(LBTF_DEB_SDIO);
@@ -414,10 +427,14 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
break;
// Check for removed device
- if (card->priv->surpriseremoved) {
- lbtf_deb_sdio("Device removed\n");
- kfree(packet);
- break;
+ if (card->priv) {
+ if (card->priv->surpriseremoved) {
+ lbtf_deb_sdio("Device removed\n");
+ kfree(packet);
+ break;
+ }
+ } else {
+ lbtf_deb_sdio("host->card called during init, assuming device exists");
}
sdio_claim_host(card->func);
@@ -687,7 +704,7 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
/*
* Disable interrupts
*/
- ret = if_sdio_disable_interrupts(card->priv);
+ ret = _if_sdio_disable_interrupts(card);
if (ret)
pr_warning("unable to disable interrupts: %d", ret);
@@ -709,7 +726,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
if( lbtf_reset_fw == 0 ) {
goto success;
} else {
- int i = 0;
lbtf_deb_sdio("attempting to reset and reload firmware\n");
if_sdio_reset_device(card);
@@ -733,15 +749,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
lbtf_deb_sdio("Firmware loaded\n");
success:
- /*
- * Enable interrupts now that everything is set up
- */
- ret = if_sdio_enable_interrupts(card->priv);
- if (ret) {
- pr_err("Error enabling interrupts: %d", ret);
- goto out;
- }
-
sdio_claim_host(card->func);
sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
sdio_release_host(card->func);
@@ -756,19 +763,16 @@ out:
/* Libertas callbacks */
/*******************************************************************/
-static int if_sdio_host_to_card(struct lbtf_private *priv,
+static int _if_sdio_host_to_card(struct if_sdio_card *card,
u8 type, u8 *buf, u16 nb)
{
int ret;
- struct if_sdio_card *card;
struct if_sdio_packet *packet, *cur;
u16 size;
unsigned long flags;
lbtf_deb_enter_args(LBTF_DEB_SDIO, "type %d, bytes %d", type, nb);
- card = priv->card;
-
if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
ret = -EINVAL;
goto out;
@@ -812,6 +816,27 @@ static int if_sdio_host_to_card(struct lbtf_private *priv,
cur->next = packet;
}
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ queue_work(card->workqueue, &card->packet_worker);
+
+ ret = 0;
+
+out:
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_host_to_card(struct lbtf_private *priv,
+ u8 type, u8 *buf, u16 nb)
+{
+ struct if_sdio_card *card;
+ unsigned long flags;
+
+ card = priv->card;
+
+ spin_lock_irqsave(&card->lock, flags);
/* TODO: the dndl_sent has to do with sleep stuff.
* Commented out till we add that.
*/
@@ -825,17 +850,9 @@ static int if_sdio_host_to_card(struct lbtf_private *priv,
default:
lbtf_deb_sdio("unknown packet type %d\n", (int)type);
}
-
spin_unlock_irqrestore(&card->lock, flags);
- queue_work(card->workqueue, &card->packet_worker);
-
- ret = 0;
-
-out:
- lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
-
- return ret;
+ return _if_sdio_host_to_card(card, type, buf, nb);
}
static int if_sdio_enter_deep_sleep(struct lbtf_private *priv)
@@ -846,7 +863,6 @@ static int if_sdio_enter_deep_sleep(struct lbtf_private *priv)
static int if_sdio_exit_deep_sleep(struct lbtf_private *priv)
{
- struct if_sdio_card *card = priv->card;
int ret = -1;
lbtf_deb_enter(LBTF_DEB_SDIO);
@@ -857,14 +873,12 @@ static int if_sdio_exit_deep_sleep(struct lbtf_private *priv)
static int if_sdio_reset_deep_sleep_wakeup(struct lbtf_private *priv)
{
- struct if_sdio_card *card = priv->card;
int ret = -1;
lbtf_deb_enter(LBTF_DEB_SDIO);
lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
return ret;
-
}
static void if_sdio_reset_device(struct if_sdio_card *card)
@@ -878,7 +892,7 @@ static void if_sdio_reset_device(struct if_sdio_card *card)
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_HALT);
- if_sdio_host_to_card(card->priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
+ _if_sdio_host_to_card(card, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
msleep(1000);
@@ -888,6 +902,157 @@ static void if_sdio_reset_device(struct if_sdio_card *card)
}
EXPORT_SYMBOL_GPL(if_sdio_reset_device);
+/**
+ * lbtf_update_hw_spec: Updates the hardware details.
+ *
+ * @priv A pointer to struct lbtf_private structure
+ *
+ * Returns: 0 on success, error on failure
+ */
+int if_sdio_update_hw_spec(struct if_sdio_card *card)
+{
+ struct cmd_ds_get_hw_spec cmd;
+ int ret = -1;
+ unsigned long timeout;
+ u16 size, type, chunk;
+ int wait_cmd_done = 0;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ /* Send hw spec command */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.hdr.command = cpu_to_le16(CMD_GET_HW_SPEC);
+ memcpy(cmd.permanentaddr, card->hw_addr, ETH_ALEN);
+ ret = _if_sdio_host_to_card(card, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
+ if (ret) {
+ goto out;
+ }
+
+ /* Wait for and retrieve response */
+ timeout = jiffies + HZ;
+ while (wait_cmd_done < 1) {
+ /* Wait for response to cmd */
+ sdio_claim_host(card->func);
+ ret = if_sdio_wait_status(card, IF_SDIO_UL_RDY);
+ sdio_release_host(card->func);
+ if (ret) {
+ /* time-out */
+ lbtf_deb_sdio("error waiting on IO ready");
+ goto out;
+ }
+
+ /* get the rx size */
+ sdio_claim_host(card->func);
+ size = if_sdio_read_rx_len(card, &ret);
+ sdio_release_host(card->func);
+ if (ret)
+ goto out;
+
+ if (size == 0) {
+ } else if (size < 4) {
+ lbtf_deb_sdio("invalid packet size (%d bytes) from firmware\n",
+ (int)size);
+ ret = -EINVAL;
+ goto out;
+ } else /* size > 4 */ {
+ /*
+ * Get command response.
+ *
+ * The transfer must be in one transaction or the firmware
+ * goes suicidal. There's no way to guarantee that for all
+ * controllers, but we can at least try.
+ */
+ sdio_claim_host(card->func);
+ chunk = sdio_align_size(card->func, size);
+
+ ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
+ sdio_release_host(card->func);
+ if (ret)
+ goto out;
+
+ chunk = card->buffer[0] | (card->buffer[1] << 8);
+ type = card->buffer[2] | (card->buffer[3] << 8);
+
+ lbtf_deb_sdio("packet of type %d and size %d bytes\n",
+ (int)type, (int)chunk);
+
+ lbtf_deb_hex(LBTF_DEB_SDIO, "SDIO Rx: ", card->buffer,
+ min_t(unsigned int, size, 100));
+
+ if (chunk > size) {
+ lbtf_deb_sdio("packet fragment (%d > %d)\n",
+ (int)chunk, (int)size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (chunk < size) {
+ lbtf_deb_sdio("packet fragment (%d < %d)\n",
+ (int)chunk, (int)size);
+ }
+
+ switch (type) {
+ case MVMS_DAT:
+ lbtf_deb_sdio("Got MVMS_DAT");
+ continue;
+ case MVMS_CMD:
+ lbtf_deb_sdio("Got MVMS_CMD");
+ memcpy(&cmd, card->buffer +4, sizeof(cmd));
+ wait_cmd_done = 1;
+ break;
+ case MVMS_EVENT:
+ lbtf_deb_sdio("Got MVMS_EVENT");
+ continue;
+ default:
+ lbtf_deb_sdio("invalid type (%d) from firmware\n",
+ (int)type);
+ ret = -EINVAL;
+ goto out;
+ }
+ } /* size > 4 */
+
+ if (!wait_cmd_done) {
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ pr_warning("Update hw spec cmd timed out\n");
+ ret = -1;
+ goto out;
+ }
+
+ msleep(10);
+ }
+ }
+
+ lbtf_deb_sdio("Got hw spec command response");
+
+ /* Process cmd return */
+ card->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
+
+ /* The firmware release is in an interesting format: the patch
+ * level is in the most significant nibble ... so fix that: */
+ card->fwrelease = le32_to_cpu(cmd.fwrelease);
+ card->fwrelease = (card->fwrelease << 8) |
+ (card->fwrelease >> 24 & 0xff);
+
+ printk(KERN_INFO "libertas_tf_sdio: %pM, fw %u.%u.%up%u, cap 0x%08x\n",
+ cmd.permanentaddr,
+ card->fwrelease >> 24 & 0xff,
+ card->fwrelease >> 16 & 0xff,
+ card->fwrelease >> 8 & 0xff,
+ card->fwrelease & 0xff,
+ card->fwcapinfo);
+ lbtf_deb_sdio("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
+ cmd.hwifversion, cmd.version);
+
+ memmove(card->hw_addr, cmd.permanentaddr, ETH_ALEN);
+
+out:
+ lbtf_deb_leave(LBTF_DEB_SDIO);
+ return ret;
+}
+
+
/*******************************************************************/
/* SDIO callbacks */
/*******************************************************************/
@@ -919,8 +1084,8 @@ static void if_sdio_interrupt(struct sdio_func *func)
* successfully received the command.
*/
if (cause & IF_SDIO_H_INT_DNLD)
- lbtf_host_to_card_done(card->priv);
-
+ if (card->priv)
+ lbtf_host_to_card_done(card->priv);
if (cause & IF_SDIO_H_INT_UPLD) {
ret = if_sdio_card_to_host(card);
@@ -1065,7 +1230,26 @@ static int if_sdio_probe(struct sdio_func *func,
func->class, func->vendor, func->device,
model, (unsigned)card->ioport);
- priv = lbtf_add_card(card, &func->dev);
+ /* Upload firmware */
+ lbtf_deb_sdio("Going to upload fw...");
+ if (if_sdio_prog_firmware(card))
+ goto reclaim;
+
+ /*
+ * We need to get the hw spec here because we must have the
+ * MAC address before we call lbtf_add_card
+ *
+ * Read priv address from HW
+ */
+ memset(card->hw_addr, 0xff, ETH_ALEN);
+ ret = if_sdio_update_hw_spec(card);
+ if (ret) {
+ ret = -1;
+ pr_err("Error fetching MAC address from hardware.");
+ goto reclaim;
+ }
+
+ priv = lbtf_add_card(card, &func->dev, card->hw_addr);
if (!priv) {
ret = -ENOMEM;
goto reclaim;
@@ -1075,7 +1259,6 @@ static int if_sdio_probe(struct sdio_func *func,
priv->card = card;
priv->hw_host_to_card = if_sdio_host_to_card;
- priv->hw_prog_firmware = if_sdio_prog_firmware;
priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
index bedb6b1..c7588fd 100644
--- a/drivers/net/wireless/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -498,7 +498,7 @@ void lbtf_cmd_response_rx(struct lbtf_private *priv);
/* main.c */
struct chan_freq_power *lbtf_get_region_cfp_table(u8 region,
int *cfp_no);
-struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev);
+struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev, u8 mac_addr[ETH_ALEN]);
int lbtf_remove_card(struct lbtf_private *priv);
int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb);
void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail);
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 119d625..14ce1bc 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -150,14 +150,15 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
int ret = -1;
lbtf_deb_enter(LBTF_DEB_FW);
+
/*
* Read priv address from HW
*/
memset(priv->current_addr, 0xff, ETH_ALEN);
ret = lbtf_update_hw_spec(priv);
if (ret) {
- ret = -1;
- goto done;
+ ret = -1;
+ goto done;
}
lbtf_set_mac_control(priv);
@@ -165,6 +166,7 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
lbtf_set_mode(priv, LBTF_PASSIVE_MODE);
ret = 0;
+
done:
lbtf_deb_leave_args(LBTF_DEB_FW, "ret: %d", ret);
return ret;
@@ -325,18 +327,20 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
lbtf_deb_enter(LBTF_DEB_MACOPS);
- if (!priv->fw_ready) {
- lbtf_deb_main("Going to upload fw...");
- /* Upload firmware */
- if (priv->hw_prog_firmware(card))
- goto err_prog_firmware;
- else
- priv->fw_ready = 1;
- } else {
- if (priv->enable_interrupts) {
- priv->enable_interrupts(priv);
+ if (priv->hw_prog_firmware) {
+ if (!priv->fw_ready) {
+ lbtf_deb_main("Going to upload fw...");
+ /* Upload firmware */
+ if (priv->hw_prog_firmware(card))
+ goto err_prog_firmware;
+ else
+ priv->fw_ready = 1;
+ } else {
+ if (priv->enable_interrupts) {
+ priv->enable_interrupts(priv);
+ }
+ lbtf_deb_main("FW was already ready...");
}
- lbtf_deb_main("FW was already ready...");
}
/* poke the firmware */
@@ -433,6 +437,7 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
lbtf_set_mac_address(priv, (u8 *) vif->addr);
}
+
lbtf_deb_leave(LBTF_DEB_MACOPS);
return 0;
}
@@ -663,7 +668,7 @@ EXPORT_SYMBOL_GPL(lbtf_rx);
*
* Returns: pointer to struct lbtf_priv.
*/
-struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
+struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev, u8 mac_addr[ETH_ALEN])
{
struct ieee80211_hw *hw;
struct lbtf_private *priv = NULL;
@@ -701,6 +706,11 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
INIT_WORK(&priv->cmd_work, lbtf_cmd_work);
INIT_WORK(&priv->tx_work, lbtf_tx_work);
+
+ printk(KERN_INFO "libertas_tf: Marvell WLAN 802.11 thinfirm adapter\n");
+
+ SET_IEEE80211_PERM_ADDR(hw, mac_addr);
+
if (ieee80211_register_hw(hw))
goto err_init_adapter;
--
1.7.0
On Wed, 8 Sep 2010 16:25:25 -0700, Steve deRosier <[email protected]>
wrote:
> mac80211 requires that the MAC address be known and set before calling
> ieee80211_register_hw(). If this isn't done, we see bad MAC addresses
> in our packet headers. In order to make this happen, I had to
restructure
> to have if_sdio_probe load the firmware and get the hardware specs.
>
> I had to add a if_sdio_update_hw_spec function as if_sdio can't use the
> standard
> command as several required variables aren't setup yet.
> if_sdio_update_hw_spec essentially uses polled io to get the hw spec
> command response from the card.
You should probably keep this for development purposes, but it will break
if your code is built into the kernel. The working model we've adopted to
solve this is to use request_firmware_nowait() in probe, and then only
continue doing work when the firmware loading returns (and then register
with mac80211 etc)
johannes
On Wed, Sep 8, 2010 at 7:16 PM, Julian Calaby <[email protected]> wrote:
> More nits:
>
> On Thu, Sep 9, 2010 at 09:25, Steve deRosier <[email protected]> wrote:
>> This patch adds tx-feedback to libertas_tf_sdio so that mac80211 rate
>> adaptation and other bookkeeping tasks function properly.
>>
>> Signed-off-by: Steve deRosier <[email protected]>
>> ---
>> ?drivers/net/wireless/libertas_tf/deb_defs.h | ? ?5 ++
>> ?drivers/net/wireless/libertas_tf/if_sdio.c ?| ? 42 +++++++++++------
>> ?drivers/net/wireless/libertas_tf/main.c ? ? | ? 65 ++++++++++++++++----------
>> ?3 files changed, 72 insertions(+), 40 deletions(-)
>>
>> diff --git a/drivers/net/wireless/libertas_tf/deb_defs.h b/drivers/net/wireless/libertas_tf/deb_defs.h
>> index 99a7478..8e86e11 100644
>> --- a/drivers/net/wireless/libertas_tf/deb_defs.h
>> +++ b/drivers/net/wireless/libertas_tf/deb_defs.h
>> @@ -1063,25 +1077,23 @@ static void if_sdio_interrupt(struct sdio_func *func)
>> ? ? ? ?if (ret)
>> ? ? ? ? ? ? ? ?goto out;
>>
>> -// ? ? lbtf_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
>> -
>> ? ? ? ?sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
>> ? ? ? ?if (ret)
>> ? ? ? ? ? ? ? ?goto out;
>
> Shouldn't this have been removed instead of being commented in the
> patch that commented it?
>
Until this time I was using this line intermittently. I frequently
uncommented it in order to see some debugging info. But as it is in
an interrupt, it creates a lot of noise that I usually didn't want to
see. Once I was past a certain point (here) and didn't need it
anymore, it got deleted.
I could have rolled all the patches into one single patch that was
nice and neat with a blue bow, but then you wouldn't have seen all the
fun I had and you would have missed out. :)
Thanks,
- Steve
On Thu, Sep 9, 2010 at 15:53, Steve deRosier <[email protected]> wrote:
> On Wed, Sep 8, 2010 at 7:21 PM, Julian Calaby <[email protected]> wrote:
>> Also, it appears that this patch does two things, update the beacon
>> code and add some debugging. You may want to separate this into two
>> patches.
>
> Well, the debugging was added _for_ the beacon code and to debug the
> beacon code either here in the driver or the interaction with new
> beacon code in the firmware.
You should probably mention that in the commit message then.
libertas_tf: Update beacon code
Update beacon code and add beacon debugging info.
Thanks,
--
Julian Calaby
Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/
On Thu, Sep 9, 2010 at 15:49, Steve deRosier <[email protected]> wrote:
> On Wed, Sep 8, 2010 at 7:06 PM, Julian Calaby <[email protected]> wrote:
>> More nits:
>>
>>
>> Are these changes really necessary here? - It'd probably be cleaner to
>> change the initial functions to just take the card struct instead? (as
>> it's always available as priv->card)
>>
>> I'm guessing you're going to do something with the _* versions of
>> these functions later, so should this change be there instead?
>>
>
> Yes, these changes are necessary. ?The enable and disable interrupt
> calls are called both from main.c as well as sdio.c. ?main.c has
> access to and needs to call with a priv, while at least one of the
> calls from sdio.c happens before priv exists. ?I could have changed
> the stuff in main.c to call with priv->card, but alas at the time I
> was still trying to minimize structural changes main.c and avoiding
> changes to the USB driver.
I'm no maintainer, but my opinion is that it's better to make
(sensible) sweeping changes to a code base, then add the changes you
want to make, rather than adding extra functions to access a
particular piece of functionality in different ways.
>>> @@ -187,7 +201,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
>>> ? ? ? ?struct lbtf_private *priv = card->priv;
>>> ? ? ? ?int ret;
>>> ? ? ? ?unsigned long flags;
>>> - ? ? ? u8 i;
>>>
>>> ? ? ? ?lbtf_deb_enter(LBTF_DEB_SDIO);
>>>
>>
>> Shouldn't this be elsewhere (maybe rolled into patch #1?)
>>
>
> It could be, but I didn't do this cleanup till now, some 20 commits
> later. ?Not that easy to pick and choose which lines from an atomic
> commit go to which patch some weeks later.
I know it isn't - I'm doing exactly that for a project I'm working on,
and my MO is to split out such changes, then roll them into more
appropriate patches later. (e.g. if I'm making the foo() function do
bar work, and, in the process of doing this, fix a whole stack of
stupid code in it, I'll commit the latter first, then the former, then
roll the changes into more appropriate patches - even if that means
more work for me. - But then I am pedantic about that.) These changes
are, in a way, why I've run my particular fine tooth comb over your
patches - I'm bored =)
>>> diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
>>> index 119d625..14ce1bc 100644
>>> --- a/drivers/net/wireless/libertas_tf/main.c
>>> +++ b/drivers/net/wireless/libertas_tf/main.c
>>> @@ -150,14 +150,15 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
>>> ? ? ? ?int ret = -1;
>>>
>>> ? ? ? ?lbtf_deb_enter(LBTF_DEB_FW);
>>> +
>>> ? ? ? ?/*
>>> ? ? ? ? * Read priv address from HW
>>> ? ? ? ? */
>>> ? ? ? ?memset(priv->current_addr, 0xff, ETH_ALEN);
>>> ? ? ? ?ret = lbtf_update_hw_spec(priv);
>>> ? ? ? ?if (ret) {
>>> - ? ? ? ? ? ? ? ret = -1;
>>> - ? ? ? ? ? ? ? goto done;
>>> + ? ? ? ? ? ? ? ? ?ret = -1;
>>> + ? ? ? ? ? ? ? ? ?goto done;
>>> ? ? ? ?}
>>>
>>> ? ? ? ?lbtf_set_mac_control(priv);
>>
>> Whitespace change noise.
>
> Well, perhaps. ?On the other hand, it made it more readable to me (the
> first one, the newline. ?The indentation change is actually incorrect,
> no doubt about it). ?Have you ever worked with a codebase for 3 some
> months and not incidentally or accidentally changed some whitespace?
> If this patch was just to change whitespace, then I'd agree with you
> and wouldn't have wasted time bothering to submit it, but the patch as
> a whole adds necessary functionality.
Yes, I have. (and it was over 3 years in my case)
>From what I understand, it's expected that white space changes and
other trivial cleanups get their own patches, mainly so that it's
easier to review separate patches. E.g. If I change the parameters
passed to bar(), and in the process lean up the whitespace in one of
the functions that calls it, those extra changes, whilst not that
significant, can make the patch harder to read. Some of the SCSI
maintainers get particularly pedantic about this, (with occasional
discussions on whether a piece of whitespace should or should not be
changed) but I expect the wireless folks are a little more relaxed. =)
I'm not meaning to lean on you over all of this, just running my eyes
over these patches.
Thanks,
--
Julian Calaby
Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/
Signed-off-by: Steve deRosier <[email protected]>
---
drivers/net/wireless/libertas_tf/libertas_tf.h | 1 +
drivers/net/wireless/libertas_tf/main.c | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
index 078c52e..bedb6b1 100644
--- a/drivers/net/wireless/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -80,6 +80,7 @@ enum lbtf_mode {
LBTF_PASSIVE_MODE,
LBTF_STA_MODE,
LBTF_AP_MODE,
+ LBTF_FULLMAC_MODE,
};
/** Card Event definition */
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 90ef6c7..5d34ad9 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -158,6 +158,7 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
lbtf_set_mac_control(priv);
lbtf_set_radio_control(priv);
+ lbtf_set_mode(priv, LBTF_PASSIVE_MODE);
ret = 0;
done:
--
1.7.0
This patch adds support for sdio-connected libertas chips with the
thin-firmware to libertas_tf. This includes the sd8686 in the OLPC XO-1.5s,
as well as some Gumstix platforms. Restructuring was necessary in libertas_tf
that will break libertas_tf_usb, which is fixed in a subsequent patch.
Signed-off-by: Steve deRosier <[email protected]>
---
drivers/net/wireless/Kconfig | 6 +
drivers/net/wireless/libertas_tf/Makefile | 2 +
drivers/net/wireless/libertas_tf/cmd.c | 10 +-
drivers/net/wireless/libertas_tf/deb_defs.h | 5 +-
drivers/net/wireless/libertas_tf/if_sdio.c | 1201 ++++++++++++++++++++++++
drivers/net/wireless/libertas_tf/if_sdio.h | 56 ++
drivers/net/wireless/libertas_tf/libertas_tf.h | 19 +-
drivers/net/wireless/libertas_tf/main.c | 100 ++-
8 files changed, 1379 insertions(+), 20 deletions(-)
create mode 100644 drivers/net/wireless/libertas_tf/if_sdio.c
create mode 100644 drivers/net/wireless/libertas_tf/if_sdio.h
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 174e344..fc6c713 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -45,6 +45,12 @@ config LIBERTAS_THINFIRM_DEBUG
---help---
Debugging support.
+config LIBERTAS_THINFIRM_SDIO
+ tristate "Marvell Libertas 8686 SDIO 802.11b/g cards"
+ depends on LIBERTAS_THINFIRM && MMC
+ ---help---
+ A driver for Marvell Libertas 8686 SDIO devices.
+
config LIBERTAS_THINFIRM_USB
tristate "Marvell Libertas 8388 USB 802.11b/g cards with thin firmware"
depends on LIBERTAS_THINFIRM && USB
diff --git a/drivers/net/wireless/libertas_tf/Makefile b/drivers/net/wireless/libertas_tf/Makefile
index ff5544d..1a44340 100644
--- a/drivers/net/wireless/libertas_tf/Makefile
+++ b/drivers/net/wireless/libertas_tf/Makefile
@@ -1,6 +1,8 @@
libertas_tf-objs := main.o cmd.o
libertas_tf_usb-objs += if_usb.o
+libertas_tf_sdio-objs += if_sdio.o
obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf.o
obj-$(CONFIG_LIBERTAS_THINFIRM_USB) += libertas_tf_usb.o
+obj-$(CONFIG_LIBERTAS_THINFIRM_SDIO) += libertas_tf_sdio.o
diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c
index 8945afd..738a2ff 100644
--- a/drivers/net/wireless/libertas_tf/cmd.c
+++ b/drivers/net/wireless/libertas_tf/cmd.c
@@ -101,7 +101,7 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
priv->fwrelease = (priv->fwrelease << 8) |
(priv->fwrelease >> 24 & 0xff);
- printk(KERN_INFO "libertastf: %pM, fw %u.%u.%up%u, cap 0x%08x\n",
+ printk(KERN_INFO "libertas_tf: %pM, fw %u.%u.%up%u, cap 0x%08x\n",
cmd.permanentaddr,
priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff,
@@ -252,7 +252,7 @@ static void lbtf_submit_command(struct lbtf_private *priv,
lbtf_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
command, le16_to_cpu(cmd->seqnum), cmdsize);
- lbtf_deb_hex(LBTF_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
+ lbtf_deb_hex(LBTF_DEB_CMD, "DNLD_CMD ", (void *) cmdnode->cmdbuf, cmdsize);
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -672,6 +672,12 @@ int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
lbtf_deb_enter(LBTF_DEB_HOST);
+ if (priv->surpriseremoved) {
+ lbtf_deb_host("CMD: card removed\n");
+ cmdnode = ERR_PTR(-ENOENT);
+ goto done;
+ }
+
cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size,
callback, callback_arg);
if (IS_ERR(cmdnode)) {
diff --git a/drivers/net/wireless/libertas_tf/deb_defs.h b/drivers/net/wireless/libertas_tf/deb_defs.h
index ae75396..e2f009c 100644
--- a/drivers/net/wireless/libertas_tf/deb_defs.h
+++ b/drivers/net/wireless/libertas_tf/deb_defs.h
@@ -11,6 +11,9 @@
#include <linux/spinlock.h>
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#ifdef CONFIG_LIBERTAS_THINFIRM_DEBUG
#define DEBUG
#define PROC_DEBUG
@@ -82,7 +85,7 @@ do { if ((lbtf_debug & (grp)) == (grp)) \
#define lbtf_deb_usbd(dev, fmt, args...) LBTF_DEB_LL(LBTF_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args)
#define lbtf_deb_cs(fmt, args...) LBTF_DEB_LL(LBTF_DEB_CS, " cs", fmt, ##args)
#define lbtf_deb_thread(fmt, args...) LBTF_DEB_LL(LBTF_DEB_THREAD, " thread", fmt, ##args)
-#define lbtf_deb_sdio(fmt, args...) LBTF_DEB_LL(LBTF_DEB_SDIO, " thread", fmt, ##args)
+#define lbtf_deb_sdio(fmt, args...) LBTF_DEB_LL(LBTF_DEB_SDIO, " sdio", fmt, ##args)
#define lbtf_deb_macops(fmt, args...) LBTF_DEB_LL(LBTF_DEB_MACOPS, " thread", fmt, ##args)
#ifdef DEBUG
diff --git a/drivers/net/wireless/libertas_tf/if_sdio.c b/drivers/net/wireless/libertas_tf/if_sdio.c
new file mode 100644
index 0000000..fed5aff
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/if_sdio.c
@@ -0,0 +1,1201 @@
+/*
+ * linux/drivers/net/wireless/libertas_tf/if_sdio.c
+ *
+ * Copyright (C) 2010, cozybit Inc.
+ *
+ * Portions Copyright 2007-2008 Pierre Ossman
+ * Inspired by if_cs.c, Copyright 2007 Holger Schurig
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/host.h>
+
+#define DRV_NAME "lbtf_sdio"
+
+#include "deb_defs.h"
+#include "libertas_tf.h"
+#include "if_sdio.h"
+
+static char *lbtf_helper_name = NULL;
+module_param_named(helper_name, lbtf_helper_name, charp, 0644);
+
+static char *lbtf_fw_name = NULL;
+module_param_named(fw_name, lbtf_fw_name, charp, 0644);
+
+static const struct sdio_device_id if_sdio_ids[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
+ SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
+ SDIO_DEVICE_ID_MARVELL_8688WLAN) },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
+
+struct if_sdio_model {
+ int model;
+ const char *helper;
+ const char *firmware;
+};
+
+static struct if_sdio_model if_sdio_models[] = {
+ {
+ /* 8686 */
+ .model = IF_SDIO_MODEL_8686,
+ .helper = "sd8686_helper.bin",
+ .firmware = "sd8686tf.bin",
+ },
+};
+MODULE_FIRMWARE("sd8686_helper.bin");
+MODULE_FIRMWARE("sd8686tf.bin");
+
+struct if_sdio_packet {
+ struct if_sdio_packet *next;
+ u16 nb;
+ u8 buffer[0] __attribute__((aligned(4)));
+};
+
+struct if_sdio_card {
+ struct sdio_func *func;
+ struct lbtf_private *priv;
+
+ int model;
+ unsigned long ioport;
+ unsigned int scratch_reg;
+
+ const char *helper;
+ const char *firmware;
+
+ u8 buffer[65536];
+
+ spinlock_t lock;
+ struct if_sdio_packet *packets;
+
+ struct workqueue_struct *workqueue;
+ struct work_struct packet_worker;
+
+ u8 rx_unit;
+};
+
+static int if_sdio_enable_interrupts(struct lbtf_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
+ sdio_release_host(card->func);
+
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+ return (ret);
+}
+
+static int if_sdio_disable_interrupts(struct lbtf_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, 0x00, IF_SDIO_H_INT_MASK, &ret);
+ sdio_release_host(card->func);
+
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+ return (ret);
+}
+
+/*
+ * For SD8385/SD8686, this function reads firmware status after
+ * the image is downloaded, or reads RX packet length when
+ * interrupt (with IF_SDIO_H_INT_UPLD bit set) is received.
+ */
+static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
+{
+ int ret;
+ u16 scratch;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ scratch = sdio_readb(card->func, card->scratch_reg, &ret);
+ if (!ret)
+ scratch |= sdio_readb(card->func, card->scratch_reg + 1,
+ &ret) << 8;
+
+ if (err)
+ *err = ret;
+
+ if (ret)
+ return 0xffff;
+
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "scratch %x", scratch);
+ return scratch;
+}
+
+/********************************************************************/
+/* I/O */
+/********************************************************************/
+static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err)
+{
+ int ret;
+ u16 rx_len;
+
+ switch (card->model) {
+ case IF_SDIO_MODEL_8385:
+ case IF_SDIO_MODEL_8686:
+ rx_len = if_sdio_read_scratch(card, &ret);
+ break;
+ case IF_SDIO_MODEL_8688:
+ default: /* for newer chipsets */
+ rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret);
+ if (!ret)
+ rx_len <<= card->rx_unit;
+ else
+ rx_len = 0xffff; /* invalid length */
+
+ break;
+ }
+
+ if (err)
+ *err = ret;
+
+ return rx_len;
+}
+
+static int if_sdio_handle_cmd(struct if_sdio_card *card,
+ u8 *buffer, unsigned size)
+{
+ struct lbtf_private *priv = card->priv;
+ int ret;
+ unsigned long flags;
+ u8 i;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ if (size > LBS_CMD_BUFFER_SIZE) {
+ lbtf_deb_sdio("response packet too large (%d bytes)\n",
+ (int)size);
+ ret = -E2BIG;
+ goto out;
+ }
+
+ spin_lock_irqsave(&priv->driver_lock, flags);
+
+ memcpy(priv->cmd_resp_buff, buffer, size);
+ lbtf_cmd_response_rx(priv);
+
+ spin_unlock_irqrestore(&card->priv->driver_lock, flags);
+
+ ret = 0;
+
+out:
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+ return ret;
+}
+
+static int if_sdio_handle_data(struct if_sdio_card *card,
+ u8 *buffer, unsigned size)
+{
+ int ret;
+ struct sk_buff *skb;
+ char *data;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
+ lbtf_deb_sdio("response packet too large (%d bytes)\n",
+ (int)size);
+ ret = -E2BIG;
+ goto out;
+ }
+
+ skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + NET_IP_ALIGN);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ data = skb_put(skb, size);
+
+ memcpy(data, buffer, size);
+
+ lbtf_rx(card->priv, skb);
+
+ ret = 0;
+
+out:
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_handle_event(struct if_sdio_card *card,
+ u8 *buffer, unsigned size)
+{
+ int ret = 0;
+ u32 event;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ if (card->model == IF_SDIO_MODEL_8385) {
+ event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
+ if (ret)
+ goto out;
+
+ /* right shift 3 bits to get the event id */
+ event >>= 3;
+ } else {
+ if (size < 4) {
+ lbtf_deb_sdio("event packet too small (%d bytes)\n",
+ (int)size);
+ ret = -EINVAL;
+ goto out;
+ }
+ event = buffer[3] << 24;
+ event |= buffer[2] << 16;
+ event |= buffer[1] << 8;
+ event |= buffer[0] << 0;
+ }
+
+ lbtf_deb_sdio("**EVENT** 0x%X\n", event);
+ ret = 0;
+
+out:
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_wait_status(struct if_sdio_card *card, const u8 condition)
+{
+ u8 status;
+ unsigned long timeout;
+ int ret = 0;
+
+ timeout = jiffies + HZ;
+ while (1) {
+ status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
+ if (ret)
+ return ret;
+ if ((status & condition) == condition)
+ break;
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ mdelay(1);
+ }
+
+ return ret;
+}
+
+static int if_sdio_card_to_host(struct if_sdio_card *card)
+{
+ int ret;
+ u16 size, type, chunk;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+
+ size = if_sdio_read_rx_len(card, &ret);
+ if (ret)
+ goto out;
+
+ if (size < 4) {
+ lbtf_deb_sdio("invalid packet size (%d bytes) from firmware\n",
+ (int)size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
+ if (ret)
+ goto out;
+
+ /*
+ * The transfer must be in one transaction or the firmware
+ * goes suicidal. There's no way to guarantee that for all
+ * controllers, but we can at least try.
+ */
+ chunk = sdio_align_size(card->func, size);
+
+ ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
+ if (ret)
+ goto out;
+
+ chunk = card->buffer[0] | (card->buffer[1] << 8);
+ type = card->buffer[2] | (card->buffer[3] << 8);
+
+ lbtf_deb_sdio("packet of type %d and size %d bytes\n",
+ (int)type, (int)chunk);
+
+ if (chunk > size) {
+ lbtf_deb_sdio("packet fragment (%d > %d)\n",
+ (int)chunk, (int)size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (chunk < size) {
+ lbtf_deb_sdio("packet fragment (%d < %d)\n",
+ (int)chunk, (int)size);
+ }
+
+ switch (type) {
+ case MVMS_CMD:
+ ret = if_sdio_handle_cmd(card, card->buffer + 4, chunk - 4);
+ if (ret)
+ goto out;
+ break;
+ case MVMS_DAT:
+ ret = if_sdio_handle_data(card, card->buffer + 4, chunk - 4);
+ if (ret)
+ goto out;
+ break;
+ case MVMS_EVENT:
+ ret = if_sdio_handle_event(card, card->buffer + 4, chunk - 4);
+ if (ret)
+ goto out;
+ break;
+ default:
+ lbtf_deb_sdio("invalid type (%d) from firmware\n",
+ (int)type);
+ ret = -EINVAL;
+ goto out;
+ }
+
+out:
+ if (ret)
+ pr_err("problem fetching packet from firmware\n");
+
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static void if_sdio_host_to_card_worker(struct work_struct *work)
+{
+ struct if_sdio_card *card;
+ struct if_sdio_packet *packet;
+ int ret;
+ unsigned long flags;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ card = container_of(work, struct if_sdio_card, packet_worker);
+
+ while (1) {
+ spin_lock_irqsave(&card->lock, flags);
+ packet = card->packets;
+ if (packet)
+ card->packets = packet->next;
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ if (!packet)
+ break;
+
+ // Check for removed device
+ if (card->priv->surpriseremoved) {
+ lbtf_deb_sdio("Device removed\n");
+ kfree(packet);
+ break;
+ }
+
+ sdio_claim_host(card->func);
+
+ ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
+ if (ret == 0) {
+ ret = sdio_writesb(card->func, card->ioport,
+ packet->buffer, packet->nb);
+ }
+
+ if (ret)
+ pr_err("error %d sending packet to firmware\n", ret);
+
+ sdio_release_host(card->func);
+
+ kfree(packet);
+ }
+
+ lbtf_deb_leave(LBTF_DEB_SDIO);
+}
+
+/********************************************************************/
+/* Firmware */
+/********************************************************************/
+
+#define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY)
+
+static int if_sdio_prog_helper(struct if_sdio_card *card)
+{
+ int ret;
+ const struct firmware *fw;
+ unsigned long timeout;
+ u8 *chunk_buffer;
+ u32 chunk_size;
+ const u8 *firmware;
+ size_t size;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ ret = request_firmware(&fw, card->helper, &card->func->dev);
+
+ if (ret) {
+ pr_err("failed to load helper firmware\n");
+ goto out;
+ }
+
+ chunk_buffer = kzalloc(64, GFP_KERNEL);
+ if (!chunk_buffer) {
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ sdio_claim_host(card->func);
+
+ ret = sdio_set_block_size(card->func, 32);
+ if (ret)
+ goto release;
+
+ firmware = fw->data;
+ size = fw->size;
+
+ lbtf_deb_sdio("Helper size: %d", size);
+
+ while (size) {
+ ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
+ if (ret)
+ goto release;
+
+ /* On some platforms (like Davinci) the chip needs more time
+ * between helper blocks.
+ */
+ mdelay(2);
+
+ chunk_size = min(size, (size_t)60);
+
+ *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
+ memcpy(chunk_buffer + 4, firmware, chunk_size);
+
+ // lbtf_deb_sdio("sending %d bytes chunk\n", chunk_size);
+
+ ret = sdio_writesb(card->func, card->ioport,
+ chunk_buffer, 64);
+ if (ret)
+ goto release;
+
+ firmware += chunk_size;
+ size -= chunk_size;
+ }
+
+ /* an empty block marks the end of the transfer */
+ memset(chunk_buffer, 0, 4);
+ ret = sdio_writesb(card->func, card->ioport, chunk_buffer, 64);
+ if (ret)
+ goto release;
+
+ lbtf_deb_sdio("waiting for helper to boot...\n");
+
+ /* wait for the helper to boot by looking at the size register */
+ timeout = jiffies + HZ;
+ while (1) {
+ u16 req_size;
+
+ req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
+ if (ret)
+ goto release;
+
+ req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
+ if (ret)
+ goto release;
+
+ if (req_size != 0)
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto release;
+ }
+
+ msleep(10);
+ }
+
+ ret = 0;
+
+release:
+ sdio_release_host(card->func);
+ kfree(chunk_buffer);
+release_fw:
+ release_firmware(fw);
+
+out:
+ if (ret)
+ pr_err("failed to load helper firmware\n");
+
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_prog_real(struct if_sdio_card *card)
+{
+ int ret;
+ const struct firmware *fw;
+ unsigned long timeout;
+ u8 *chunk_buffer;
+ u32 chunk_size;
+ const u8 *firmware;
+ size_t size, req_size;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ ret = request_firmware(&fw, card->firmware, &card->func->dev);
+ if (ret) {
+ pr_err("can't load firmware\n");
+ goto out;
+ }
+
+ chunk_buffer = kzalloc(512, GFP_KERNEL);
+ if (!chunk_buffer) {
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ sdio_claim_host(card->func);
+
+ ret = sdio_set_block_size(card->func, 32);
+ if (ret)
+ goto release;
+
+ firmware = fw->data;
+ size = fw->size;
+
+ lbtf_deb_sdio("Firmware size: %d", size);
+
+ while (size) {
+ ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
+ if (ret)
+ goto release;
+
+ req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
+ if (ret)
+ goto release;
+
+ req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
+ if (ret)
+ goto release;
+
+ if (req_size == 0) {
+ lbtf_deb_sdio("firmware helper gave up early\n");
+ ret = -EIO;
+ goto release;
+ }
+
+ if (req_size & 0x01) {
+ lbtf_deb_sdio("firmware helper signalled error\n");
+ ret = -EIO;
+ goto release;
+ }
+
+ if (req_size > size)
+ req_size = size;
+
+ while (req_size) {
+ chunk_size = min(req_size, (size_t)512);
+
+ memcpy(chunk_buffer, firmware, chunk_size);
+ ret = sdio_writesb(card->func, card->ioport,
+ chunk_buffer, roundup(chunk_size, 32));
+ if (ret)
+ goto release;
+
+ firmware += chunk_size;
+ size -= chunk_size;
+ req_size -= chunk_size;
+ }
+ }
+
+ ret = 0;
+
+ lbtf_deb_sdio("waiting for firmware to boot...\n");
+
+ /* wait for the firmware to boot */
+ timeout = jiffies + HZ;
+ while (1) {
+ u16 scratch;
+
+ scratch = if_sdio_read_scratch(card, &ret);
+ if (ret)
+ goto release;
+
+ if (scratch == IF_SDIO_FIRMWARE_OK)
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto release;
+ }
+
+ msleep(10);
+ }
+
+ ret = 0;
+
+release:
+ sdio_release_host(card->func);
+ kfree(chunk_buffer);
+release_fw:
+ release_firmware(fw);
+
+out:
+ if (ret)
+ pr_err("failed to load firmware\n");
+
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_prog_firmware(struct if_sdio_card *card)
+{
+ int ret;
+ u16 scratch;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ /*
+ * Disable interrupts
+ */
+ ret = if_sdio_disable_interrupts(card->priv);
+ if (ret)
+ pr_warning("unable to disable interrupts: %d", ret);
+
+ sdio_claim_host(card->func);
+ scratch = if_sdio_read_scratch(card, &ret);
+ sdio_release_host(card->func);
+
+ if (ret)
+ goto out;
+
+ lbtf_deb_sdio("firmware status = %#x\n", scratch);
+
+ if (scratch == IF_SDIO_FIRMWARE_OK) {
+ lbtf_deb_sdio("firmware already loaded\n");
+ goto success;
+ } else if ((card->model == IF_SDIO_MODEL_8686) && (scratch > 0)) {
+ lbtf_deb_sdio("firmware may be running\n");
+ goto success;
+ }
+
+ ret = if_sdio_prog_helper(card);
+ if (ret)
+ goto out;
+
+ lbtf_deb_sdio("Helper firmware loaded\n");
+
+ ret = if_sdio_prog_real(card);
+ if (ret)
+ goto out;
+
+ lbtf_deb_sdio("Firmware loaded\n");
+
+success:
+ /*
+ * Enable interrupts now that everything is set up
+ */
+ ret = if_sdio_enable_interrupts(card->priv);
+ if (ret) {
+ pr_err("Error enabling interrupts: %d", ret);
+ goto out;
+ }
+
+ sdio_claim_host(card->func);
+ sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
+ sdio_release_host(card->func);
+
+out:
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+/*******************************************************************/
+/* Libertas callbacks */
+/*******************************************************************/
+
+static int if_sdio_host_to_card(struct lbtf_private *priv,
+ u8 type, u8 *buf, u16 nb)
+{
+ int ret;
+ struct if_sdio_card *card;
+ struct if_sdio_packet *packet, *cur;
+ u16 size;
+ unsigned long flags;
+
+ lbtf_deb_enter_args(LBTF_DEB_SDIO, "type %d, bytes %d", type, nb);
+
+ card = priv->card;
+
+ if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * The transfer must be in one transaction or the firmware
+ * goes suicidal. There's no way to guarantee that for all
+ * controllers, but we can at least try.
+ */
+ size = sdio_align_size(card->func, nb + 4);
+
+ packet = kzalloc(sizeof(struct if_sdio_packet) + size,
+ GFP_ATOMIC);
+ if (!packet) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ packet->next = NULL;
+ packet->nb = size;
+
+ /*
+ * SDIO specific header.
+ */
+ packet->buffer[0] = (nb + 4) & 0xff;
+ packet->buffer[1] = ((nb + 4) >> 8) & 0xff;
+ packet->buffer[2] = type;
+ packet->buffer[3] = 0;
+
+ memcpy(packet->buffer + 4, buf, nb);
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ if (!card->packets)
+ card->packets = packet;
+ else {
+ cur = card->packets;
+ while (cur->next)
+ cur = cur->next;
+ cur->next = packet;
+ }
+
+ /* TODO: the dndl_sent has to do with sleep stuff.
+ * Commented out till we add that.
+ */
+ switch (type) {
+ case MVMS_CMD:
+ /* priv->dnld_sent = DNLD_CMD_SENT;
+ break; */
+ case MVMS_DAT:
+ /*priv->dnld_sent = DNLD_DATA_SENT;*/
+ break;
+ default:
+ lbtf_deb_sdio("unknown packet type %d\n", (int)type);
+ }
+
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ queue_work(card->workqueue, &card->packet_worker);
+
+ ret = 0;
+
+out:
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_enter_deep_sleep(struct lbtf_private *priv)
+{
+ int ret = -1;
+ return ret;
+}
+
+static int if_sdio_exit_deep_sleep(struct lbtf_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+ return ret;
+}
+
+static int if_sdio_reset_deep_sleep_wakeup(struct lbtf_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+ return ret;
+
+}
+
+static void if_sdio_reset_device(struct if_sdio_card *card)
+{
+ struct cmd_ds_802_11_reset cmd;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.command = cpu_to_le16(CMD_802_11_RESET);
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(CMD_ACT_HALT);
+
+ if_sdio_host_to_card(card->priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
+
+ msleep(100);
+
+ lbtf_deb_leave(LBTF_DEB_SDIO);
+
+ return;
+}
+EXPORT_SYMBOL_GPL(if_sdio_reset_device);
+
+/*******************************************************************/
+/* SDIO callbacks */
+/*******************************************************************/
+
+static void if_sdio_interrupt(struct sdio_func *func)
+{
+ int ret;
+ struct if_sdio_card *card;
+ u8 cause;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ card = sdio_get_drvdata(func);
+
+ cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
+ if (ret)
+ goto out;
+
+ lbtf_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
+
+ sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
+ if (ret)
+ goto out;
+
+ /*
+ * Ignore the define name, this really means the card has
+ * successfully received the command.
+ */
+ if (cause & IF_SDIO_H_INT_DNLD)
+ lbtf_host_to_card_done(card->priv);
+
+
+ if (cause & IF_SDIO_H_INT_UPLD) {
+ ret = if_sdio_card_to_host(card);
+ if (ret)
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+}
+
+static int if_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct if_sdio_card *card;
+ struct lbtf_private *priv;
+ int ret, i;
+ unsigned int model;
+ struct if_sdio_packet *packet;
+ struct mmc_host *host = func->card->host;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ for (i = 0;i < func->card->num_info;i++) {
+ if (sscanf(func->card->info[i],
+ "802.11 SDIO ID: %x", &model) == 1)
+ break;
+ if (sscanf(func->card->info[i],
+ "ID: %x", &model) == 1)
+ break;
+ if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
+ model = IF_SDIO_MODEL_8385;
+ break;
+ }
+ }
+
+ if (i == func->card->num_info) {
+ pr_err("unable to identify card model\n");
+ return -ENODEV;
+ }
+
+ lbtf_deb_sdio("Found model: 0x%x", model);
+
+ card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->func = func;
+ card->model = model;
+
+ switch (card->model) {
+ case IF_SDIO_MODEL_8385:
+ card->scratch_reg = IF_SDIO_SCRATCH_OLD;
+ break;
+ case IF_SDIO_MODEL_8686:
+ lbtf_deb_sdio("Found Marvel 8686");
+ card->scratch_reg = IF_SDIO_SCRATCH;
+ break;
+ case IF_SDIO_MODEL_8688:
+ default: /* for newer chipsets */
+ card->scratch_reg = IF_SDIO_FW_STATUS;
+ break;
+ }
+
+ spin_lock_init(&card->lock);
+ card->workqueue = create_workqueue("libertas_tf_sdio");
+ INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
+
+ for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
+ if (card->model == if_sdio_models[i].model)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(if_sdio_models)) {
+ pr_err("unknown card model 0x%x\n", card->model);
+ ret = -ENODEV;
+ goto free;
+ }
+
+ card->helper = if_sdio_models[i].helper;
+ card->firmware = if_sdio_models[i].firmware;
+
+ if (lbtf_helper_name) {
+ lbtf_deb_sdio("overriding helper firmware: %s\n",
+ lbtf_helper_name);
+ card->helper = lbtf_helper_name;
+ }
+
+ if (lbtf_fw_name) {
+ lbtf_deb_sdio("overriding firmware: %s\n", lbtf_fw_name);
+ card->firmware = lbtf_fw_name;
+ }
+
+ sdio_claim_host(func);
+
+ ret = sdio_enable_func(func);
+ if (ret)
+ goto release;
+
+ ret = sdio_claim_irq(func, if_sdio_interrupt);
+ if (ret)
+ goto disable;
+
+ /* For 1-bit transfers to the 8686 model, we need to enable the
+ * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
+ * bit to allow access to non-vendor registers. */
+ if ((card->model == IF_SDIO_MODEL_8686) &&
+ (host->caps & MMC_CAP_SDIO_IRQ) &&
+ (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
+ u8 reg;
+
+ func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+ reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
+ if (ret)
+ goto release_int;
+
+ reg |= SDIO_BUS_ECSI;
+ sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
+ if (ret)
+ goto release_int;
+ }
+
+ card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
+ if (ret)
+ goto release_int;
+
+ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
+ if (ret)
+ goto release_int;
+
+ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
+ if (ret)
+ goto release_int;
+
+ sdio_release_host(func);
+ sdio_set_drvdata(func, card);
+
+ lbtf_deb_sdio("class = 0x%X, vendor = 0x%X, "
+ "device = 0x%X, model = 0x%X, ioport = 0x%X\n",
+ func->class, func->vendor, func->device,
+ model, (unsigned)card->ioport);
+
+ priv = lbtf_add_card(card, &func->dev);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto reclaim;
+ }
+
+ card->priv = priv;
+ priv->card = card;
+
+ priv->hw_host_to_card = if_sdio_host_to_card;
+ priv->hw_prog_firmware = if_sdio_prog_firmware;
+ priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
+ priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
+ priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
+ priv->hw_reset_device = if_sdio_reset_device;
+ priv->enable_interrupts = if_sdio_enable_interrupts;
+ priv->disable_interrupts = if_sdio_disable_interrupts;
+
+ /* SD8385 & SD8686 do not have rx_unit. */
+ card->rx_unit = 0;
+
+out:
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+
+err_activate_card:
+ lbtf_deb_sdio("prob error jump: err_activate_card");
+ flush_workqueue(card->workqueue);
+ lbtf_remove_card(priv);
+reclaim:
+ lbtf_deb_sdio("prob error jump: reclaim");
+ sdio_claim_host(func);
+release_int:
+ lbtf_deb_sdio("prob error jump: release_int");
+ sdio_release_irq(func);
+disable:
+ lbtf_deb_sdio("prob error jump: disable");
+ sdio_disable_func(func);
+release:
+ lbtf_deb_sdio("prob error jump: release");
+ sdio_release_host(func);
+free:
+ lbtf_deb_sdio("prob error jump: free");
+ destroy_workqueue(card->workqueue);
+ while (card->packets) {
+ packet = card->packets;
+ card->packets = card->packets->next;
+ kfree(packet);
+ }
+
+ kfree(card);
+
+ goto out;
+}
+
+static void if_sdio_remove(struct sdio_func *func)
+{
+ struct if_sdio_card *card;
+ struct if_sdio_packet *packet;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ card = sdio_get_drvdata(func);
+
+ card->priv->surpriseremoved = 1;
+
+ lbtf_deb_sdio("call remove card\n");
+ lbtf_remove_card(card->priv);
+
+ flush_workqueue(card->workqueue);
+ destroy_workqueue(card->workqueue);
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_set_drvdata(func, NULL);
+ sdio_release_host(func);
+
+ while (card->packets) {
+ packet = card->packets;
+ card->packets = card->packets->next;
+ kfree(packet);
+ }
+
+ kfree(card);
+
+ lbtf_deb_leave(LBTF_DEB_SDIO);
+}
+
+static int if_sdio_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int if_sdio_resume(struct device *dev)
+{
+ return 0;
+}
+
+static struct dev_pm_ops if_sdio_pm_ops = {
+ .suspend = if_sdio_suspend,
+ .resume = if_sdio_resume,
+};
+
+static struct sdio_driver if_sdio_driver = {
+ .name = "libertas_tf_sdio",
+ .id_table = if_sdio_ids,
+ .probe = if_sdio_probe,
+ .remove = if_sdio_remove,
+ .drv = {
+ .pm = &if_sdio_pm_ops,
+ },
+};
+
+/*******************************************************************/
+/* Module functions */
+/*******************************************************************/
+
+static int __init if_sdio_init_module(void)
+{
+ int ret = 0;
+
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+ printk(KERN_INFO "libertas_tf_sdio: Libertas Thinfirmware SDIO driver\n");
+ printk(KERN_INFO "libertas_tf_sdio: Copyright cozybit Inc.\n");
+ printk(KERN_INFO "libertas_tf_sdio: buildstamp: 6\n");
+
+ ret = sdio_register_driver(&if_sdio_driver);
+
+ lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static void __exit if_sdio_exit_module(void)
+{
+ lbtf_deb_enter(LBTF_DEB_SDIO);
+
+
+ sdio_unregister_driver(&if_sdio_driver);
+
+ lbtf_deb_leave(LBTF_DEB_SDIO);
+}
+
+module_init(if_sdio_init_module);
+module_exit(if_sdio_exit_module);
+
+MODULE_DESCRIPTION("Libertas_tf SDIO WLAN Driver");
+MODULE_AUTHOR("Steve deRosier");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas_tf/if_sdio.h b/drivers/net/wireless/libertas_tf/if_sdio.h
new file mode 100644
index 0000000..12179c1
--- /dev/null
+++ b/drivers/net/wireless/libertas_tf/if_sdio.h
@@ -0,0 +1,56 @@
+/*
+ * linux/drivers/net/wireless/libertas/if_sdio.h
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef _LBS_IF_SDIO_H
+#define _LBS_IF_SDIO_H
+
+#define IF_SDIO_MODEL_8385 0x04
+#define IF_SDIO_MODEL_8686 0x0b
+#define IF_SDIO_MODEL_8688 0x10
+
+#define IF_SDIO_IOPORT 0x00
+
+#define IF_SDIO_H_INT_MASK 0x04
+#define IF_SDIO_H_INT_OFLOW 0x08
+#define IF_SDIO_H_INT_UFLOW 0x04
+#define IF_SDIO_H_INT_DNLD 0x02
+#define IF_SDIO_H_INT_UPLD 0x01
+
+#define IF_SDIO_H_INT_STATUS 0x05
+#define IF_SDIO_H_INT_RSR 0x06
+#define IF_SDIO_H_INT_STATUS2 0x07
+
+#define IF_SDIO_RD_BASE 0x10
+
+#define IF_SDIO_STATUS 0x20
+#define IF_SDIO_IO_RDY 0x08
+#define IF_SDIO_CIS_RDY 0x04
+#define IF_SDIO_UL_RDY 0x02
+#define IF_SDIO_DL_RDY 0x01
+
+#define IF_SDIO_C_INT_MASK 0x24
+#define IF_SDIO_C_INT_STATUS 0x28
+#define IF_SDIO_C_INT_RSR 0x2C
+
+#define IF_SDIO_SCRATCH 0x34
+#define IF_SDIO_SCRATCH_OLD 0x80fe
+#define IF_SDIO_FW_STATUS 0x40
+#define IF_SDIO_FIRMWARE_OK 0xfedc
+
+#define IF_SDIO_RX_LEN 0x42
+#define IF_SDIO_RX_UNIT 0x43
+
+#define IF_SDIO_EVENT 0x80fc
+
+#define IF_SDIO_BLOCK_SIZE 256
+#define CONFIGURATION_REG 0x03
+#define HOST_POWER_UP (0x1U << 1)
+#endif
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
index ad77b92..078c52e 100644
--- a/drivers/net/wireless/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -190,9 +190,13 @@ struct lbtf_private {
struct work_struct tx_work;
/** Hardware access */
int (*hw_host_to_card) (struct lbtf_private *priv, u8 type, u8 *payload, u16 nb);
- int (*hw_prog_firmware) (struct if_usb_card *cardp);
- int (*hw_reset_device) (struct if_usb_card *cardp);
-
+ int (*hw_prog_firmware) (void *cardp);
+ int (*hw_reset_device) (void *cardp);
+ int (*enter_deep_sleep) (struct lbtf_private *priv);
+ int (*exit_deep_sleep) (struct lbtf_private *priv);
+ int (*reset_deep_sleep_wakeup) (struct lbtf_private *priv);
+ int (*enable_interrupts) (struct lbtf_private *priv);
+ int (*disable_interrupts) (struct lbtf_private *priv);
/** Wlan adapter data structure*/
/** STATUS variables */
@@ -256,6 +260,13 @@ struct lbtf_private {
/* Most recently reported noise in dBm */
s8 noise;
+
+ /* Command responses sent from the hardware to the driver */
+ int cur_cmd_retcode;
+ u8 resp_idx;
+ u8 resp_buf[2][LBS_UPLD_SIZE];
+ u32 resp_len[2];
+
};
/* 802.11-related definitions */
@@ -488,9 +499,9 @@ struct chan_freq_power *lbtf_get_region_cfp_table(u8 region,
int *cfp_no);
struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev);
int lbtf_remove_card(struct lbtf_private *priv);
-int lbtf_start_card(struct lbtf_private *priv);
int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb);
void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail);
+void lbtf_host_to_card_done(struct lbtf_private *priv );
void lbtf_bcn_sent(struct lbtf_private *priv);
/* support functions for cmd.c */
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 5550755..90ef6c7 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -16,7 +16,7 @@
#define DRIVER_RELEASE_VERSION "004.p0"
/* thinfirm version: 5.132.X.pX */
#define LBTF_FW_VER_MIN 0x05840300
-#define LBTF_FW_VER_MAX 0x0584ffff
+#define LBTF_FW_VER_MAX 0x0900ffff
#define QOS_CONTROL_LEN 2
/* Module parameters */
@@ -178,12 +178,12 @@ static void command_timer_fn(unsigned long data)
spin_lock_irqsave(&priv->driver_lock, flags);
if (!priv->cur_cmd) {
- printk(KERN_DEBUG "libertastf: command timer expired; "
+ printk(KERN_DEBUG "libertas_tf: command timer expired; "
"no pending command\n");
goto out;
}
- printk(KERN_DEBUG "libertas: command %x timed out\n",
+ printk(KERN_DEBUG "libertas_tf: command %x timed out\n",
le16_to_cpu(priv->cur_cmd->cmdbuf->command));
priv->cmd_timed_out = 1;
@@ -228,6 +228,8 @@ static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct lbtf_private *priv = hw->priv;
+ lbtf_deb_enter(LBTF_DEB_TX);
+
priv->skb_to_tx = skb;
queue_work(lbtf_wq, &priv->tx_work);
/*
@@ -235,6 +237,8 @@ static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* there are no buffered multicast frames to send
*/
ieee80211_stop_queues(priv->hw);
+
+ lbtf_deb_leave(LBTF_DEB_TX);
return NETDEV_TX_OK;
}
@@ -250,9 +254,19 @@ static void lbtf_tx_work(struct work_struct *work)
lbtf_deb_enter(LBTF_DEB_MACOPS | LBTF_DEB_TX);
- if ((priv->vif->type == NL80211_IFTYPE_AP) &&
- (!skb_queue_empty(&priv->bc_ps_buf)))
+ /* Below are some extra debugging prints that normally we don't want */
+ /* Change to 1 to reenable */
+#if 0
+ lbtf_deb_tx("priv: %p", priv);
+ lbtf_deb_tx("priv->vif: %p", priv->vif);
+ lbtf_deb_tx("&(priv->bc_ps_buf): %p", &priv->bc_ps_buf);
+#endif
+
+ if (priv->vif &&
+ (priv->vif->type == NL80211_IFTYPE_AP) &&
+ (!skb_queue_empty(&priv->bc_ps_buf))) {
skb = skb_dequeue(&priv->bc_ps_buf);
+ }
else if (priv->skb_to_tx) {
skb = priv->skb_to_tx;
priv->skb_to_tx = NULL;
@@ -281,8 +295,10 @@ static void lbtf_tx_work(struct work_struct *work)
ETH_ALEN);
txpd->tx_packet_length = cpu_to_le16(len);
txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
- lbtf_deb_hex(LBTF_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
- BUG_ON(priv->tx_skb);
+ lbtf_deb_hex(LBTF_DEB_TX, "TX Data ", skb->data, min_t(unsigned int, skb->len, 100));
+
+ WARN_ON(priv->tx_skb);
+
spin_lock_irq(&priv->driver_lock);
priv->tx_skb = skb;
err = priv->hw_host_to_card(priv, MVMS_DAT, skb->data, skb->len);
@@ -292,6 +308,7 @@ static void lbtf_tx_work(struct work_struct *work)
priv->tx_skb = NULL;
pr_err("TX error: %d", err);
}
+ lbtf_deb_tx("TX success");
lbtf_deb_leave(LBTF_DEB_MACOPS | LBTF_DEB_TX);
}
@@ -303,12 +320,22 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
lbtf_deb_enter(LBTF_DEB_MACOPS);
- if (!priv->fw_ready)
+ if (!priv->fw_ready) {
+ lbtf_deb_main("Going to upload fw...");
/* Upload firmware */
if (priv->hw_prog_firmware(card))
goto err_prog_firmware;
+ else
+ priv->fw_ready = 1;
+ } else {
+ if (priv->enable_interrupts) {
+ priv->enable_interrupts(priv);
+ }
+ lbtf_deb_main("FW was already ready...");
+ }
/* poke the firmware */
+ lbtf_deb_main("Poking fw...");
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->radioon = RADIO_ON;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
@@ -322,12 +349,17 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
goto err_prog_firmware;
}
- printk(KERN_INFO "libertastf: Marvell WLAN 802.11 thinfirm adapter\n");
+ printk(KERN_INFO "libertas_tf: Marvell WLAN 802.11 thinfirm adapter\n");
+
+ SET_IEEE80211_PERM_ADDR(hw, priv->current_addr);
+
+ ieee80211_wake_queues(priv->hw);
+
lbtf_deb_leave(LBTF_DEB_MACOPS);
return 0;
err_prog_firmware:
- priv->hw_reset_device(card);
+// priv->hw_reset_device(card);
lbtf_deb_leave_args(LBTF_DEB_MACOPS, "error programing fw; ret=%d", ret);
return ret;
}
@@ -342,6 +374,8 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
lbtf_deb_enter(LBTF_DEB_MACOPS);
+ ieee80211_stop_queues(hw);
+
/* Flush pending command nodes */
spin_lock_irqsave(&priv->driver_lock, flags);
list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
@@ -358,12 +392,17 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
priv->radioon = RADIO_OFF;
lbtf_set_radio_control(priv);
+ if (priv->disable_interrupts) {
+ priv->disable_interrupts(priv);
+ }
+
lbtf_deb_leave(LBTF_DEB_MACOPS);
}
static int lbtf_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
+ u8 null_addr[ETH_ALEN] = {0};
struct lbtf_private *priv = hw->priv;
lbtf_deb_enter(LBTF_DEB_MACOPS);
if (priv->vif != NULL)
@@ -382,7 +421,12 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
priv->vif = NULL;
return -EOPNOTSUPP;
}
- lbtf_set_mac_address(priv, (u8 *) vif->addr);
+
+ if (compare_ether_addr(null_addr, vif->addr) != 0) {
+ lbtf_deb_macops("Setting mac addr: %pM\n", vif->addr);
+ lbtf_set_mac_address(priv, (u8 *) vif->addr);
+ }
+
lbtf_deb_leave(LBTF_DEB_MACOPS);
return 0;
}
@@ -596,7 +640,7 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
lbtf_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
- lbtf_deb_hex(LBTF_DEB_RX, "RX Data", skb->data,
+ lbtf_deb_hex(LBTF_DEB_RX, "RX Data ", skb->data,
min_t(unsigned int, skb->len, 100));
ieee80211_rx_irqsafe(priv->hw, skb);
@@ -667,7 +711,6 @@ done:
}
EXPORT_SYMBOL_GPL(lbtf_add_card);
-
int lbtf_remove_card(struct lbtf_private *priv)
{
struct ieee80211_hw *hw = priv->hw;
@@ -709,6 +752,37 @@ void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail)
}
EXPORT_SYMBOL_GPL(lbtf_send_tx_feedback);
+void lbtf_host_to_card_done(struct lbtf_private *priv )
+{
+ lbtf_deb_enter(LBTF_DEB_MAIN);
+
+ /* Below are some extra debugging prints that normally we don't want */
+ /* Change to 1 to reenable */
+#if 0
+ lbtf_deb_main("priv: %p", priv);
+ lbtf_deb_main("priv->hw: %p", priv->hw);
+ lbtf_deb_main("priv->tx_skb: %p", priv->tx_skb);
+ lbtf_deb_main("priv->skb_to_tx: %p", priv->skb_to_tx);
+#endif
+
+ if (priv->tx_skb) {
+ ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb);
+ priv->tx_skb = NULL;
+ lbtf_deb_main("Got done on packet.");
+ } else {
+ lbtf_deb_main("Got done on command.");
+ }
+
+ if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf)) {
+ ieee80211_wake_queues(priv->hw);
+ } else {
+ queue_work(lbtf_wq, &priv->tx_work);
+ }
+
+ lbtf_deb_leave(LBTF_DEB_THREAD);
+}
+EXPORT_SYMBOL_GPL(lbtf_host_to_card_done);
+
void lbtf_bcn_sent(struct lbtf_private *priv)
{
struct sk_buff *skb = NULL;
--
1.7.0
This patch adds tx-feedback to libertas_tf_sdio so that mac80211 rate
adaptation and other bookkeeping tasks function properly.
Signed-off-by: Steve deRosier <[email protected]>
---
drivers/net/wireless/libertas_tf/deb_defs.h | 5 ++
drivers/net/wireless/libertas_tf/if_sdio.c | 42 +++++++++++------
drivers/net/wireless/libertas_tf/main.c | 65 ++++++++++++++++----------
3 files changed, 72 insertions(+), 40 deletions(-)
diff --git a/drivers/net/wireless/libertas_tf/deb_defs.h b/drivers/net/wireless/libertas_tf/deb_defs.h
index 99a7478..8e86e11 100644
--- a/drivers/net/wireless/libertas_tf/deb_defs.h
+++ b/drivers/net/wireless/libertas_tf/deb_defs.h
@@ -43,6 +43,9 @@
#define LBTF_DEB_HEX 0x00200000
#define LBTF_DEB_SDIO 0x00400000
#define LBTF_DEB_MACOPS 0x00800000
+#define LBTF_DEB_STATS 0x01000000
+#define LBTF_DEB_INT 0x02000000
+#define LBTF_DEB_SCRATCH 0x04000000
extern unsigned int lbtf_debug;
@@ -87,6 +90,8 @@ do { if ((lbtf_debug & (grp)) == (grp)) \
#define lbtf_deb_thread(fmt, args...) LBTF_DEB_LL(LBTF_DEB_THREAD, " thread", fmt, ##args)
#define lbtf_deb_sdio(fmt, args...) LBTF_DEB_LL(LBTF_DEB_SDIO, " sdio", fmt, ##args)
#define lbtf_deb_macops(fmt, args...) LBTF_DEB_LL(LBTF_DEB_MACOPS, " thread", fmt, ##args)
+#define lbtf_deb_stats(fmt, args...) LBTF_DEB_LL(LBTF_DEB_STATS, " statistics", fmt, ##args)
+#define lbtf_deb_int(fmt, args...) LBTF_DEB_LL(LBTF_DEB_INT, " int", fmt, ##args)
#ifdef DEBUG
static inline void lbtf_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
diff --git a/drivers/net/wireless/libertas_tf/if_sdio.c b/drivers/net/wireless/libertas_tf/if_sdio.c
index 189b820..5074f8b 100644
--- a/drivers/net/wireless/libertas_tf/if_sdio.c
+++ b/drivers/net/wireless/libertas_tf/if_sdio.c
@@ -148,7 +148,7 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
int ret;
u16 scratch;
- lbtf_deb_enter(LBTF_DEB_SDIO);
+ lbtf_deb_enter(LBTF_DEB_SCRATCH);
scratch = sdio_readb(card->func, card->scratch_reg, &ret);
if (!ret)
@@ -161,7 +161,7 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
if (ret)
return 0xffff;
- lbtf_deb_leave_args(LBTF_DEB_SDIO, "scratch %x", scratch);
+ lbtf_deb_leave_args(LBTF_DEB_SCRATCH, "scratch %x", scratch);
return scratch;
}
@@ -232,7 +232,7 @@ static int if_sdio_handle_data(struct if_sdio_card *card,
struct sk_buff *skb;
char *data;
- lbtf_deb_enter(LBTF_DEB_SDIO);
+ lbtf_deb_enter(LBTF_DEB_INT);
if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
lbtf_deb_sdio("response packet too large (%d bytes)\n",
@@ -258,7 +258,7 @@ static int if_sdio_handle_data(struct if_sdio_card *card,
ret = 0;
out:
- lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+ lbtf_deb_leave_args(LBTF_DEB_INT, "ret %d", ret);
return ret;
}
@@ -291,7 +291,21 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
event |= buffer[0] << 0;
}
- lbtf_deb_sdio("**EVENT** 0x%X\n", event);
+ lbtf_deb_stats("**EVENT** 0x%X\n", event);
+
+ if (event & 0xffff0000) {
+ u16 tmp;
+ u8 retrycnt;
+ u8 failure;
+
+ tmp = event >> 16;
+ retrycnt = tmp & 0x00ff;
+ failure = (tmp & 0xff00) >> 8;
+ lbtf_deb_stats("Got feedback event. retry: %d, failure: %d", retrycnt, failure);
+ lbtf_send_tx_feedback(card->priv, retrycnt, failure);
+ } else if (event == LBTF_EVENT_BCN_SENT)
+ lbtf_bcn_sent(card->priv);
+
ret = 0;
out:
@@ -326,7 +340,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card)
int ret;
u16 size, type, chunk;
- lbtf_deb_enter(LBTF_DEB_SDIO);
+ lbtf_deb_enter(LBTF_DEB_INT);
size = if_sdio_read_rx_len(card, &ret);
@@ -358,7 +372,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card)
chunk = card->buffer[0] | (card->buffer[1] << 8);
type = card->buffer[2] | (card->buffer[3] << 8);
- lbtf_deb_sdio("packet of type %d and size %d bytes\n",
+ lbtf_deb_int("packet of type %d and size %d bytes\n",
(int)type, (int)chunk);
if (chunk > size) {
@@ -400,7 +414,7 @@ out:
if (ret)
pr_err("problem fetching packet from firmware\n");
- lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+ lbtf_deb_leave_args(LBTF_DEB_INT, "ret %d", ret);
return ret;
}
@@ -1063,25 +1077,23 @@ static void if_sdio_interrupt(struct sdio_func *func)
struct if_sdio_card *card;
u8 cause;
- lbtf_deb_enter(LBTF_DEB_SDIO);
+ lbtf_deb_enter(LBTF_DEB_INT);
card = sdio_get_drvdata(func);
cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
- lbtf_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
- lbtf_deb_sdio("interrupt ret: 0x%X\n", ret);
+ lbtf_deb_int("interrupt: 0x%X\n", (unsigned)cause);
+ lbtf_deb_int("interrupt ret: 0x%X\n", ret);
if (ret)
goto out;
-// lbtf_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
-
sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
if (ret)
goto out;
/*
* Ignore the define name, this really means the card has
- * successfully received the command.
+ * successfully received the command or packet.
*/
if (cause & IF_SDIO_H_INT_DNLD)
if (card->priv)
@@ -1096,7 +1108,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
ret = 0;
out:
- lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
+ lbtf_deb_leave_args(LBTF_DEB_INT, "ret %d", ret);
}
static int if_sdio_probe(struct sdio_func *func,
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index b797787..cc2217c 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -296,12 +296,14 @@ static void lbtf_tx_work(struct work_struct *work)
/* Activate per-packet rate selection */
txpd->tx_control |= cpu_to_le32(MRVL_PER_PACKET_RATE |
ieee80211_get_tx_rate(priv->hw, info)->hw_value);
+ lbtf_deb_tx("tx_control: %x", txpd->tx_control );
/* copy destination address from 802.11 header */
memcpy(txpd->tx_dest_addr_high, skb->data + sizeof(struct txpd) + 4,
ETH_ALEN);
txpd->tx_packet_length = cpu_to_le16(len);
txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
+
lbtf_deb_hex(LBTF_DEB_TX, "TX Data ", skb->data, min_t(unsigned int, skb->len, 100));
WARN_ON(priv->tx_skb);
@@ -729,10 +731,18 @@ EXPORT_SYMBOL_GPL(lbtf_add_card);
int lbtf_remove_card(struct lbtf_private *priv)
{
+ struct sk_buff *skb = NULL;
struct ieee80211_hw *hw = priv->hw;
lbtf_deb_enter(LBTF_DEB_MAIN);
+ ieee80211_stop_queues(priv->hw);
+
+ while (!skb_queue_empty(&priv->tx_skb_buf)) {
+ skb = skb_dequeue(&priv->tx_skb_buf);
+ dev_kfree_skb_any(skb);
+ }
+
priv->surpriseremoved = 1;
del_timer(&priv->command_timer);
lbtf_free_adapter(priv);
@@ -747,24 +757,37 @@ EXPORT_SYMBOL_GPL(lbtf_remove_card);
void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb);
+ struct ieee80211_tx_info *info;
+ lbtf_deb_enter(LBTF_DEB_MAIN);
- ieee80211_tx_info_clear_status(info);
- /*
- * Commented out, otherwise we never go beyond 1Mbit/s using mac80211
- * default pid rc algorithm.
- *
- * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt;
- */
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail)
- info->flags |= IEEE80211_TX_STAT_ACK;
- skb_pull(priv->tx_skb, sizeof(struct txpd));
- ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb);
- priv->tx_skb = NULL;
- if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf))
- ieee80211_wake_queues(priv->hw);
- else
- queue_work(lbtf_wq, &priv->tx_work);
+ if(priv->tx_skb == 0) {
+ lbtf_deb_stats("tx_skb is null");
+ } else {
+
+ lbtf_deb_stats("tx_skb is ok");
+
+ info = IEEE80211_SKB_CB(priv->tx_skb);
+ ieee80211_tx_info_clear_status(info);
+ /*
+ * Commented out, otherwise we never go beyond 1Mbit/s using mac80211
+ * default pid rc algorithm.
+ *
+ * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt;
+ */
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail) {
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ }
+ skb_pull(priv->tx_skb, sizeof(struct txpd));
+ ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb);
+ }
+
+ priv->tx_skb = NULL;
+ if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf))
+ ieee80211_wake_queues(priv->hw);
+ else
+ queue_work(lbtf_wq, &priv->tx_work);
+
+ lbtf_deb_leave(LBTF_DEB_MAIN);
}
EXPORT_SYMBOL_GPL(lbtf_send_tx_feedback);
@@ -782,19 +805,11 @@ void lbtf_host_to_card_done(struct lbtf_private *priv )
#endif
if (priv->tx_skb) {
- ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb);
- priv->tx_skb = NULL;
lbtf_deb_main("Got done on packet.");
} else {
lbtf_deb_main("Got done on command.");
}
- if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf)) {
- ieee80211_wake_queues(priv->hw);
- } else {
- queue_work(lbtf_wq, &priv->tx_work);
- }
-
lbtf_deb_leave(LBTF_DEB_THREAD);
}
EXPORT_SYMBOL_GPL(lbtf_host_to_card_done);
--
1.7.0
On Thu, Sep 09, 2010 at 08:34:41PM -0700, Steve deRosier wrote:
> In light of the above, and Julian's comments, I'm going to rework the
> libertas_tf patch set a little. I'll make the following two changes:
> 1. Restrict building to module-only for now. This avoids building it
> into the kernel which we know will break. Latter when I have time
> I'll happily do what's necessary to make the fix Johannes wants, but
> as it's not trivial I want to get a base down.
> 2. I'll change a few things around as Julian's advised so the patch
> set makes a bit more sense. I'll be also killing some inadvertent
> white-space changes that were mistakes.
I interpret this as "drop this series -- new series will replace it".
> I think my mac80211 patch "mac80211: Fix dangling pointer in
> ieee80211_xmit" stands 100% alone and fixes a clear bug. I don't see
> any need to delay that one.
I missed this before -- I'll take that patch on its own.
> It might be a few days before I get these in.
Is this still coming?
John
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.
On Thu, Sep 9, 2010 at 09:25, Steve deRosier <[email protected]> wrote:
>
> Signed-off-by: Steve deRosier <[email protected]>
It'd be nice if the subject line of this patch was a bit more descriptive.
Something like "libertas_tf: Update beacon code" would be descriptive.
Also, it appears that this patch does two things, update the beacon
code and add some debugging. You may want to separate this into two
patches.
Thanks,
--
Julian Calaby
Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/
Signed-off-by: Steve deRosier <[email protected]>
---
drivers/net/wireless/libertas_tf/main.c | 18 +++++++++---------
1 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 14ce1bc..b797787 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -327,20 +327,20 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
lbtf_deb_enter(LBTF_DEB_MACOPS);
- if (priv->hw_prog_firmware) {
- if (!priv->fw_ready) {
- lbtf_deb_main("Going to upload fw...");
- /* Upload firmware */
+ if (!priv->fw_ready) {
+ lbtf_deb_main("Going to upload fw...");
+ /* Upload firmware */
+ if (priv->hw_prog_firmware) {
if (priv->hw_prog_firmware(card))
goto err_prog_firmware;
else
priv->fw_ready = 1;
- } else {
- if (priv->enable_interrupts) {
- priv->enable_interrupts(priv);
- }
- lbtf_deb_main("FW was already ready...");
}
+ } else {
+ if (priv->enable_interrupts) {
+ priv->enable_interrupts(priv);
+ }
+ lbtf_deb_main("FW was already ready...");
}
/* poke the firmware */
--
1.7.0
On Thu, Sep 9, 2010 at 15:49, Steve deRosier <[email protected]> wrote:
> On Wed, Sep 8, 2010 at 7:16 PM, Julian Calaby <[email protected]> wrote:
>> More nits:
>>
>> On Thu, Sep 9, 2010 at 09:25, Steve deRosier <[email protected]> wrote:
>>> This patch adds tx-feedback to libertas_tf_sdio so that mac80211 rate
>>> adaptation and other bookkeeping tasks function properly.
>>>
>>> Signed-off-by: Steve deRosier <[email protected]>
>>> ---
>>> ?drivers/net/wireless/libertas_tf/deb_defs.h | ? ?5 ++
>>> ?drivers/net/wireless/libertas_tf/if_sdio.c ?| ? 42 +++++++++++------
>>> ?drivers/net/wireless/libertas_tf/main.c ? ? | ? 65 ++++++++++++++++----------
>>> ?3 files changed, 72 insertions(+), 40 deletions(-)
>>>
>>> diff --git a/drivers/net/wireless/libertas_tf/deb_defs.h b/drivers/net/wireless/libertas_tf/deb_defs.h
>>> index 99a7478..8e86e11 100644
>>> --- a/drivers/net/wireless/libertas_tf/deb_defs.h
>>> +++ b/drivers/net/wireless/libertas_tf/deb_defs.h
>>> @@ -1063,25 +1077,23 @@ static void if_sdio_interrupt(struct sdio_func *func)
>>> ? ? ? ?if (ret)
>>> ? ? ? ? ? ? ? ?goto out;
>>>
>>> -// ? ? lbtf_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
>>> -
>>> ? ? ? ?sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
>>> ? ? ? ?if (ret)
>>> ? ? ? ? ? ? ? ?goto out;
>>
>> Shouldn't this have been removed instead of being commented in the
>> patch that commented it?
>>
>
> Until this time I was using this line intermittently. ?I frequently
> uncommented it in order to see some debugging info. ?But as it is in
> an interrupt, it creates a lot of noise that I usually didn't want to
> see. ?Once I was past a certain point (here) and didn't need it
> anymore, it got deleted.
>
> I could have rolled all the patches into one single patch that was
> nice and neat with a blue bow, but then you wouldn't have seen all the
> fun I had and you would have missed out. ?:)
Hehehe. Quite. I guess I'm just more pedantic about such things than
most people. Ah well =)
Thanks,
--
Julian Calaby
Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/
On Wed, Sep 8, 2010 at 7:06 PM, Julian Calaby <[email protected]> wrote:
> More nits:
>
>
> Are these changes really necessary here? - It'd probably be cleaner to
> change the initial functions to just take the card struct instead? (as
> it's always available as priv->card)
>
> I'm guessing you're going to do something with the _* versions of
> these functions later, so should this change be there instead?
>
Yes, these changes are necessary. The enable and disable interrupt
calls are called both from main.c as well as sdio.c. main.c has
access to and needs to call with a priv, while at least one of the
calls from sdio.c happens before priv exists. I could have changed
the stuff in main.c to call with priv->card, but alas at the time I
was still trying to minimize structural changes main.c and avoiding
changes to the USB driver.
>> @@ -187,7 +201,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
>> ? ? ? ?struct lbtf_private *priv = card->priv;
>> ? ? ? ?int ret;
>> ? ? ? ?unsigned long flags;
>> - ? ? ? u8 i;
>>
>> ? ? ? ?lbtf_deb_enter(LBTF_DEB_SDIO);
>>
>
> Shouldn't this be elsewhere (maybe rolled into patch #1?)
>
It could be, but I didn't do this cleanup till now, some 20 commits
later. Not that easy to pick and choose which lines from an atomic
commit go to which patch some weeks later.
>> @@ -709,7 +726,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
>> ? ? ? ? ? ? ? ?if( lbtf_reset_fw == 0 ) {
>> ? ? ? ? ? ? ? ? ? ? ? ?goto success;
>> ? ? ? ? ? ? ? ?} else {
>> - ? ? ? ? ? ? ? ? ? ? ? int i = 0;
>> ? ? ? ? ? ? ? ? ? ? ? ?lbtf_deb_sdio("attempting to reset and reload firmware\n");
>>
>> ? ? ? ? ? ? ? ? ? ? ? ?if_sdio_reset_device(card);
>
> Ditto.
Ditto. And so on...
>> diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
>> index 119d625..14ce1bc 100644
>> --- a/drivers/net/wireless/libertas_tf/main.c
>> +++ b/drivers/net/wireless/libertas_tf/main.c
>> @@ -150,14 +150,15 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
>> ? ? ? ?int ret = -1;
>>
>> ? ? ? ?lbtf_deb_enter(LBTF_DEB_FW);
>> +
>> ? ? ? ?/*
>> ? ? ? ? * Read priv address from HW
>> ? ? ? ? */
>> ? ? ? ?memset(priv->current_addr, 0xff, ETH_ALEN);
>> ? ? ? ?ret = lbtf_update_hw_spec(priv);
>> ? ? ? ?if (ret) {
>> - ? ? ? ? ? ? ? ret = -1;
>> - ? ? ? ? ? ? ? goto done;
>> + ? ? ? ? ? ? ? ? ?ret = -1;
>> + ? ? ? ? ? ? ? ? ?goto done;
>> ? ? ? ?}
>>
>> ? ? ? ?lbtf_set_mac_control(priv);
>
> Whitespace change noise.
Well, perhaps. On the other hand, it made it more readable to me (the
first one, the newline. The indentation change is actually incorrect,
no doubt about it). Have you ever worked with a codebase for 3 some
months and not incidentally or accidentally changed some whitespace?
If this patch was just to change whitespace, then I'd agree with you
and wouldn't have wasted time bothering to submit it, but the patch as
a whole adds necessary functionality.
If you want me to fix the whitespace, I can.
Thanks,
- Steve
On Wed, Sep 8, 2010 at 6:44 PM, Julian Calaby <[email protected]> wrote:
> Minor nit:
>
> On Thu, Sep 9, 2010 at 09:25, Steve deRosier <[email protected]> wrote:
>> This patch adds a method to do a firmware/chip reset to the sdio driver and
>> attempts to reload the firmware.
>>
>> Signed-off-by: Steve deRosier <[email protected]>
>> ---
>> ?drivers/net/wireless/libertas_tf/if_sdio.c | ? 40 +++++++++++++++++++++++----
>> ?drivers/net/wireless/libertas_tf/main.c ? ?| ? ?7 ++++-
>> ?2 files changed, 40 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/net/wireless/libertas_tf/if_sdio.c b/drivers/net/wireless/libertas_tf/if_sdio.c
>> index fed5aff..1e72b4c 100644
>> --- a/drivers/net/wireless/libertas_tf/main.c
>> +++ b/drivers/net/wireless/libertas_tf/main.c
>> @@ -360,7 +364,8 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
>> ? ? ? ?return 0;
>>
>> ?err_prog_firmware:
>> -// ? ? priv->hw_reset_device(card);
>> + ? ? ? if (priv->hw_reset_device)
>> + ? ? ? ? ? ? ? priv->hw_reset_device(card);
>
> Should this not be done in the first patch? - rather than just
> commenting out the call: Would commenting out this line in the first
> patch make the original version of libertas_tf unable to handle
> firmware errors properly?
>
Yes, it could have been done in the first patch. I could have rolled
all my patches into one single patch, but I felt it was better to keep
some parts split out. As it was, I squashed and reordered about 50
commits into the 17 I posted. I basically spent most of the day
rebasing 3 months worth of commits to come out with what I thought was
a logical set. In particular, since I had contributions from others
in the mix, I wanted to respect their patches as _theirs_ instead of
squashing them into my own. As you'll notice patch 2 was from someone
else.
If John would prefer, I can squish all my patches into one, with the
exception of those submitted to me by other parties and the lone
mac80211 patch.
As for the specific question about this item... The libertas_tf_sdio
driver started from the libertas_sdio driver. I hacked and molded
until I had something that worked and I learned more about the chip
and the interface. I started by commenting out code I didn't need at
the time. This specific line was commented out because it wasn't
germane to the problems I was solving at the moment AND it caused
problems. Did commenting the line out "make the original version of
libertas_tf unable to handle firmware errors properly?" No: simple
fact is resetting the device didn't work properly at the time anyway
and just really mucked up the situation making debugging the firmware
a bear.
If it really matters, I'll be happy to rebase more and send up fewer patches.
Thanks,
- Steve
On Thu, 9 Sep 2010 20:34:41 -0700, Steve deRosier <[email protected]>
wrote:
> I think my mac80211 patch "mac80211: Fix dangling pointer in
> ieee80211_xmit" stands 100% alone and fixes a clear bug. I don't see
> any need to delay that one.
Agree, best resend it outside this series, or if John wants to just
pick it up outside the series.
(Generally, I would ask to send mac80211 patches outside driver
series anyway, because it makes it harder to miss such things)
johannes
On Tue, Sep 28, 2010 at 11:24:57AM -0400, John W. Linville wrote:
> > I think my mac80211 patch "mac80211: Fix dangling pointer in
> > ieee80211_xmit" stands 100% alone and fixes a clear bug. I don't see
> > any need to delay that one.
>
> I missed this before -- I'll take that patch on its own.
Actually, looks like I already did... :-)
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.
Minor nit:
On Thu, Sep 9, 2010 at 09:25, Steve deRosier <[email protected]> wrote:
> This patch adds a method to do a firmware/chip reset to the sdio driver and
> attempts to reload the firmware.
>
> Signed-off-by: Steve deRosier <[email protected]>
> ---
> ?drivers/net/wireless/libertas_tf/if_sdio.c | ? 40 +++++++++++++++++++++++----
> ?drivers/net/wireless/libertas_tf/main.c ? ?| ? ?7 ++++-
> ?2 files changed, 40 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/wireless/libertas_tf/if_sdio.c b/drivers/net/wireless/libertas_tf/if_sdio.c
> index fed5aff..1e72b4c 100644
> --- a/drivers/net/wireless/libertas_tf/main.c
> +++ b/drivers/net/wireless/libertas_tf/main.c
> @@ -360,7 +364,8 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
> ? ? ? ?return 0;
>
> ?err_prog_firmware:
> -// ? ? priv->hw_reset_device(card);
> + ? ? ? if (priv->hw_reset_device)
> + ? ? ? ? ? ? ? priv->hw_reset_device(card);
Should this not be done in the first patch? - rather than just
commenting out the call: Would commenting out this line in the first
patch make the original version of libertas_tf unable to handle
firmware errors properly?
> ? ? ? ?lbtf_deb_leave_args(LBTF_DEB_MACOPS, "error programing fw; ret=%d", ret);
> ? ? ? ?return ret;
> ?}
Thanks,
--
Julian Calaby
Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/
On Thu, Sep 9, 2010 at 9:38 AM, Johannes Berg <[email protected]> wrote:
>
> On Wed, ?8 Sep 2010 16:25:25 -0700, Steve deRosier <[email protected]>
> wrote:
>> mac80211 requires that the MAC address be known and set before calling
>> ieee80211_register_hw(). ?If this isn't done, we see bad MAC addresses
>> in our packet headers. ?In order to make this happen, I had to
> restructure
>> to have if_sdio_probe load the firmware and get the hardware specs.
>>
>> I had to add a if_sdio_update_hw_spec function as if_sdio can't use the
>> standard
>> command as several required variables aren't setup yet.
>> if_sdio_update_hw_spec essentially uses polled io to get the hw spec
>> command response from the card.
>
> You should probably keep this for development purposes, but it will break
> if your code is built into the kernel. The working model we've adopted to
> solve this is to use request_firmware_nowait() in probe, and then only
> continue doing work when the firmware loading returns (and then register
> with mac80211 etc)
>
Johannes,
Before doing any of this stuff (back in patch 1), my driver goes
through and loads the firmware using the request_firmware() calls
anyway. In other words, I haven't changed that part. Is the problem
specifically with my "get the MAC from the hardware before setting up
mac80211" change, or with waiting on firmware loading?
For fun, I just tried compiling the driver into the kernel. Mixed
results: with two cards on the system, the first card found failed on
the call to request_firmware() with a -ENOENT, while the second card
came up just fine. When done as modules, both work fine. So there's
clearly something to what you're saying. Is it that the filesystem is
not up and available yet when we try to load the firmware for the
first card?
>From looking through the drivers, iwl and ar9170_usb are the only ones
to use the request_firmware_nowait(). I don't know if those are the
only mac80211 cards with firmware or not everyone's following the
model.
Do you have specific pointers of which code I should look at as a
model, or a better way to solve the problem?
In the short term, can we limit libertas_tf to build as module only
via Kconfig, and I can add the request_firmware_nowait() as a new
feature later with a new patch? Looking at the examples, it looks
like the changes for this would be fairly involved and I would prefer
to break such a change out separately. I'd like to get
libertas_tf_sdio accepted as a base so I can then do smaller change
sets going forward. Is that a reasonable plan or just plain silly?
BTW, thanks for pointing out this problem. I hadn't tried this built
into the kernel and it never occurred to me that this would be an
issue.
Thanks,
- Steve
Signed-off-by: Steve deRosier <[email protected]>
---
drivers/net/wireless/libertas_tf/cmd.c | 2 +-
drivers/net/wireless/libertas_tf/if_sdio.c | 5 +-
drivers/net/wireless/libertas_tf/libertas_tf.h | 6 ++
drivers/net/wireless/libertas_tf/main.c | 88 ++++++++++++++++++------
4 files changed, 78 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c
index 738a2ff..8c15e35 100644
--- a/drivers/net/wireless/libertas_tf/cmd.c
+++ b/drivers/net/wireless/libertas_tf/cmd.c
@@ -354,7 +354,7 @@ void lbtf_set_bssid(struct lbtf_private *priv, bool activate, const u8 *bssid)
{
struct cmd_ds_set_bssid cmd;
lbtf_deb_enter(LBTF_DEB_CMD);
-
+ lbtf_deb_cmd("Set BSSID: %pM a: %d", bssid, activate);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.activate = activate ? 1 : 0;
if (activate)
diff --git a/drivers/net/wireless/libertas_tf/if_sdio.c b/drivers/net/wireless/libertas_tf/if_sdio.c
index 5074f8b..09c028f 100644
--- a/drivers/net/wireless/libertas_tf/if_sdio.c
+++ b/drivers/net/wireless/libertas_tf/if_sdio.c
@@ -303,8 +303,11 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
failure = (tmp & 0xff00) >> 8;
lbtf_deb_stats("Got feedback event. retry: %d, failure: %d", retrycnt, failure);
lbtf_send_tx_feedback(card->priv, retrycnt, failure);
- } else if (event == LBTF_EVENT_BCN_SENT)
+ } else if (event == LBTF_EVENT_BCN_SENT) {
lbtf_bcn_sent(card->priv);
+ } else {
+ lbtf_deb_stats("UNKNOWN HOST EVENT: 0x%x", event);
+ }
ret = 0;
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
index c7588fd..db6dd7b 100644
--- a/drivers/net/wireless/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -241,6 +241,8 @@ struct lbtf_private {
struct sk_buff *skb_to_tx;
struct sk_buff *tx_skb;
+ struct sk_buff *tx_skb_old;
+ struct sk_buff_head tx_skb_buf;
/** NIC Operation characteristics */
u16 mac_control;
@@ -267,6 +269,10 @@ struct lbtf_private {
u8 resp_idx;
u8 resp_buf[2][LBS_UPLD_SIZE];
u32 resp_len[2];
+
+ /* beacon status info */
+ bool beacon_enable;
+ u16 beacon_int;
};
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index cc2217c..6c4a1b6 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -272,6 +272,7 @@ static void lbtf_tx_work(struct work_struct *work)
if (priv->vif &&
(priv->vif->type == NL80211_IFTYPE_AP) &&
(!skb_queue_empty(&priv->bc_ps_buf))) {
+ lbtf_deb_tx("bc_ps_buf");
skb = skb_dequeue(&priv->bc_ps_buf);
}
else if (priv->skb_to_tx) {
@@ -306,15 +307,13 @@ static void lbtf_tx_work(struct work_struct *work)
lbtf_deb_hex(LBTF_DEB_TX, "TX Data ", skb->data, min_t(unsigned int, skb->len, 100));
- WARN_ON(priv->tx_skb);
-
spin_lock_irq(&priv->driver_lock);
- priv->tx_skb = skb;
+ skb_queue_tail(&priv->tx_skb_buf, skb);
err = priv->hw_host_to_card(priv, MVMS_DAT, skb->data, skb->len);
spin_unlock_irq(&priv->driver_lock);
if (err) {
dev_kfree_skb_any(skb);
- priv->tx_skb = NULL;
+ skb_dequeue_tail(&priv->tx_skb_buf);
pr_err("TX error: %d", err);
}
lbtf_deb_tx("TX success");
@@ -417,8 +416,10 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
u8 null_addr[ETH_ALEN] = {0};
struct lbtf_private *priv = hw->priv;
lbtf_deb_enter(LBTF_DEB_MACOPS);
- if (priv->vif != NULL)
+ if (priv->vif != NULL) {
+ lbtf_deb_macops("priv->vif != NULL");
return -EOPNOTSUPP;
+ }
priv->vif = vif;
switch (vif->type) {
@@ -431,6 +432,7 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
break;
default:
priv->vif = NULL;
+ lbtf_deb_macops("Unsupported interface mode: %d", vif->type);
return -EOPNOTSUPP;
}
@@ -548,7 +550,10 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
struct sk_buff *beacon;
lbtf_deb_enter(LBTF_DEB_MACOPS);
- if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_INT)) {
+ lbtf_deb_macops("bss info changed: 0x%x", changes);
+ if (changes & (BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_INT |
+ BSS_CHANGED_BEACON_ENABLED)) {
switch (priv->vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
@@ -556,7 +561,10 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
if (beacon) {
lbtf_beacon_set(priv, beacon);
kfree_skb(beacon);
- lbtf_beacon_ctrl(priv, 1,
+ priv->beacon_enable = bss_conf->enable_beacon;
+ priv->beacon_int = bss_conf->beacon_int;
+ lbtf_set_bssid(priv, 1, bss_conf->bssid);
+ lbtf_beacon_ctrl(priv, bss_conf->enable_beacon,
bss_conf->beacon_int);
}
break;
@@ -565,6 +573,21 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
+ if (changes & (BSS_CHANGED_BEACON_INT |
+ BSS_CHANGED_BEACON_ENABLED)) {
+ switch (priv->vif->type) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
+ priv->beacon_enable = bss_conf->enable_beacon;
+ priv->beacon_int = bss_conf->beacon_int;
+ lbtf_beacon_ctrl(priv, bss_conf->enable_beacon,
+ bss_conf->beacon_int);
+ break;
+ default:
+ break;
+ }
+ }
+
if (changes & BSS_CHANGED_BSSID) {
bool activate = !is_zero_ether_addr(bss_conf->bssid);
lbtf_set_bssid(priv, activate, bss_conf->bssid);
@@ -688,6 +711,7 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev, u8 mac_addr
priv->hw = hw;
priv->card = card;
priv->tx_skb = NULL;
+ priv->tx_skb_old = NULL;
hw->queues = 1;
hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
@@ -701,8 +725,11 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev, u8 mac_addr
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
skb_queue_head_init(&priv->bc_ps_buf);
+ skb_queue_head_init(&priv->tx_skb_buf);
SET_IEEE80211_DEV(hw, dmdev);
@@ -758,15 +785,20 @@ EXPORT_SYMBOL_GPL(lbtf_remove_card);
void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail)
{
struct ieee80211_tx_info *info;
+ struct sk_buff *skb = NULL;
lbtf_deb_enter(LBTF_DEB_MAIN);
- if(priv->tx_skb == 0) {
- lbtf_deb_stats("tx_skb is null");
+ if (!skb_queue_empty(&priv->tx_skb_buf)) {
+ skb = skb_dequeue(&priv->tx_skb_buf);
+ }
+
+ if(skb == 0) {
+ lbtf_deb_stats("skb is null");
} else {
- lbtf_deb_stats("tx_skb is ok");
+ lbtf_deb_stats("skb is ok");
- info = IEEE80211_SKB_CB(priv->tx_skb);
+ info = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(info);
/*
* Commented out, otherwise we never go beyond 1Mbit/s using mac80211
@@ -777,15 +809,14 @@ void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail)
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail) {
info->flags |= IEEE80211_TX_STAT_ACK;
}
- skb_pull(priv->tx_skb, sizeof(struct txpd));
- ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb);
+ skb_pull(skb, sizeof(struct txpd));
+ ieee80211_tx_status_irqsafe(priv->hw, skb);
}
- priv->tx_skb = NULL;
- if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf))
- ieee80211_wake_queues(priv->hw);
- else
- queue_work(lbtf_wq, &priv->tx_work);
+ if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf))
+ ieee80211_wake_queues(priv->hw);
+ else
+ queue_work(lbtf_wq, &priv->tx_work);
lbtf_deb_leave(LBTF_DEB_MAIN);
}
@@ -810,7 +841,7 @@ void lbtf_host_to_card_done(struct lbtf_private *priv )
lbtf_deb_main("Got done on command.");
}
- lbtf_deb_leave(LBTF_DEB_THREAD);
+ lbtf_deb_leave(LBTF_DEB_MAIN);
}
EXPORT_SYMBOL_GPL(lbtf_host_to_card_done);
@@ -818,6 +849,18 @@ void lbtf_bcn_sent(struct lbtf_private *priv)
{
struct sk_buff *skb = NULL;
+ lbtf_deb_enter(LBTF_DEB_MAIN);
+
+ if (!priv) {
+ lbtf_deb_main("got bcn sent with priv == NULL");
+ return;
+ }
+
+ if (!priv->vif) {
+ lbtf_deb_main("got bcn sent with vif == NULL");
+ return;
+ }
+
if (priv->vif->type != NL80211_IFTYPE_AP)
return;
@@ -837,9 +880,12 @@ void lbtf_bcn_sent(struct lbtf_private *priv)
skb = ieee80211_beacon_get(priv->hw, priv->vif);
if (skb) {
- lbtf_beacon_set(priv, skb);
+ lbtf_beacon_set(priv, skb);
kfree_skb(skb);
+ lbtf_beacon_ctrl(priv, priv->beacon_enable, priv->beacon_int);
}
+
+ lbtf_deb_leave(LBTF_DEB_MAIN);
}
EXPORT_SYMBOL_GPL(lbtf_bcn_sent);
--
1.7.0
On Thu, Sep 9, 2010 at 1:58 PM, Johannes Berg <[email protected]> wrote:
>
> On Thu, 9 Sep 2010 12:13:52 -0700, Steve deRosier <[email protected]>
>> In the short term, can we limit libertas_tf to build as module only
>> via Kconfig, and I can add the request_firmware_nowait() as a new
>> feature later with a new patch?
>
> Certainly. I just wanted to point it out. This wasn't meant as
> a comment that should stop merging of these patches.
>
>> Looking at the examples, it looks
>> like the changes for this would be fairly involved and I would prefer
>> to break such a change out separately.
>
> Yeah, I tried to do it in libertas_tf at some point last year and
> failed miserably :-)
>
>> I'd like to get
>> libertas_tf_sdio accepted as a base so I can then do smaller change
>> sets going forward. Is that a reasonable plan or just plain silly?
>
> Makes sense to me.
>
In light of the above, and Julian's comments, I'm going to rework the
libertas_tf patch set a little. I'll make the following two changes:
1. Restrict building to module-only for now. This avoids building it
into the kernel which we know will break. Latter when I have time
I'll happily do what's necessary to make the fix Johannes wants, but
as it's not trivial I want to get a base down.
2. I'll change a few things around as Julian's advised so the patch
set makes a bit more sense. I'll be also killing some inadvertent
white-space changes that were mistakes.
I think my mac80211 patch "mac80211: Fix dangling pointer in
ieee80211_xmit" stands 100% alone and fixes a clear bug. I don't see
any need to delay that one.
It might be a few days before I get these in.
Thanks,
- Steve
From: Thomas Klute <[email protected]>
Compiling with CONFIG_LIBERTAS_THINFIRM_DEBUG=y failed before, this was
the reason.
Signed-off-by: Thomas Klute <[email protected]>
Signed-off-by: Steve deRosier <[email protected]>
---
drivers/net/wireless/libertas_tf/deb_defs.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/libertas_tf/deb_defs.h b/drivers/net/wireless/libertas_tf/deb_defs.h
index e2f009c..99a7478 100644
--- a/drivers/net/wireless/libertas_tf/deb_defs.h
+++ b/drivers/net/wireless/libertas_tf/deb_defs.h
@@ -3,7 +3,7 @@
* global variable declaration.
*/
#ifndef _LBS_DEB_DEFS_H_
-#define _LBS_DEB_EFS_H_
+#define _LBS_DEB_DEFS_H_
#ifndef DRV_NAME
#define DRV_NAME "libertas_tf"
--
1.7.0
More nits:
On Thu, Sep 9, 2010 at 09:25, Steve deRosier <[email protected]> wrote:
> This patch adds tx-feedback to libertas_tf_sdio so that mac80211 rate
> adaptation and other bookkeeping tasks function properly.
>
> Signed-off-by: Steve deRosier <[email protected]>
> ---
> ?drivers/net/wireless/libertas_tf/deb_defs.h | ? ?5 ++
> ?drivers/net/wireless/libertas_tf/if_sdio.c ?| ? 42 +++++++++++------
> ?drivers/net/wireless/libertas_tf/main.c ? ? | ? 65 ++++++++++++++++----------
> ?3 files changed, 72 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/net/wireless/libertas_tf/deb_defs.h b/drivers/net/wireless/libertas_tf/deb_defs.h
> index 99a7478..8e86e11 100644
> --- a/drivers/net/wireless/libertas_tf/deb_defs.h
> +++ b/drivers/net/wireless/libertas_tf/deb_defs.h
> @@ -1063,25 +1077,23 @@ static void if_sdio_interrupt(struct sdio_func *func)
> ? ? ? ?if (ret)
> ? ? ? ? ? ? ? ?goto out;
>
> -// ? ? lbtf_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
> -
> ? ? ? ?sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
> ? ? ? ?if (ret)
> ? ? ? ? ? ? ? ?goto out;
Shouldn't this have been removed instead of being commented in the
patch that commented it?
Thanks,
--
Julian Calaby
Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/
On Thu, 9 Sep 2010 12:13:52 -0700, Steve deRosier <[email protected]>
wrote:
> Before doing any of this stuff (back in patch 1), my driver goes
> through and loads the firmware using the request_firmware() calls
> anyway.
Right.
> In other words, I haven't changed that part. Is the problem
> specifically with my "get the MAC from the hardware before setting up
> mac80211" change, or with waiting on firmware loading?
Well, so previously mac80211 had some support for *not* knowing
the MAC address before setting up all of the mac80211 stuff, but
that broke and I'd like to remove it as well because it advertises
wrong things to userspace. So you need to know the MAC address
before registering with mac80211.
Now, on libertas_tf (correct me if I'm wrong), the firmware has to
be loaded to read the MAC address. So you need to load the firmware
in probe or so, like you do now. Then, however, building it into
the kernel may fail to load the firmware.
> For fun, I just tried compiling the driver into the kernel. Mixed
> results: with two cards on the system, the first card found failed on
> the call to request_firmware() with a -ENOENT, while the second card
> came up just fine. When done as modules, both work fine. So there's
> clearly something to what you're saying. Is it that the filesystem is
> not up and available yet when we try to load the firmware for the
> first card?
Yeah, userspace needs to be up and running to load firmware.
> From looking through the drivers, iwl and ar9170_usb are the only ones
> to use the request_firmware_nowait(). I don't know if those are the
> only mac80211 cards with firmware or not everyone's following the
> model.
Well, not everyone's following the model _yet_ (look at mwl8k for
example), but nobody but libertas_tf needs firmware loaded to know
the MAC address. So they don't have the MAC address issue there.
> Do you have specific pointers of which code I should look at as a
> model, or a better way to solve the problem?
You should probably look at ar9170 or iwlwifi.
> In the short term, can we limit libertas_tf to build as module only
> via Kconfig, and I can add the request_firmware_nowait() as a new
> feature later with a new patch?
Certainly. I just wanted to point it out. This wasn't meant as
a comment that should stop merging of these patches.
> Looking at the examples, it looks
> like the changes for this would be fairly involved and I would prefer
> to break such a change out separately.
Yeah, I tried to do it in libertas_tf at some point last year and
failed miserably :-)
> I'd like to get
> libertas_tf_sdio accepted as a base so I can then do smaller change
> sets going forward. Is that a reasonable plan or just plain silly?
Makes sense to me.
johannes
On Tue, Sep 28, 2010 at 8:24 AM, John W. Linville
<[email protected]> wrote:
> I interpret this as "drop this series -- new series will replace it".
Yes, "drop this series -- new series will replace it". I'll be more
clear next time. :)
>> It might be a few days before I get these in.
>
> Is this still coming?
>
Yes. Due to vacation and other work commitments, I've been delayed on
the patches. I'll try to finish it up and resubmit sometime next
week.
- Steve
This patch adds a method to do a firmware/chip reset to the sdio driver and
attempts to reload the firmware.
Signed-off-by: Steve deRosier <[email protected]>
---
drivers/net/wireless/libertas_tf/if_sdio.c | 40 +++++++++++++++++++++++----
drivers/net/wireless/libertas_tf/main.c | 7 ++++-
2 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/libertas_tf/if_sdio.c b/drivers/net/wireless/libertas_tf/if_sdio.c
index fed5aff..1e72b4c 100644
--- a/drivers/net/wireless/libertas_tf/if_sdio.c
+++ b/drivers/net/wireless/libertas_tf/if_sdio.c
@@ -53,6 +53,8 @@ struct if_sdio_model {
const char *firmware;
};
+extern unsigned int lbtf_reset_fw;
+
static struct if_sdio_model if_sdio_models[] = {
{
/* 8686 */
@@ -673,6 +675,8 @@ out:
return ret;
}
+static void if_sdio_reset_device(struct if_sdio_card *card);
+
static int if_sdio_prog_firmware(struct if_sdio_card *card)
{
int ret;
@@ -691,17 +695,29 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
scratch = if_sdio_read_scratch(card, &ret);
sdio_release_host(card->func);
+ lbtf_deb_sdio("firmware status = %#x\n", scratch);
+ lbtf_deb_sdio("scratch ret = %d\n", ret);
+
if (ret)
goto out;
- lbtf_deb_sdio("firmware status = %#x\n", scratch);
-
if (scratch == IF_SDIO_FIRMWARE_OK) {
lbtf_deb_sdio("firmware already loaded\n");
goto success;
} else if ((card->model == IF_SDIO_MODEL_8686) && (scratch > 0)) {
lbtf_deb_sdio("firmware may be running\n");
- goto success;
+ if( lbtf_reset_fw == 0 ) {
+ goto success;
+ } else {
+ int i = 0;
+ lbtf_deb_sdio("attempting to reset and reload firmware\n");
+
+ if_sdio_reset_device(card);
+ lbtf_reset_fw=0;
+
+ ret = if_sdio_prog_firmware(card);
+ goto out;
+ }
}
ret = if_sdio_prog_helper(card);
@@ -864,7 +880,7 @@ static void if_sdio_reset_device(struct if_sdio_card *card)
if_sdio_host_to_card(card->priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
- msleep(100);
+ msleep(1000);
lbtf_deb_leave(LBTF_DEB_SDIO);
@@ -887,10 +903,12 @@ static void if_sdio_interrupt(struct sdio_func *func)
card = sdio_get_drvdata(func);
cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
+ lbtf_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
+ lbtf_deb_sdio("interrupt ret: 0x%X\n", ret);
if (ret)
goto out;
- lbtf_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
+// lbtf_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
if (ret)
@@ -1061,13 +1079,23 @@ static int if_sdio_probe(struct sdio_func *func,
priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
- priv->hw_reset_device = if_sdio_reset_device;
priv->enable_interrupts = if_sdio_enable_interrupts;
priv->disable_interrupts = if_sdio_disable_interrupts;
/* SD8385 & SD8686 do not have rx_unit. */
card->rx_unit = 0;
+ /*
+ * Enable interrupts now that everything is set up
+ */
+ ret = _if_sdio_enable_interrupts(card);
+ if (ret) {
+ pr_err("Error enabling interrupts: %d", ret);
+ goto err_activate_card;
+ }
+
+ priv->fw_ready = 1;
+
out:
lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 5d34ad9..119d625 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -24,6 +24,10 @@ unsigned int lbtf_debug;
EXPORT_SYMBOL_GPL(lbtf_debug);
module_param_named(libertas_tf_debug, lbtf_debug, int, 0644);
+unsigned int lbtf_reset_fw;
+EXPORT_SYMBOL_GPL(lbtf_reset_fw);
+module_param_named(libertas_tf_reset_fw, lbtf_reset_fw, int, 0644);
+
static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION
#ifdef DEBUG
"-dbg"
@@ -360,7 +364,8 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
return 0;
err_prog_firmware:
-// priv->hw_reset_device(card);
+ if (priv->hw_reset_device)
+ priv->hw_reset_device(card);
lbtf_deb_leave_args(LBTF_DEB_MACOPS, "error programing fw; ret=%d", ret);
return ret;
}
--
1.7.0
Signed-off-by: Steve deRosier <[email protected]>
---
drivers/net/wireless/libertas_tf/libertas_tf.h | 1 +
drivers/net/wireless/libertas_tf/main.c | 5 ++++-
2 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
index db6dd7b..5ccec4d 100644
--- a/drivers/net/wireless/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -104,6 +104,7 @@ enum lbtf_mode {
#define LBS_CMD_BUFFER_SIZE (2 * 1024)
#define MRVDRV_MAX_CHANNEL_SIZE 14
#define MRVDRV_SNAP_HEADER_LEN 8
+#define LBS_NUM_BUFFERS 7
#define LBS_UPLD_SIZE 2312
#define DEV_NAME_LEN 32
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 6c4a1b6..0b03fd5 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -315,8 +315,11 @@ static void lbtf_tx_work(struct work_struct *work)
dev_kfree_skb_any(skb);
skb_dequeue_tail(&priv->tx_skb_buf);
pr_err("TX error: %d", err);
+ } else {
+ if (LBS_NUM_BUFFERS > skb_queue_len(&priv->tx_skb_buf))
+ ieee80211_wake_queues(priv->hw);
+ lbtf_deb_tx("TX success");
}
- lbtf_deb_tx("TX success");
lbtf_deb_leave(LBTF_DEB_MACOPS | LBTF_DEB_TX);
}
--
1.7.0
On Thu, Sep 9, 2010 at 09:25, Steve deRosier <[email protected]> wrote:
>
> Signed-off-by: Steve deRosier <[email protected]>
> ---
> ?drivers/net/wireless/libertas_tf/main.c | ? 18 +++++++++---------
> ?1 files changed, 9 insertions(+), 9 deletions(-)
Shouldn't this be rolled into the previous patch?
Thanks,
--
Julian Calaby
Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/
More nits:
On Thu, Sep 9, 2010 at 09:25, Steve deRosier <[email protected]> wrote:
> mac80211 requires that the MAC address be known and set before calling
> ieee80211_register_hw(). ?If this isn't done, we see bad MAC addresses
> in our packet headers. ?In order to make this happen, I had to restructure
> to have if_sdio_probe load the firmware and get the hardware specs.
>
> I had to add a if_sdio_update_hw_spec function as if_sdio can't use the standard
> command as several required variables aren't setup yet.
> if_sdio_update_hw_spec essentially uses polled io to get the hw spec
> command response from the card.
>
> Signed-off-by: Steve deRosier <[email protected]>
> ---
> ?drivers/net/wireless/libertas_tf/if_sdio.c ? ? | ?263 ++++++++++++++++++++----
> ?drivers/net/wireless/libertas_tf/libertas_tf.h | ? ?2 +-
> ?drivers/net/wireless/libertas_tf/main.c ? ? ? ?| ? 38 +++--
> ?3 files changed, 248 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/net/wireless/libertas_tf/if_sdio.c b/drivers/net/wireless/libertas_tf/if_sdio.c
> index 1e72b4c..189b820 100644
> --- a/drivers/net/wireless/libertas_tf/if_sdio.c
> +++ b/drivers/net/wireless/libertas_tf/if_sdio.c
> @@ -91,12 +91,15 @@ struct if_sdio_card {
> ? ? ? ?u8 ? ? ? ? ? ? ? ? ? ? ?rx_unit;
> ?};
>
> -static int if_sdio_enable_interrupts(struct lbtf_private *priv)
> +static int _if_sdio_enable_interrupts(struct if_sdio_card *card)
> ?{
> - ? ? ? struct if_sdio_card *card = priv->card;
> ? ? ? ?int ret;
>
> ? ? ? ?lbtf_deb_enter(LBTF_DEB_SDIO);
> @@ -109,9 +112,14 @@ static int if_sdio_enable_interrupts(struct lbtf_private *priv)
> ? ? ? ?return (ret);
> ?}
>
> -static int if_sdio_disable_interrupts(struct lbtf_private *priv)
> +static int if_sdio_enable_interrupts(struct lbtf_private *priv)
> ?{
> ? ? ? ?struct if_sdio_card *card = priv->card;
> + ? ? ? return _if_sdio_enable_interrupts(card);
> +}
> +
> +static int _if_sdio_disable_interrupts(struct if_sdio_card *card)
> +{
> ? ? ? ?int ret;
>
> ? ? ? ?lbtf_deb_enter(LBTF_DEB_SDIO);
> @@ -124,6 +132,12 @@ static int if_sdio_disable_interrupts(struct lbtf_private *priv)
> ? ? ? ?return (ret);
> ?}
>
> +static int if_sdio_disable_interrupts(struct lbtf_private *priv)
> +{
> + ? ? ? struct if_sdio_card *card = priv->card;
> + ? ? ? return _if_sdio_disable_interrupts(card);
> +}
> +
> ?/*
> ?* ?For SD8385/SD8686, this function reads firmware status after
> ?* ?the image is downloaded, or reads RX packet length when
Are these changes really necessary here? - It'd probably be cleaner to
change the initial functions to just take the card struct instead? (as
it's always available as priv->card)
I'm guessing you're going to do something with the _* versions of
these functions later, so should this change be there instead?
> @@ -187,7 +201,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
> ? ? ? ?struct lbtf_private *priv = card->priv;
> ? ? ? ?int ret;
> ? ? ? ?unsigned long flags;
> - ? ? ? u8 i;
>
> ? ? ? ?lbtf_deb_enter(LBTF_DEB_SDIO);
>
Shouldn't this be elsewhere (maybe rolled into patch #1?)
> @@ -709,7 +726,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
> ? ? ? ? ? ? ? ?if( lbtf_reset_fw == 0 ) {
> ? ? ? ? ? ? ? ? ? ? ? ?goto success;
> ? ? ? ? ? ? ? ?} else {
> - ? ? ? ? ? ? ? ? ? ? ? int i = 0;
> ? ? ? ? ? ? ? ? ? ? ? ?lbtf_deb_sdio("attempting to reset and reload firmware\n");
>
> ? ? ? ? ? ? ? ? ? ? ? ?if_sdio_reset_device(card);
Ditto.
> @@ -846,7 +863,6 @@ static int if_sdio_enter_deep_sleep(struct lbtf_private *priv)
>
> ?static int if_sdio_exit_deep_sleep(struct lbtf_private *priv)
> ?{
> - ? ? ? struct if_sdio_card *card = priv->card;
> ? ? ? ?int ret = -1;
>
> ? ? ? ?lbtf_deb_enter(LBTF_DEB_SDIO);
Ditto.
> @@ -857,14 +873,12 @@ static int if_sdio_exit_deep_sleep(struct lbtf_private *priv)
>
> ?static int if_sdio_reset_deep_sleep_wakeup(struct lbtf_private *priv)
> ?{
> - ? ? ? struct if_sdio_card *card = priv->card;
> ? ? ? ?int ret = -1;
>
> ? ? ? ?lbtf_deb_enter(LBTF_DEB_SDIO);
>
> ? ? ? ?lbtf_deb_leave_args(LBTF_DEB_SDIO, "ret %d", ret);
> ? ? ? ?return ret;
> -
> ?}
>
> ?static void if_sdio_reset_device(struct if_sdio_card *card)
Ditto.
> diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
> index 119d625..14ce1bc 100644
> --- a/drivers/net/wireless/libertas_tf/main.c
> +++ b/drivers/net/wireless/libertas_tf/main.c
> @@ -150,14 +150,15 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
> ? ? ? ?int ret = -1;
>
> ? ? ? ?lbtf_deb_enter(LBTF_DEB_FW);
> +
> ? ? ? ?/*
> ? ? ? ? * Read priv address from HW
> ? ? ? ? */
> ? ? ? ?memset(priv->current_addr, 0xff, ETH_ALEN);
> ? ? ? ?ret = lbtf_update_hw_spec(priv);
> ? ? ? ?if (ret) {
> - ? ? ? ? ? ? ? ret = -1;
> - ? ? ? ? ? ? ? goto done;
> + ? ? ? ? ? ? ? ? ?ret = -1;
> + ? ? ? ? ? ? ? ? ?goto done;
> ? ? ? ?}
>
> ? ? ? ?lbtf_set_mac_control(priv);
Whitespace change noise.
> @@ -165,6 +166,7 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
> ? ? ? ?lbtf_set_mode(priv, LBTF_PASSIVE_MODE);
>
> ? ? ? ?ret = 0;
> +
> ?done:
> ? ? ? ?lbtf_deb_leave_args(LBTF_DEB_FW, "ret: %d", ret);
> ? ? ? ?return ret;
And again.
> @@ -433,6 +437,7 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
> ? ? ? ? ? ? ? ?lbtf_set_mac_address(priv, (u8 *) vif->addr);
> ? ? ? ?}
>
> +
> ? ? ? ?lbtf_deb_leave(LBTF_DEB_MACOPS);
> ? ? ? ?return 0;
> ?}
And again.
Thanks,
--
Julian Calaby
Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/
On Wed, Sep 8, 2010 at 7:21 PM, Julian Calaby <[email protected]> wrote:
> Also, it appears that this patch does two things, update the beacon
> code and add some debugging. You may want to separate this into two
> patches.
Well, the debugging was added _for_ the beacon code and to debug the
beacon code either here in the driver or the interaction with new
beacon code in the firmware.
Thanks,
- Steve