* [PATCH 6/6] orinoco_usb: implement fw download
From: David Kilroy @ 2010-05-01 13:05 UTC (permalink / raw)
To: linux-wireless; +Cc: orinoco-devel, linville, David Kilroy
In-Reply-To: <1272719143-26171-1-git-send-email-kilroyd@googlemail.com>
This involves some refactorring of the common fw download code to
substitute ezusb versions of various functions.
Note that WPA-enabled firmwares (9.xx series) will not work fully with
orinoco_usb yet.
Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
drivers/net/wireless/orinoco/fw.c | 8 +-
drivers/net/wireless/orinoco/hermes.c | 208 ++++++++++++++++++++++++
drivers/net/wireless/orinoco/hermes.h | 7 +
drivers/net/wireless/orinoco/hermes_dld.c | 243 +--------------------------
drivers/net/wireless/orinoco/orinoco_usb.c | 120 ++++++++++++++
drivers/net/wireless/orinoco/spectrum_cs.c | 1 +
6 files changed, 349 insertions(+), 238 deletions(-)
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 4c99240..3e1947d 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -122,7 +122,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
/* Read current plug data */
- err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
+ err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
dev_dbg(dev, "Read PDA returned %d\n", err);
if (err)
goto free;
@@ -149,7 +149,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
}
/* Enable aux port to allow programming */
- err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
+ err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point));
dev_dbg(dev, "Program init returned %d\n", err);
if (err != 0)
goto abort;
@@ -177,7 +177,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
goto abort;
/* Tell card we've finished */
- err = hermesi_program_end(hw);
+ err = hw->ops->program_end(hw);
dev_dbg(dev, "Program end returned %d\n", err);
if (err != 0)
goto abort;
@@ -224,7 +224,7 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
if (!pda)
return -ENOMEM;
- ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
+ ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
if (ret)
goto free;
}
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index 845693f..6c6a23e 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -52,6 +52,26 @@
#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
/*
+ * AUX port access. To unlock the AUX port write the access keys to the
+ * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
+ * register. Then read it and make sure it's HERMES_AUX_ENABLED.
+ */
+#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
+#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
+#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
+#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
+
+#define HERMES_AUX_PW0 0xFE01
+#define HERMES_AUX_PW1 0xDC23
+#define HERMES_AUX_PW2 0xBA45
+
+/* HERMES_CMD_DOWNLD */
+#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
+
+/*
* Debugging helpers
*/
@@ -170,6 +190,7 @@ void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
hw->iobase = address;
hw->reg_spacing = reg_spacing;
hw->inten = 0x0;
+ hw->eeprom_pda = false;
hw->ops = &hermes_ops_local;
}
EXPORT_SYMBOL(hermes_struct_init);
@@ -529,6 +550,189 @@ static int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
return err;
}
+/*** Hermes AUX control ***/
+
+static inline void
+hermes_aux_setaddr(hermes_t *hw, u32 addr)
+{
+ hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
+ hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
+}
+
+static inline int
+hermes_aux_control(hermes_t *hw, int enabled)
+{
+ int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
+ int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
+ int i;
+
+ /* Already open? */
+ if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
+ return 0;
+
+ hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
+ hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
+ hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
+ hermes_write_reg(hw, HERMES_CONTROL, action);
+
+ for (i = 0; i < 20; i++) {
+ udelay(10);
+ if (hermes_read_reg(hw, HERMES_CONTROL) ==
+ desired_state)
+ return 0;
+ }
+
+ return -EBUSY;
+}
+
+/*** Hermes programming ***/
+
+/* About to start programming data (Hermes I)
+ * offset is the entry point
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+static int hermesi_program_init(hermes_t *hw, u32 offset)
+{
+ int err;
+
+ /* Disable interrupts?*/
+ /*hw->inten = 0x0;*/
+ /*hermes_write_regn(hw, INTEN, 0);*/
+ /*hermes_set_irqmask(hw, 0);*/
+
+ /* Acknowledge any outstanding command */
+ hermes_write_regn(hw, EVACK, 0xFFFF);
+
+ /* Using init_cmd_wait rather than cmd_wait */
+ err = hw->ops->init_cmd_wait(hw,
+ 0x0100 | HERMES_CMD_INIT,
+ 0, 0, 0, NULL);
+ if (err)
+ return err;
+
+ err = hw->ops->init_cmd_wait(hw,
+ 0x0000 | HERMES_CMD_INIT,
+ 0, 0, 0, NULL);
+ if (err)
+ return err;
+
+ err = hermes_aux_control(hw, 1);
+ pr_debug("AUX enable returned %d\n", err);
+
+ if (err)
+ return err;
+
+ pr_debug("Enabling volatile, EP 0x%08x\n", offset);
+ err = hw->ops->init_cmd_wait(hw,
+ HERMES_PROGRAM_ENABLE_VOLATILE,
+ offset & 0xFFFFu,
+ offset >> 16,
+ 0,
+ NULL);
+ pr_debug("PROGRAM_ENABLE returned %d\n", err);
+
+ return err;
+}
+
+/* Done programming data (Hermes I)
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+static int hermesi_program_end(hermes_t *hw)
+{
+ struct hermes_response resp;
+ int rc = 0;
+ int err;
+
+ rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
+
+ pr_debug("PROGRAM_DISABLE returned %d, "
+ "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+ rc, resp.resp0, resp.resp1, resp.resp2);
+
+ if ((rc == 0) &&
+ ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
+ rc = -EIO;
+
+ err = hermes_aux_control(hw, 0);
+ pr_debug("AUX disable returned %d\n", err);
+
+ /* Acknowledge any outstanding command */
+ hermes_write_regn(hw, EVACK, 0xFFFF);
+
+ /* Reinitialise, ignoring return */
+ (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
+ 0, 0, 0, NULL);
+
+ return rc ? rc : err;
+}
+
+static int hermes_program_bytes(struct hermes *hw, const char *data,
+ u32 addr, u32 len)
+{
+ /* wl lkm splits the programming into chunks of 2000 bytes.
+ * This restriction appears to come from USB. The PCMCIA
+ * adapters can program the whole lot in one go */
+ hermes_aux_setaddr(hw, addr);
+ hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
+ return 0;
+}
+
+/* Read PDA from the adapter */
+static int hermes_read_pda(hermes_t *hw, __le16 *pda, u32 pda_addr, u16 pda_len)
+{
+ int ret;
+ u16 pda_size;
+ u16 data_len = pda_len;
+ __le16 *data = pda;
+
+ if (hw->eeprom_pda) {
+ /* PDA of spectrum symbol is in eeprom */
+
+ /* Issue command to read EEPROM */
+ ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+ if (ret)
+ return ret;
+ } else {
+ /* wl_lkm does not include PDA size in the PDA area.
+ * We will pad the information into pda, so other routines
+ * don't have to be modified */
+ pda[0] = cpu_to_le16(pda_len - 2);
+ /* Includes CFG_PROD_DATA but not itself */
+ pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+ data_len = pda_len - 4;
+ data = pda + 2;
+ }
+
+ /* Open auxiliary port */
+ ret = hermes_aux_control(hw, 1);
+ pr_debug("AUX enable returned %d\n", ret);
+ if (ret)
+ return ret;
+
+ /* Read PDA */
+ hermes_aux_setaddr(hw, pda_addr);
+ hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
+
+ /* Close aux port */
+ ret = hermes_aux_control(hw, 0);
+ pr_debug("AUX disable returned %d\n", ret);
+
+ /* Check PDA length */
+ pda_size = le16_to_cpu(pda[0]);
+ pr_debug("Actual PDA length %d, Max allowed %d\n",
+ pda_size, pda_len);
+ if (pda_size > pda_len)
+ return -EINVAL;
+
+ return 0;
+}
+
static void hermes_lock_irqsave(spinlock_t *lock,
unsigned long *flags) __acquires(lock)
{
@@ -561,6 +765,10 @@ static const struct hermes_ops hermes_ops_local = {
.write_ltv = hermes_write_ltv,
.bap_pread = hermes_bap_pread,
.bap_pwrite = hermes_bap_pwrite,
+ .read_pda = hermes_read_pda,
+ .program_init = hermesi_program_init,
+ .program_end = hermesi_program_end,
+ .program = hermes_program_bytes,
.lock_irqsave = hermes_lock_irqsave,
.unlock_irqrestore = hermes_unlock_irqrestore,
.lock_irq = hermes_lock_irq,
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index aed14ff..9ca34e7 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -393,6 +393,12 @@ struct hermes_ops {
u16 id, u16 offset);
int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
int len, u16 id, u16 offset);
+ int (*read_pda)(struct hermes *hw, __le16 *pda,
+ u32 pda_addr, u16 pda_len);
+ int (*program_init)(struct hermes *hw, u32 entry_point);
+ int (*program_end)(struct hermes *hw);
+ int (*program)(struct hermes *hw, const char *buf,
+ u32 addr, u32 len);
void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags);
void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags);
void (*lock_irq)(spinlock_t *lock);
@@ -406,6 +412,7 @@ typedef struct hermes {
#define HERMES_16BIT_REGSPACING 0
#define HERMES_32BIT_REGSPACING 1
u16 inten; /* Which interrupts should be enabled? */
+ bool eeprom_pda;
const struct hermes_ops *ops;
void *priv;
} hermes_t;
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index 8f22e20..6da85e7 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -46,37 +46,11 @@
#define PFX "hermes_dld: "
-/*
- * AUX port access. To unlock the AUX port write the access keys to the
- * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
- * register. Then read it and make sure it's HERMES_AUX_ENABLED.
- */
-#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
-#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
-#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
-#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
-
-#define HERMES_AUX_PW0 0xFE01
-#define HERMES_AUX_PW1 0xDC23
-#define HERMES_AUX_PW2 0xBA45
-
-/* HERMES_CMD_DOWNLD */
-#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
-
/* End markers used in dblocks */
#define PDI_END 0x00000000 /* End of PDA */
#define BLOCK_END 0xFFFFFFFF /* Last image block */
#define TEXT_END 0x1A /* End of text header */
-/* Limit the amout we try to download in a single shot.
- * Size is in bytes.
- */
-#define MAX_DL_SIZE 1024
-#define LIMIT_PROGRAM_SIZE 0
-
/*
* The following structures have little-endian fields denoted by
* the leading underscore. Don't access them directly - use inline
@@ -165,41 +139,6 @@ pdi_len(const struct pdi *pdi)
return 2 * (le16_to_cpu(pdi->len) - 1);
}
-/*** Hermes AUX control ***/
-
-static inline void
-hermes_aux_setaddr(hermes_t *hw, u32 addr)
-{
- hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
- hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
-}
-
-static inline int
-hermes_aux_control(hermes_t *hw, int enabled)
-{
- int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
- int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
- int i;
-
- /* Already open? */
- if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
- return 0;
-
- hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
- hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
- hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
- hermes_write_reg(hw, HERMES_CONTROL, action);
-
- for (i = 0; i < 20; i++) {
- udelay(10);
- if (hermes_read_reg(hw, HERMES_CONTROL) ==
- desired_state)
- return 0;
- }
-
- return -EBUSY;
-}
-
/*** Plug Data Functions ***/
/*
@@ -271,62 +210,7 @@ hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr,
return -EINVAL;
/* do the actual plugging */
- hermes_aux_setaddr(hw, pdr_addr(pdr));
- hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
-
- return 0;
-}
-
-/* Read PDA from the adapter */
-int hermes_read_pda(hermes_t *hw,
- __le16 *pda,
- u32 pda_addr,
- u16 pda_len,
- int use_eeprom) /* can we get this into hw? */
-{
- int ret;
- u16 pda_size;
- u16 data_len = pda_len;
- __le16 *data = pda;
-
- if (use_eeprom) {
- /* PDA of spectrum symbol is in eeprom */
-
- /* Issue command to read EEPROM */
- ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
- if (ret)
- return ret;
- } else {
- /* wl_lkm does not include PDA size in the PDA area.
- * We will pad the information into pda, so other routines
- * don't have to be modified */
- pda[0] = cpu_to_le16(pda_len - 2);
- /* Includes CFG_PROD_DATA but not itself */
- pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
- data_len = pda_len - 4;
- data = pda + 2;
- }
-
- /* Open auxiliary port */
- ret = hermes_aux_control(hw, 1);
- pr_debug(PFX "AUX enable returned %d\n", ret);
- if (ret)
- return ret;
-
- /* read PDA from EEPROM */
- hermes_aux_setaddr(hw, pda_addr);
- hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
-
- /* Close aux port */
- ret = hermes_aux_control(hw, 0);
- pr_debug(PFX "AUX disable returned %d\n", ret);
-
- /* Check PDA length */
- pda_size = le16_to_cpu(pda[0]);
- pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
- pda_size, pda_len);
- if (pda_size > pda_len)
- return -EINVAL;
+ hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
return 0;
}
@@ -389,101 +273,13 @@ hermes_blocks_length(const char *first_block, const void *end)
/*** Hermes programming ***/
-/* About to start programming data (Hermes I)
- * offset is the entry point
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_init(hermes_t *hw, u32 offset)
-{
- int err;
-
- /* Disable interrupts?*/
- /*hw->inten = 0x0;*/
- /*hermes_write_regn(hw, INTEN, 0);*/
- /*hermes_set_irqmask(hw, 0);*/
-
- /* Acknowledge any outstanding command */
- hermes_write_regn(hw, EVACK, 0xFFFF);
-
- /* Using init_cmd_wait rather than cmd_wait */
- err = hw->ops->init_cmd_wait(hw,
- 0x0100 | HERMES_CMD_INIT,
- 0, 0, 0, NULL);
- if (err)
- return err;
-
- err = hw->ops->init_cmd_wait(hw,
- 0x0000 | HERMES_CMD_INIT,
- 0, 0, 0, NULL);
- if (err)
- return err;
-
- err = hermes_aux_control(hw, 1);
- pr_debug(PFX "AUX enable returned %d\n", err);
-
- if (err)
- return err;
-
- pr_debug(PFX "Enabling volatile, EP 0x%08x\n", offset);
- err = hw->ops->init_cmd_wait(hw,
- HERMES_PROGRAM_ENABLE_VOLATILE,
- offset & 0xFFFFu,
- offset >> 16,
- 0,
- NULL);
- pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
-
- return err;
-}
-
-/* Done programming data (Hermes I)
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_end(hermes_t *hw)
-{
- struct hermes_response resp;
- int rc = 0;
- int err;
-
- rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
-
- pr_debug(PFX "PROGRAM_DISABLE returned %d, "
- "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
- rc, resp.resp0, resp.resp1, resp.resp2);
-
- if ((rc == 0) &&
- ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
- rc = -EIO;
-
- err = hermes_aux_control(hw, 0);
- pr_debug(PFX "AUX disable returned %d\n", err);
-
- /* Acknowledge any outstanding command */
- hermes_write_regn(hw, EVACK, 0xFFFF);
-
- /* Reinitialise, ignoring return */
- (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
- 0, 0, 0, NULL);
-
- return rc ? rc : err;
-}
-
/* Program the data blocks */
int hermes_program(hermes_t *hw, const char *first_block, const void *end)
{
const struct dblock *blk;
u32 blkaddr;
u32 blklen;
-#if LIMIT_PROGRAM_SIZE
- u32 addr;
- u32 len;
-#endif
+ int err = 0;
blk = (const struct dblock *) first_block;
@@ -498,30 +294,10 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
pr_debug(PFX "Programming block of length %d "
"to address 0x%08x\n", blklen, blkaddr);
-#if !LIMIT_PROGRAM_SIZE
- /* wl_lkm driver splits this into writes of 2000 bytes */
- hermes_aux_setaddr(hw, blkaddr);
- hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
- blklen);
-#else
- len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
- addr = blkaddr;
-
- while (addr < (blkaddr + blklen)) {
- pr_debug(PFX "Programming subblock of length %d "
- "to address 0x%08x. Data @ %p\n",
- len, addr, &blk->data[addr - blkaddr]);
-
- hermes_aux_setaddr(hw, addr);
- hermes_write_bytes(hw, HERMES_AUXDATA,
- &blk->data[addr - blkaddr],
- len);
-
- addr += len;
- len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
- (blkaddr + blklen - addr) : MAX_DL_SIZE;
- }
-#endif
+ err = hw->ops->program(hw, blk->data, blkaddr, blklen);
+ if (err)
+ break;
+
blk = (const struct dblock *) &blk->data[blklen];
if ((void *) blk > (end - sizeof(*blk)))
@@ -530,7 +306,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
blkaddr = dblock_addr(blk);
blklen = dblock_len(blk);
}
- return 0;
+ return err;
}
/*** Default plugging data for Hermes I ***/
@@ -690,9 +466,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
if ((pdi_len(pdi) == pdr_len(pdr)) &&
((void *) pdi->data + pdi_len(pdi) < pda_end)) {
/* do the actual plugging */
- hermes_aux_setaddr(hw, pdr_addr(pdr));
- hermes_write_bytes(hw, HERMES_AUXDATA,
- pdi->data, pdi_len(pdi));
+ hw->ops->program(hw, pdi->data, pdr_addr(pdr),
+ pdi_len(pdi));
}
}
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 8e1b31c..e220933 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -184,6 +184,11 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
#define EZUSB_RID_RX 0x0701
#define EZUSB_RID_INIT1 0x0702
#define EZUSB_RID_ACK 0x0710
+#define EZUSB_RID_READ_PDA 0x0800
+#define EZUSB_RID_PROG_INIT 0x0852
+#define EZUSB_RID_PROG_SET_ADDR 0x0853
+#define EZUSB_RID_PROG_BYTES 0x0854
+#define EZUSB_RID_PROG_END 0x0855
#define EZUSB_RID_DOCMD 0x0860
/* Recognize info frames */
@@ -198,6 +203,8 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
#define BULK_BUF_SIZE 2048
+#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet))
+
#define FW_BUF_SIZE 64
#define FW_VAR_OFFSET_PTR 0x359
#define FW_VAR_VALUE 0
@@ -1077,6 +1084,115 @@ static int ezusb_bap_pread(struct hermes *hw, int bap,
return 0;
}
+static int ezusb_read_pda(struct hermes *hw, __le16 *pda,
+ u32 pda_addr, u16 pda_len)
+{
+ struct ezusb_priv *upriv = hw->priv;
+ struct request_context *ctx;
+ __le16 data[] = {
+ cpu_to_le16(pda_addr & 0xffff),
+ cpu_to_le16(pda_len - 4)
+ };
+ ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA);
+ if (!ctx)
+ return -ENOMEM;
+
+ /* wl_lkm does not include PDA size in the PDA area.
+ * We will pad the information into pda, so other routines
+ * don't have to be modified */
+ pda[0] = cpu_to_le16(pda_len - 2);
+ /* Includes CFG_PROD_DATA but not itself */
+ pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+
+ return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+ EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4,
+ NULL);
+}
+
+static int ezusb_program_init(struct hermes *hw, u32 entry_point)
+{
+ struct ezusb_priv *upriv = hw->priv;
+ struct request_context *ctx;
+ __le32 data = cpu_to_le32(entry_point);
+
+ ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK);
+ if (!ctx)
+ return -ENOMEM;
+
+ return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+ EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program_end(struct hermes *hw)
+{
+ struct ezusb_priv *upriv = hw->priv;
+ struct request_context *ctx;
+
+ ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK);
+ if (!ctx)
+ return -ENOMEM;
+
+ return ezusb_access_ltv(upriv, ctx, 0, NULL,
+ EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program_bytes(struct hermes *hw, const char *buf,
+ u32 addr, u32 len)
+{
+ struct ezusb_priv *upriv = hw->priv;
+ struct request_context *ctx;
+ __le32 data = cpu_to_le32(addr);
+ int err;
+
+ ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK);
+ if (!ctx)
+ return -ENOMEM;
+
+ err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+ EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+ if (err)
+ return err;
+
+ ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK);
+ if (!ctx)
+ return -ENOMEM;
+
+ return ezusb_access_ltv(upriv, ctx, len, buf,
+ EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program(struct hermes *hw, const char *buf,
+ u32 addr, u32 len)
+{
+ u32 ch_addr;
+ u32 ch_len;
+ int err = 0;
+
+ /* We can only send 2048 bytes out of the bulk xmit at a time,
+ * so we have to split any programming into chunks of <2048
+ * bytes. */
+
+ ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE;
+ ch_addr = addr;
+
+ while (ch_addr < (addr + len)) {
+ pr_debug("Programming subblock of length %d "
+ "to address 0x%08x. Data @ %p\n",
+ ch_len, ch_addr, &buf[ch_addr - addr]);
+
+ err = ezusb_program_bytes(hw, &buf[ch_addr - addr],
+ ch_addr, ch_len);
+ if (err)
+ break;
+
+ ch_addr += ch_len;
+ ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ?
+ (addr + len - ch_addr) : MAX_DL_SIZE;
+ }
+
+ return err;
+}
+
static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct orinoco_private *priv = ndev_priv(dev);
@@ -1440,6 +1556,10 @@ static const struct hermes_ops ezusb_ops = {
.read_ltv = ezusb_read_ltv,
.write_ltv = ezusb_write_ltv,
.bap_pread = ezusb_bap_pread,
+ .read_pda = ezusb_read_pda,
+ .program_init = ezusb_program_init,
+ .program_end = ezusb_program_end,
+ .program = ezusb_program,
.lock_irqsave = ezusb_lock_irqsave,
.unlock_irqrestore = ezusb_unlock_irqrestore,
.lock_irq = ezusb_lock_irq,
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index b4f68ef..9b1af49 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -349,6 +349,7 @@ spectrum_cs_config(struct pcmcia_device *link)
goto failed;
hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+ hw->eeprom_pda = true;
/*
* This actually configures the PCMCIA socket -- setting up
--
1.6.4.4
^ permalink raw reply related
* Re: BCM4312 802.11b/g LP-PHY (rev 01) dma & led problems
From: Gábor Stefanik @ 2010-05-01 16:04 UTC (permalink / raw)
To: Philippe De Muyter
Cc: Larry Finger, Matthew Garrett, Dan Williams, linux-wireless
In-Reply-To: <20100501121706.GA32719@frolo.macqel>
On Sat, May 1, 2010 at 2:17 PM, Philippe De Muyter <phdm@macqel.be> wrote:
> This is a followup on my attempt to use b43 (now from 2.6.34-rc6) on
> a HP Pavilion dv6-1300sb.
>
> With 2.6.34-rc6, I have not had any boot problem (blocking around ssb/b43)
> so far.
>
> But, dma mode gives an error (like before) and driver now switches
> automatically to PIO mode (new).
>
> [ 89.830222] device mon0 entered promiscuous mode
> [ 101.965896] NOHZ: local_softirq_pending 08
> [ 101.969431] NOHZ: local_softirq_pending 08
> [ 101.972230] NOHZ: local_softirq_pending 08
> [ 101.975041] NOHZ: local_softirq_pending 08
> [ 101.977771] NOHZ: local_softirq_pending 08
> [ 101.984651] NOHZ: local_softirq_pending 08
> [ 101.988808] NOHZ: local_softirq_pending 08
> [ 101.991562] NOHZ: local_softirq_pending 08
> [ 101.994363] NOHZ: local_softirq_pending 08
> [ 101.997116] NOHZ: local_softirq_pending 08
> [ 111.816257] hpet1: lost 1 rtc interrupts
> [ 112.131040] hpet1: lost 1 rtc interrupts
> [ 112.133343] hpet1: lost 1 rtc interrupts
> [ 112.135528] hpet1: lost 1 rtc interrupts
> [ 112.137722] hpet1: lost 1 rtc interrupts
> [ 112.139911] hpet1: lost 1 rtc interrupts
> [ 112.142089] hpet1: lost 1 rtc interrupts
> [ 112.146370] hpet1: lost 1 rtc interrupts
> [ 112.150637] hpet1: lost 1 rtc interrupts
> [ 112.152849] hpet1: lost 1 rtc interrupts
> [ 113.100932] b43-phy0 ERROR: Fatal DMA error: 0x00000000, 0x00000800, 0x00000000, 0x00000000, 0x00000000, 0x00000000
> [ 113.100949] b43-phy0 ERROR: This device does not support DMA on your system. Please use PIO instead.
> [ 113.100957] b43-phy0: Controller RESET (DMA error) ...
> [ 113.336119] b43-phy0: Loading firmware version 478.104 (2008-07-01 00:50:23)
> [ 118.853353] b43-phy0: Controller restarted
>
> During the switch, the led switches from blue to red and returns to blue
> after some seconds. Touching the led switches the hardware blocking on
> and off, but the led color does not change.
>
> I then tried with the broadcom supplied hybrid driver, and there the
> touch/led functionality works as expected : led is red whenever
> I touch the button (enabling hardware blocking) or when I issue
> a rfkill block 0 (enabling software blocking). Led is blue only when
> both blocking are disabled. But, hybrid driver does not give monitor
> functionality :( (and of course, also no injection).
> [10703.172776] wl: module license 'unspecified' taints kernel.
> [10703.172791] Disabling lock debugging due to kernel taint
> [10703.174286] wl: Unknown symbol lib80211_get_crypto_ops
> [10778.692746] lib80211: common routines for IEEE802.11 drivers
> [10778.692759] lib80211_crypt: registered algorithm 'NULL'
> [10783.823152] wl 0000:02:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
> [10783.823188] wl 0000:02:00.0: setting latency timer to 64
> [10783.921236] lib80211_crypt: registered algorithm 'TKIP'
> [10783.921623] eth1: Broadcom BCM4315 802.11 Hybrid Wireless Controller 5.60.48.36
>
> Any idea on what I could do to debug more / fix the dma and led problems ?
Nothing, unfortunately. We are working on this issue; apparently some
workarounds are missing from our PCI-E init implementation.
>
> Philippe
>
> Here the output of lspci -nvv for that chip :
>
> linux-m1ew:~ # lspci -nvv -s 02:00.0
> 02:00.0 0280: 14e4:4315 (rev 01)
> Subsystem: 103c:1508
> Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
> Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
> Latency: 0, Cache Line Size: 64 bytes
> Interrupt: pin A routed to IRQ 16
> Region 0: Memory at d9000000 (64-bit, non-prefetchable) [size=16K]
> Capabilities: [40] Power Management version 3
> Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
> Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=2 PME-
> Capabilities: [58] Vendor Specific Information: Len=78 <?>
> Capabilities: [e8] MSI: Enable- Count=1/1 Maskable- 64bit+
> Address: 0000000000000000 Data: 0000
> Capabilities: [d0] Express (v1) Endpoint, MSI 00
> DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <4us, L1 unlimited
> ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
> DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
> RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
> MaxPayload 128 bytes, MaxReadReq 128 bytes
> DevSta: CorrErr+ UncorrErr- FatalErr- UnsuppReq+ AuxPwr- TransPend-
> LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <4us, L1 <64us
> ClockPM+ Surprise- LLActRep- BwNot-
> LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled- Retrain- CommClk+
> ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
> LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
> Capabilities: [100 v1] Advanced Error Reporting
> UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
> UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
> UESvrt: DLP+ SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
> CESta: RxErr+ BadTLP- BadDLLP- Rollover- Timeout+ NonFatalErr+
> CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
> AERCap: First Error Pointer: 14, GenCap+ CGenEn- ChkCap+ ChkEn-
> Capabilities: [13c v1] Virtual Channel
> Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
> Arb: Fixed- WRR32- WRR64- WRR128-
> Ctrl: ArbSelect=Fixed
> Status: InProgress-
> VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
> Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
> Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
> Status: NegoPending- InProgress-
> Capabilities: [160 v1] Device Serial Number 00-00-00-ff-ff-00-ff-ff
> Capabilities: [16c v1] Power Budgeting <?>
> Kernel driver in use: b43-pci-bridge
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
^ permalink raw reply
* [PATCH] ar9170usb: remove deprecated aggregation code
From: Christian Lamparter @ 2010-05-01 16:18 UTC (permalink / raw)
To: linux-wireless; +Cc: linville
This patch removes the incomplete AMPDU implementation in ar9170usb.
The code in question is:
* too big and complex (more than 550 SLOC.)
This is enough to qualify for a new separate code file!
* unbalanced quantity & quality
over-engineered areas like:
* xmit scheduling and queuing frames for multiple HT peers
* redundant frame sorting
are confronted by gaping holes:
* accurate transmission feedback
* firmware error-handling and device reset
* HT rate control algorithm
* error-prone
Since its inclusion, hardly anything was done to fix
any of the outlined flaws from the initial commit message.
=> This also indicates poor maintainability.
* relies heavily on several spinlocks.
As a result of this shortcomings, the code is slow and does not
even support the most basic 11n requirement: HT station mode.
Therefore, I request to purge my heap of **** from the kernel:
"ar9170: implement transmit aggregation".
The next item on the agenda is: (re-)start from scratch with
an adequate design to accommodate the special requirements
and features of the available frameworks and tools.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
Note:
While this 'generic' ampdu implementation has failed to deliver
for ar9170usb, it is performing rather well in a different project
called" carl9170". Don't confuse these two.
---
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index dc662b7..4f845f8 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -109,41 +109,6 @@ struct ar9170_rxstream_mpdu_merge {
bool has_plcp;
};
-#define AR9170_NUM_TID 16
-#define WME_BA_BMP_SIZE 64
-#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
-
-#define WME_AC_BE 2
-#define WME_AC_BK 3
-#define WME_AC_VI 1
-#define WME_AC_VO 0
-
-#define TID_TO_WME_AC(_tid) \
- ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
- (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
- (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
- WME_AC_VO)
-
-#define BAW_WITHIN(_start, _bawsz, _seqno) \
- ((((_seqno) - (_start)) & 0xfff) < (_bawsz))
-
-enum ar9170_tid_state {
- AR9170_TID_STATE_INVALID,
- AR9170_TID_STATE_SHUTDOWN,
- AR9170_TID_STATE_PROGRESS,
- AR9170_TID_STATE_COMPLETE,
-};
-
-struct ar9170_sta_tid {
- struct list_head list;
- struct sk_buff_head queue;
- u8 addr[ETH_ALEN];
- u16 ssn;
- u16 tid;
- enum ar9170_tid_state state;
- bool active;
-};
-
struct ar9170_tx_queue_stats {
unsigned int len;
unsigned int limit;
@@ -152,14 +117,11 @@ struct ar9170_tx_queue_stats {
#define AR9170_QUEUE_TIMEOUT 64
#define AR9170_TX_TIMEOUT 8
-#define AR9170_BA_TIMEOUT 4
#define AR9170_JANITOR_DELAY 128
#define AR9170_TX_INVALID_RATE 0xffffffff
-#define AR9170_NUM_TX_STATUS 128
-#define AR9170_NUM_TX_AGG_MAX 30
-#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH
-#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10)
+#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH
+#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10)
struct ar9170 {
struct ieee80211_hw *hw;
@@ -234,11 +196,6 @@ struct ar9170 {
struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
struct delayed_work tx_janitor;
- /* tx ampdu */
- struct sk_buff_head tx_status_ampdu;
- spinlock_t tx_ampdu_list_lock;
- struct list_head tx_ampdu_list;
- atomic_t tx_ampdu_pending;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
@@ -250,11 +207,6 @@ struct ar9170 {
u8 global_ampdu_factor;
};
-struct ar9170_sta_info {
- struct ar9170_sta_tid agg[AR9170_NUM_TID];
- unsigned int ampdu_max_len;
-};
-
struct ar9170_tx_info {
unsigned long timeout;
};
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index f57e7c6..b68f317 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -50,10 +50,6 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
-static int modparam_ht;
-module_param_named(ht, modparam_ht, bool, S_IRUGO);
-MODULE_PARM_DESC(ht, "enable MPDU aggregation.");
-
#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \
.bitrate = (_bitrate), \
.flags = (_flags), \
@@ -182,7 +178,6 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
};
static void ar9170_tx(struct ar9170 *ar);
-static bool ar9170_tx_ampdu(struct ar9170 *ar);
static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
{
@@ -195,21 +190,7 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb)
return ar9170_get_seq_h((void *) txc->frame_data);
}
-static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr)
-{
- return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
-}
-
-static inline u16 ar9170_get_tid(struct sk_buff *skb)
-{
- struct ar9170_tx_control *txc = (void *) skb->data;
- return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data);
-}
-
-#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff)
-#define GET_NEXT_SEQ_FROM_SKB(skb) (GET_NEXT_SEQ(ar9170_get_seq(skb)))
-
-#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG)
+#ifdef AR9170_QUEUE_DEBUG
static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
@@ -244,7 +225,7 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
"mismatch %d != %d\n", skb_queue_len(queue), i);
printk(KERN_DEBUG "---[ end ]---\n");
}
-#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
+#endif /* AR9170_QUEUE_DEBUG */
#ifdef AR9170_QUEUE_DEBUG
static void ar9170_dump_txqueue(struct ar9170 *ar,
@@ -275,20 +256,6 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
}
#endif /* AR9170_QUEUE_STOP_DEBUG */
-#ifdef AR9170_TXAGG_DEBUG
-static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
- printk(KERN_DEBUG "%s: A-MPDU tx_status queue =>\n",
- wiphy_name(ar->hw->wiphy));
- __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
- spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
-}
-
-#endif /* AR9170_TXAGG_DEBUG */
-
/* caller must guarantee exclusive access for _bin_ queue. */
static void ar9170_recycle_expired(struct ar9170 *ar,
struct sk_buff_head *queue,
@@ -360,70 +327,6 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
ieee80211_tx_status_irqsafe(ar->hw, skb);
}
-static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
-{
- struct sk_buff_head success;
- struct sk_buff *skb;
- unsigned int i;
- unsigned long queue_bitmap = 0;
-
- skb_queue_head_init(&success);
-
- while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS)
- __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu));
-
- ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success);
-
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n",
- wiphy_name(ar->hw->wiphy), skb_queue_len(&success));
- __ar9170_dump_txqueue(ar, &success);
-#endif /* AR9170_TXAGG_DEBUG */
-
- while ((skb = __skb_dequeue(&success))) {
- struct ieee80211_tx_info *txinfo;
-
- queue_bitmap |= BIT(skb_get_queue_mapping(skb));
-
- txinfo = IEEE80211_SKB_CB(skb);
- ieee80211_tx_info_clear_status(txinfo);
-
- txinfo->flags |= IEEE80211_TX_STAT_ACK;
- txinfo->status.rates[0].count = 1;
-
- skb_pull(skb, sizeof(struct ar9170_tx_control));
- ieee80211_tx_status_irqsafe(ar->hw, skb);
- }
-
- for_each_set_bit(i, &queue_bitmap, BITS_PER_BYTE) {
-#ifdef AR9170_QUEUE_STOP_DEBUG
- printk(KERN_DEBUG "%s: wake queue %d\n",
- wiphy_name(ar->hw->wiphy), i);
- __ar9170_dump_txstats(ar);
-#endif /* AR9170_QUEUE_STOP_DEBUG */
- ieee80211_wake_queue(ar->hw, i);
- }
-
- if (queue_bitmap)
- ar9170_tx(ar);
-}
-
-static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
- struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
-
- arinfo->timeout = jiffies +
- msecs_to_jiffies(AR9170_BA_TIMEOUT);
-
- skb_queue_tail(&ar->tx_status_ampdu, skb);
- ar9170_tx_fake_ampdu_status(ar);
-
- if (atomic_dec_and_test(&ar->tx_ampdu_pending) &&
- !list_empty(&ar->tx_ampdu_list))
- ar9170_tx_ampdu(ar);
-}
-
void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -447,14 +350,10 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
} else {
- if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- ar9170_tx_ampdu_callback(ar, skb);
- } else {
- arinfo->timeout = jiffies +
- msecs_to_jiffies(AR9170_TX_TIMEOUT);
+ arinfo->timeout = jiffies +
+ msecs_to_jiffies(AR9170_TX_TIMEOUT);
- skb_queue_tail(&ar->tx_status[queue], skb);
- }
+ skb_queue_tail(&ar->tx_status[queue], skb);
}
if (!ar->tx_stats[queue].len &&
@@ -524,38 +423,6 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
return NULL;
}
-static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r)
-{
- struct sk_buff *skb;
- struct ieee80211_tx_info *txinfo;
-
- while (count) {
- skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r);
- if (!skb)
- break;
-
- txinfo = IEEE80211_SKB_CB(skb);
- ieee80211_tx_info_clear_status(txinfo);
-
- /* FIXME: maybe more ? */
- txinfo->status.rates[0].count = 1;
-
- skb_pull(skb, sizeof(struct ar9170_tx_control));
- ieee80211_tx_status_irqsafe(ar->hw, skb);
- count--;
- }
-
-#ifdef AR9170_TXAGG_DEBUG
- if (count) {
- printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more "
- "suitable frames left in tx_status queue.\n",
- wiphy_name(ar->hw->wiphy), count);
-
- ar9170_dump_tx_status_ampdu(ar);
- }
-#endif /* AR9170_TXAGG_DEBUG */
-}
-
/*
* This worker tries to keeps an maintain tx_status queues.
* So we can guarantee that incoming tx_status reports are
@@ -592,8 +459,6 @@ static void ar9170_tx_janitor(struct work_struct *work)
resched = true;
}
- ar9170_tx_fake_ampdu_status(ar);
-
if (!resched)
return;
@@ -673,10 +538,6 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
case 0xc5:
/* BlockACK events */
- ar9170_handle_block_ack(ar,
- le16_to_cpu(cmd->ba_fail_cnt.failed),
- le16_to_cpu(cmd->ba_fail_cnt.rate));
- ar9170_tx_fake_ampdu_status(ar);
break;
case 0xc6:
@@ -1247,7 +1108,6 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
ar->global_ampdu_density = 6;
ar->global_ampdu_factor = 3;
- atomic_set(&ar->tx_ampdu_pending, 0);
ar->bad_hw_nagger = jiffies;
err = ar->open(ar);
@@ -1310,40 +1170,10 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
skb_queue_purge(&ar->tx_pending[i]);
skb_queue_purge(&ar->tx_status[i]);
}
- skb_queue_purge(&ar->tx_status_ampdu);
mutex_unlock(&ar->mutex);
}
-static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb)
-{
- struct ar9170_tx_control *txc = (void *) skb->data;
-
- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU);
-}
-
-static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst,
- struct sk_buff *src)
-{
- struct ar9170_tx_control *dst_txc, *src_txc;
- struct ieee80211_tx_info *dst_info, *src_info;
- struct ar9170_tx_info *dst_arinfo, *src_arinfo;
-
- src_txc = (void *) src->data;
- src_info = IEEE80211_SKB_CB(src);
- src_arinfo = (void *) src_info->rate_driver_data;
-
- dst_txc = (void *) dst->data;
- dst_info = IEEE80211_SKB_CB(dst);
- dst_arinfo = (void *) dst_info->rate_driver_data;
-
- dst_txc->phy_control = src_txc->phy_control;
-
- /* same MCS for the whole aggregate */
- memcpy(dst_info->driver_rates, src_info->driver_rates,
- sizeof(dst_info->driver_rates));
-}
-
static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
@@ -1420,14 +1250,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
txc->phy_control |=
cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
- if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- if (unlikely(!info->control.sta))
- goto err_out;
-
- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
- } else {
- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
- }
+ txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
}
return 0;
@@ -1537,158 +1360,6 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
}
-static bool ar9170_tx_ampdu(struct ar9170 *ar)
-{
- struct sk_buff_head agg;
- struct ar9170_sta_tid *tid_info = NULL, *tmp;
- struct sk_buff *skb, *first = NULL;
- unsigned long flags, f2;
- unsigned int i = 0;
- u16 seq, queue, tmpssn;
- bool run = false;
-
- skb_queue_head_init(&agg);
-
- spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
- if (list_empty(&ar->tx_ampdu_list)) {
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: aggregation list is empty.\n",
- wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
- goto out_unlock;
- }
-
- list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) {
- if (tid_info->state != AR9170_TID_STATE_COMPLETE) {
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: dangling aggregation entry!\n",
- wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
- continue;
- }
-
- if (++i > 64) {
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: enough frames aggregated.\n",
- wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
- break;
- }
-
- queue = TID_TO_WME_AC(tid_info->tid);
-
- if (skb_queue_len(&ar->tx_pending[queue]) >=
- AR9170_NUM_TX_AGG_MAX) {
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: queue %d full.\n",
- wiphy_name(ar->hw->wiphy), queue);
-#endif /* AR9170_TXAGG_DEBUG */
- continue;
- }
-
- list_del_init(&tid_info->list);
-
- spin_lock_irqsave(&tid_info->queue.lock, f2);
- tmpssn = seq = tid_info->ssn;
- first = skb_peek(&tid_info->queue);
-
- if (likely(first))
- tmpssn = ar9170_get_seq(first);
-
- if (unlikely(tmpssn != seq)) {
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.",
- wiphy_name(ar->hw->wiphy), seq, tmpssn);
-#endif /* AR9170_TXAGG_DEBUG */
- tid_info->ssn = tmpssn;
- }
-
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with "
- "%d queued frames.\n", wiphy_name(ar->hw->wiphy),
- tid_info->tid, tid_info->ssn,
- skb_queue_len(&tid_info->queue));
- __ar9170_dump_txqueue(ar, &tid_info->queue);
-#endif /* AR9170_TXAGG_DEBUG */
-
- while ((skb = skb_peek(&tid_info->queue))) {
- if (unlikely(ar9170_get_seq(skb) != seq))
- break;
-
- __skb_unlink(skb, &tid_info->queue);
- tid_info->ssn = seq = GET_NEXT_SEQ(seq);
-
- if (unlikely(skb_get_queue_mapping(skb) != queue)) {
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d "
- "!match.\n", wiphy_name(ar->hw->wiphy),
- tid_info->tid,
- TID_TO_WME_AC(tid_info->tid),
- skb_get_queue_mapping(skb));
-#endif /* AR9170_TXAGG_DEBUG */
- dev_kfree_skb_any(skb);
- continue;
- }
-
- if (unlikely(first == skb)) {
- ar9170_tx_prepare_phy(ar, skb);
- __skb_queue_tail(&agg, skb);
- first = skb;
- } else {
- ar9170_tx_copy_phy(ar, skb, first);
- __skb_queue_tail(&agg, skb);
- }
-
- if (unlikely(skb_queue_len(&agg) ==
- AR9170_NUM_TX_AGG_MAX))
- break;
- }
-
- if (skb_queue_empty(&tid_info->queue))
- tid_info->active = false;
- else
- list_add_tail(&tid_info->list,
- &ar->tx_ampdu_list);
-
- spin_unlock_irqrestore(&tid_info->queue.lock, f2);
-
- if (unlikely(skb_queue_empty(&agg))) {
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: queued empty list!\n",
- wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
- continue;
- }
-
- /*
- * tell the FW/HW that this is the last frame,
- * that way it will wait for the immediate block ack.
- */
- ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
-
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
- wiphy_name(ar->hw->wiphy));
- __ar9170_dump_txqueue(ar, &agg);
-#endif /* AR9170_TXAGG_DEBUG */
-
- spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-
- spin_lock_irqsave(&ar->tx_pending[queue].lock, flags);
- skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
- spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags);
- run = true;
-
- spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
- }
-
-out_unlock:
- spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
- __skb_queue_purge(&agg);
-
- return run;
-}
-
static void ar9170_tx(struct ar9170 *ar)
{
struct sk_buff *skb;
@@ -1763,9 +1434,6 @@ static void ar9170_tx(struct ar9170 *ar)
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
- if (info->flags & IEEE80211_TX_CTL_AMPDU)
- atomic_inc(&ar->tx_ampdu_pending);
-
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n",
wiphy_name(ar->hw->wiphy), i);
@@ -1774,9 +1442,6 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb);
if (unlikely(err)) {
- if (info->flags & IEEE80211_TX_CTL_AMPDU)
- atomic_dec(&ar->tx_ampdu_pending);
-
frames_failed++;
dev_kfree_skb_any(skb);
} else {
@@ -1823,94 +1488,11 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
-static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *txinfo;
- struct ar9170_sta_info *sta_info;
- struct ar9170_sta_tid *agg;
- struct sk_buff *iter;
- unsigned long flags, f2;
- unsigned int max;
- u16 tid, seq, qseq;
- bool run = false, queue = false;
-
- tid = ar9170_get_tid(skb);
- seq = ar9170_get_seq(skb);
- txinfo = IEEE80211_SKB_CB(skb);
- sta_info = (void *) txinfo->control.sta->drv_priv;
- agg = &sta_info->agg[tid];
- max = sta_info->ampdu_max_len;
-
- spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-
- if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) {
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: BlockACK session not fully initialized "
- "for ESS:%pM tid:%d state:%d.\n",
- wiphy_name(ar->hw->wiphy), agg->addr, agg->tid,
- agg->state);
-#endif /* AR9170_TXAGG_DEBUG */
- goto err_unlock;
- }
-
- if (!agg->active) {
- agg->active = true;
- agg->ssn = seq;
- queue = true;
- }
-
- /* check if seq is within the BA window */
- if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) {
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not "
- "fit into BA window (%d - %d)\n",
- wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn,
- (agg->ssn + max) & 0xfff);
-#endif /* AR9170_TXAGG_DEBUG */
- goto err_unlock;
- }
-
- spin_lock_irqsave(&agg->queue.lock, f2);
-
- skb_queue_reverse_walk(&agg->queue, iter) {
- qseq = ar9170_get_seq(iter);
-
- if (GET_NEXT_SEQ(qseq) == seq) {
- __skb_queue_after(&agg->queue, iter, skb);
- goto queued;
- }
- }
-
- __skb_queue_head(&agg->queue, skb);
-
-queued:
- spin_unlock_irqrestore(&agg->queue.lock, f2);
-
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_DEBUG "%s: new aggregate %p queued.\n",
- wiphy_name(ar->hw->wiphy), skb);
- __ar9170_dump_txqueue(ar, &agg->queue);
-#endif /* AR9170_TXAGG_DEBUG */
-
- if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX)
- run = true;
-
- if (queue)
- list_add_tail(&agg->list, &ar->tx_ampdu_list);
-
- spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
- return run;
-
-err_unlock:
- spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
- dev_kfree_skb_irq(skb);
- return false;
-}
-
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ar9170 *ar = hw->priv;
struct ieee80211_tx_info *info;
+ unsigned int queue;
if (unlikely(!IS_STARTED(ar)))
goto err_free;
@@ -1918,18 +1500,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (unlikely(ar9170_tx_prepare(ar, skb)))
goto err_free;
+ queue = skb_get_queue_mapping(skb);
info = IEEE80211_SKB_CB(skb);
- if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- bool run = ar9170_tx_ampdu_queue(ar, skb);
-
- if (run || !atomic_read(&ar->tx_ampdu_pending))
- ar9170_tx_ampdu(ar);
- } else {
- unsigned int queue = skb_get_queue_mapping(skb);
-
- ar9170_tx_prepare_phy(ar, skb);
- skb_queue_tail(&ar->tx_pending[queue], skb);
- }
+ ar9170_tx_prepare_phy(ar, skb);
+ skb_queue_tail(&ar->tx_pending[queue], skb);
ar9170_tx(ar);
return NETDEV_TX_OK;
@@ -2330,57 +1904,6 @@ out:
return err;
}
-static int ar9170_sta_add(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct ar9170 *ar = hw->priv;
- struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
- unsigned int i;
-
- memset(sta_info, 0, sizeof(*sta_info));
-
- if (!sta->ht_cap.ht_supported)
- return 0;
-
- if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
- ar->global_ampdu_density = sta->ht_cap.ampdu_density;
-
- if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
- ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
-
- for (i = 0; i < AR9170_NUM_TID; i++) {
- sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
- sta_info->agg[i].active = false;
- sta_info->agg[i].ssn = 0;
- sta_info->agg[i].tid = i;
- INIT_LIST_HEAD(&sta_info->agg[i].list);
- skb_queue_head_init(&sta_info->agg[i].queue);
- }
-
- sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
-
- return 0;
-}
-
-static int ar9170_sta_remove(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
- unsigned int i;
-
- if (!sta->ht_cap.ht_supported)
- return 0;
-
- for (i = 0; i < AR9170_NUM_TID; i++) {
- sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
- skb_queue_purge(&sta_info->agg[i].queue);
- }
-
- return 0;
-}
-
static int ar9170_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
@@ -2423,55 +1946,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
- struct ar9170 *ar = hw->priv;
- struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
- struct ar9170_sta_tid *tid_info = &sta_info->agg[tid];
- unsigned long flags;
-
- if (!modparam_ht)
- return -EOPNOTSUPP;
-
switch (action) {
- case IEEE80211_AMPDU_TX_START:
- spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
- if (tid_info->state != AR9170_TID_STATE_SHUTDOWN ||
- !list_empty(&tid_info->list)) {
- spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] "
- "is in a very bad state!\n",
- wiphy_name(hw->wiphy), sta->addr, tid);
-#endif /* AR9170_TXAGG_DEBUG */
- return -EBUSY;
- }
-
- *ssn = tid_info->ssn;
- tid_info->state = AR9170_TID_STATE_PROGRESS;
- tid_info->active = false;
- spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
- ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- break;
-
- case IEEE80211_AMPDU_TX_STOP:
- spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
- tid_info->state = AR9170_TID_STATE_SHUTDOWN;
- list_del_init(&tid_info->list);
- tid_info->active = false;
- skb_queue_purge(&tid_info->queue);
- spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- break;
-
- case IEEE80211_AMPDU_TX_OPERATIONAL:
-#ifdef AR9170_TXAGG_DEBUG
- printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n",
- wiphy_name(hw->wiphy), sta->addr, tid);
-#endif /* AR9170_TXAGG_DEBUG */
- spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
- sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE;
- spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
- break;
-
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
/* Handled by firmware */
@@ -2497,8 +1972,6 @@ static const struct ieee80211_ops ar9170_ops = {
.bss_info_changed = ar9170_op_bss_info_changed,
.get_tsf = ar9170_op_get_tsf,
.set_key = ar9170_set_key,
- .sta_add = ar9170_sta_add,
- .sta_remove = ar9170_sta_remove,
.get_stats = ar9170_get_stats,
.ampdu_action = ar9170_ampdu_action,
};
@@ -2531,8 +2004,6 @@ void *ar9170_alloc(size_t priv_size)
mutex_init(&ar->mutex);
spin_lock_init(&ar->cmdlock);
spin_lock_init(&ar->tx_stats_lock);
- spin_lock_init(&ar->tx_ampdu_list_lock);
- skb_queue_head_init(&ar->tx_status_ampdu);
for (i = 0; i < __AR9170_NUM_TXQ; i++) {
skb_queue_head_init(&ar->tx_status[i]);
skb_queue_head_init(&ar->tx_pending[i]);
@@ -2540,7 +2011,6 @@ void *ar9170_alloc(size_t priv_size)
ar9170_rx_reset_rx_mpdu(ar);
INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
- INIT_LIST_HEAD(&ar->tx_ampdu_list);
/* all hw supports 2.4 GHz, so set channel to 1 by default */
ar->channel = &ar9170_2ghz_chantable[0];
@@ -2554,16 +2024,8 @@ void *ar9170_alloc(size_t priv_size)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
- if (modparam_ht) {
- ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
- } else {
- ar9170_band_2GHz.ht_cap.ht_supported = false;
- ar9170_band_5GHz.ht_cap.ht_supported = false;
- }
-
ar->hw->queues = __AR9170_NUM_TXQ;
ar->hw->extra_tx_headroom = 8;
- ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
ar->hw->max_rates = 1;
ar->hw->max_rate_tries = 3;
^ permalink raw reply related
* [PATCH] ssb: Implement fast powerup delay calculation
From: Gábor Stefanik @ 2010-05-01 16:29 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, b43-dev, Michael Buesch, Larry Finger
Implement fast powerup delay calculation, as described
in the recently updated specs. The 4325 part is coming soon.
Signed-off-by: Gábor Stefanik<netrolller.3d@gmail.com>
---
To people experiencing DMA errors: please test this patch, it touches
the PMU code, one of the suspected problem areas.
I'm submitting this patch using Thunderbird 3; so I cannot be held liable
if it gets damaged in transit. Blame Mozilla. :-)
Index: wireless-testing/drivers/ssb/driver_chipcommon.c
===================================================================
--- wireless-testing.orig/drivers/ssb/driver_chipcommon.c
+++ wireless-testing/drivers/ssb/driver_chipcommon.c
@@ -209,7 +209,24 @@ static void chipco_powercontrol_init(str
}
}
-static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
+static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+
+ switch (bus->chip_id) {
+ case 0x4312:
+ case 0x4322:
+ case 0x4328:
+ return 7000;
+ case 0x4325:
+ /* TODO: */
+ default:
+ break;
+ }
+ return 15000;
+}
+
+static u16 calc_fast_powerup_delay(struct ssb_chipcommon *cc)
{
struct ssb_bus *bus = cc->dev->bus;
int minfreq;
@@ -217,26 +234,33 @@ static void calc_fast_powerup_delay(stru
u32 pll_on_delay;
if (bus->bustype != SSB_BUSTYPE_PCI)
- return;
+ return 0;
+ if (cc->capabilities& SSB_CHIPCO_CAP_PMU)
+ return pmu_fast_powerup_delay(cc);
if (!(cc->capabilities& SSB_CHIPCO_CAP_PCTL))
- return;
+ return 0;
minfreq = chipco_pctl_clockfreqlimit(cc, 0);
pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY);
tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
SSB_WARN_ON(tmp& ~0xFFFF);
- cc->fast_pwrup_delay = tmp;
+ return tmp;
}
void ssb_chipcommon_init(struct ssb_chipcommon *cc)
{
+ u16 delay;
+
if (!cc->dev)
return; /* We don't have a ChipCommon */
ssb_pmu_init(cc);
chipco_powercontrol_init(cc);
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
- calc_fast_powerup_delay(cc);
+ delay = calc_fast_powerup_delay(cc);
+ ssb_printk(KERN_INFO PFX "fast_pwrup_delay is %d\n", delay);
+ cc->fast_pwrup_delay = delay;
+ ssb_write16(cc->dev, SSB_MMIO_POWERUP_DELAY, delay);
}
void ssb_chipco_suspend(struct ssb_chipcommon *cc)
Index: wireless-testing/include/linux/ssb/ssb_regs.h
===================================================================
--- wireless-testing.orig/include/linux/ssb/ssb_regs.h
+++ wireless-testing/include/linux/ssb/ssb_regs.h
@@ -26,6 +26,7 @@
#define SSB_EUART (SSB_EXTIF_BASE + 0x00800000)
#define SSB_LED (SSB_EXTIF_BASE + 0x00900000)
+#define SSB_MMIO_POWERUP_DELAY 0x06A8
/* Enumeration space constants */
#define SSB_CORE_SIZE 0x1000 /* Size of a core MMIO area */
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Gábor Stefanik @ 2010-05-01 16:32 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, b43-dev, Michael Buesch, Larry Finger
In-Reply-To: <4BDC56D2.5060605@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 660 bytes --]
2010/5/1 Gábor Stefanik <netrolller.3d@gmail.com>:
> Implement fast powerup delay calculation, as described
> in the recently updated specs. The 4325 part is coming soon.
>
> Signed-off-by: Gábor Stefanik<netrolller.3d@gmail.com>
> ---
>
> To people experiencing DMA errors: please test this patch, it touches
> the PMU code, one of the suspected problem areas.
>
> I'm submitting this patch using Thunderbird 3; so I cannot be held liable
> if it gets damaged in transit. Blame Mozilla. :-)
Apparently the nasty space-doubling issue seen in the Tb3 beta is
still present in the final version... here is the patch as an
attachment.
--Gábor
[-- Attachment #2: ssb_fast_pwrup_delay.patch --]
[-- Type: application/octet-stream, Size: 2489 bytes --]
Implement fast powerup delay calculation, as described
in the recently updated specs. The 4325 part is coming soon.
Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
---
Index: wireless-testing/drivers/ssb/driver_chipcommon.c
===================================================================
--- wireless-testing.orig/drivers/ssb/driver_chipcommon.c
+++ wireless-testing/drivers/ssb/driver_chipcommon.c
@@ -209,7 +209,24 @@ static void chipco_powercontrol_init(str
}
}
-static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
+static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+
+ switch (bus->chip_id) {
+ case 0x4312:
+ case 0x4322:
+ case 0x4328:
+ return 7000;
+ case 0x4325:
+ /* TODO: */
+ default:
+ break;
+ }
+ return 15000;
+}
+
+static u16 calc_fast_powerup_delay(struct ssb_chipcommon *cc)
{
struct ssb_bus *bus = cc->dev->bus;
int minfreq;
@@ -217,26 +234,33 @@ static void calc_fast_powerup_delay(stru
u32 pll_on_delay;
if (bus->bustype != SSB_BUSTYPE_PCI)
- return;
+ return 0;
+ if (cc->capabilities & SSB_CHIPCO_CAP_PMU)
+ return pmu_fast_powerup_delay(cc);
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
- return;
+ return 0;
minfreq = chipco_pctl_clockfreqlimit(cc, 0);
pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY);
tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
SSB_WARN_ON(tmp & ~0xFFFF);
- cc->fast_pwrup_delay = tmp;
+ return tmp;
}
void ssb_chipcommon_init(struct ssb_chipcommon *cc)
{
+ u16 delay;
+
if (!cc->dev)
return; /* We don't have a ChipCommon */
ssb_pmu_init(cc);
chipco_powercontrol_init(cc);
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
- calc_fast_powerup_delay(cc);
+ delay = calc_fast_powerup_delay(cc);
+ ssb_printk(KERN_INFO PFX "fast_pwrup_delay is %d\n", delay);
+ cc->fast_pwrup_delay = delay;
+ ssb_write16(cc->dev, SSB_MMIO_POWERUP_DELAY, delay);
}
void ssb_chipco_suspend(struct ssb_chipcommon *cc)
Index: wireless-testing/include/linux/ssb/ssb_regs.h
===================================================================
--- wireless-testing.orig/include/linux/ssb/ssb_regs.h
+++ wireless-testing/include/linux/ssb/ssb_regs.h
@@ -26,6 +26,7 @@
#define SSB_EUART (SSB_EXTIF_BASE + 0x00800000)
#define SSB_LED (SSB_EXTIF_BASE + 0x00900000)
+#define SSB_MMIO_POWERUP_DELAY 0x06A8
/* Enumeration space constants */
#define SSB_CORE_SIZE 0x1000 /* Size of a core MMIO area */
^ permalink raw reply
* [PATCH] mac80211: allow controlling aggregation manually
From: Johannes Berg @ 2010-05-01 16:53 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless
This allows enabling TX and disabling both TX and
RX aggregation sessions manually in debugfs. It is
very useful for debugging session initiation and
teardown problems since with this you don't have
to force a lot of traffic to get aggregation and
thus have less data to analyse.
Also, to debug mac80211 code itself, make hwsim
"support" aggregation sessions. It will still just
transfer the frame, but go through the setup and
teardown handshakes.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
Ok so I do want it in the tree... had another
situation where I needed it and don't want to
have to patch all the time.
Unless anyone objects?
drivers/net/wireless/mac80211_hwsim.c | 3 +
net/mac80211/debugfs_sta.c | 65 +++++++++++++++++++++++++++++++++-
2 files changed, 66 insertions(+), 2 deletions(-)
--- wireless-testing.orig/drivers/net/wireless/mac80211_hwsim.c 2010-05-01 08:47:54.000000000 +0200
+++ wireless-testing/drivers/net/wireless/mac80211_hwsim.c 2010-05-01 08:47:56.000000000 +0200
@@ -1317,7 +1317,8 @@ static int __init init_mac80211_hwsim(vo
hw->flags = IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_STATIC_SMPS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
+ IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+ IEEE80211_HW_AMPDU_AGGREGATION;
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
--- wireless-testing.orig/net/mac80211/debugfs_sta.c 2010-05-01 08:46:26.000000000 +0200
+++ wireless-testing/net/mac80211/debugfs_sta.c 2010-05-01 08:47:56.000000000 +0200
@@ -39,6 +39,13 @@ static const struct file_operations sta_
.open = mac80211_open_file_generic, \
}
+#define STA_OPS_RW(name) \
+static const struct file_operations sta_ ##name## _ops = { \
+ .read = sta_##name##_read, \
+ .write = sta_##name##_write, \
+ .open = mac80211_open_file_generic, \
+}
+
#define STA_FILE(name, field, format) \
STA_READ_##format(name, field) \
STA_OPS(name)
@@ -156,7 +163,63 @@ static ssize_t sta_agg_status_read(struc
return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
}
-STA_OPS(agg_status);
+
+static ssize_t sta_agg_status_write(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char _buf[12], *buf = _buf;
+ struct sta_info *sta = file->private_data;
+ bool start, tx;
+ unsigned long tid;
+ int ret;
+
+ if (count > sizeof(_buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, userbuf, count))
+ return -EFAULT;
+
+ buf[sizeof(_buf) - 1] = '\0';
+
+ if (strncmp(buf, "tx ", 3) == 0) {
+ buf += 3;
+ tx = true;
+ } else if (strncmp(buf, "rx ", 3) == 0) {
+ buf += 3;
+ tx = false;
+ } else
+ return -EINVAL;
+
+ if (strncmp(buf, "start ", 6) == 0) {
+ buf += 6;
+ start = true;
+ if (!tx)
+ return -EINVAL;
+ } else if (strncmp(buf, "stop ", 5) == 0) {
+ buf += 5;
+ start = false;
+ } else
+ return -EINVAL;
+
+ tid = simple_strtoul(buf, NULL, 0);
+
+ if (tid >= STA_TID_NUM)
+ return -EINVAL;
+
+ if (tx) {
+ if (start)
+ ret = ieee80211_start_tx_ba_session(&sta->sta, tid);
+ else
+ ret = ieee80211_stop_tx_ba_session(&sta->sta, tid,
+ WLAN_BACK_RECIPIENT);
+ } else {
+ __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3);
+ ret = 0;
+ }
+
+ return ret ?: count;
+}
+STA_OPS_RW(agg_status);
static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Michael Buesch @ 2010-05-01 17:07 UTC (permalink / raw)
To: Gábor Stefanik
Cc: John W. Linville, linux-wireless, b43-dev, Larry Finger
In-Reply-To: <4BDC56D2.5060605@gmail.com>
On Saturday 01 May 2010 18:29:06 Gábor Stefanik wrote:
> + ssb_write16(cc->dev, SSB_MMIO_POWERUP_DELAY, delay);
> }
>
> void ssb_chipco_suspend(struct ssb_chipcommon *cc)
> Index: wireless-testing/include/linux/ssb/ssb_regs.h
> ===================================================================
> --- wireless-testing.orig/include/linux/ssb/ssb_regs.h
> +++ wireless-testing/include/linux/ssb/ssb_regs.h
> @@ -26,6 +26,7 @@
> #define SSB_EUART (SSB_EXTIF_BASE + 0x00800000)
> #define SSB_LED (SSB_EXTIF_BASE + 0x00900000)
>
> +#define SSB_MMIO_POWERUP_DELAY 0x06A8
I think you are really confusing something here.
That register is a wireless core register and we already write it in b43.
--
Greetings, Michael.
^ permalink raw reply
* [RFC] mac80211: radiotap vendor data
From: Johannes Berg @ 2010-05-01 17:13 UTC (permalink / raw)
To: linux-wireless
This allows drivers to add radiotap vendor data
to any received frame, which will be simply
passed into userspace and ignored by the kernel.
Can be used by drivers to convey hw-specific
information.
Note: 11n shouldn't be done there, in case somebody
got ideas!!
Note: didn't test this after the paged RX changes
---
drivers/net/wireless/mac80211_hwsim.c | 17 ++++++++++
include/net/mac80211.h | 12 +++++++
net/mac80211/rx.c | 53 ++++++++++++++++++++++++++++++----
3 files changed, 77 insertions(+), 5 deletions(-)
--- wireless-testing.orig/include/net/mac80211.h 2010-05-01 08:46:26.000000000 +0200
+++ wireless-testing/include/net/mac80211.h 2010-05-01 08:47:54.000000000 +0200
@@ -565,6 +565,13 @@ enum mac80211_rx_flags {
* @rate_idx: index of data rate into band's supported rates or MCS index if
* HT rates are use (RX_FLAG_HT)
* @flag: %RX_FLAG_*
+ * @vendor_radiotap_bitmap: radiotap vendor namespace presence bitmap
+ * @vendor_radiotap_len: radiotap vendor namespace length
+ * @vendor_radiotap_align: radiotap vendor namespace alignment. Note
+ * that the actual data must be at the start of the SKB data
+ * already.
+ * @vendor_radiotap_oui: radiotap vendor namespace OUI
+ * @vendor_radiotap_subns: radiotap vendor sub namespace
*/
struct ieee80211_rx_status {
u64 mactime;
@@ -575,6 +582,11 @@ struct ieee80211_rx_status {
int antenna;
int rate_idx;
int flag;
+ u32 vendor_radiotap_bitmap;
+ u16 vendor_radiotap_len;
+ u8 vendor_radiotap_align;
+ u8 vendor_radiotap_oui[3];
+ u8 vendor_radiotap_subns;
};
/**
--- wireless-testing.orig/net/mac80211/rx.c 2010-05-01 08:46:26.000000000 +0200
+++ wireless-testing/net/mac80211/rx.c 2010-05-01 08:47:54.000000000 +0200
@@ -37,6 +37,8 @@
static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
struct sk_buff *skb)
{
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
if (likely(skb->len > FCS_LEN))
__pskb_trim(skb, skb->len - FCS_LEN);
@@ -48,6 +50,9 @@ static struct sk_buff *remove_monitor_in
}
}
+ if (status->vendor_radiotap_len)
+ __pskb_pull(skb, status->vendor_radiotap_len);
+
return skb;
}
@@ -69,8 +74,8 @@ static inline int should_drop_frame(stru
}
static int
-ieee80211_rx_radiotap_len(struct ieee80211_local *local,
- struct ieee80211_rx_status *status)
+ieee80211_rx_radiotap_space(struct ieee80211_local *local,
+ struct ieee80211_rx_status *status)
{
int len;
@@ -87,6 +92,21 @@ ieee80211_rx_radiotap_len(struct ieee802
if (len & 1) /* padding for RX_FLAGS if necessary */
len++;
+ if (status->vendor_radiotap_len) {
+ /* allocate extra bitmap */
+ len += 4;
+
+ if (WARN_ON(status->vendor_radiotap_align == 0))
+ status->vendor_radiotap_align = 1;
+ /* align standard part of vendor namespace */
+ len = ALIGN(len, 2);
+ /* allocate standard part of vendor namespace */
+ len += 6;
+ /* align vendor-defined part */
+ len = ALIGN(len, status->vendor_radiotap_align);
+ /* vendor-defined part is already in skb */
+ }
+
return len;
}
@@ -115,10 +135,18 @@ ieee80211_add_rx_radiotap_header(struct
(1 << IEEE80211_RADIOTAP_CHANNEL) |
(1 << IEEE80211_RADIOTAP_ANTENNA) |
(1 << IEEE80211_RADIOTAP_RX_FLAGS));
- rthdr->it_len = cpu_to_le16(rtap_len);
+ rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len);
pos = (unsigned char *)(rthdr+1);
+ if (status->vendor_radiotap_len) {
+ rthdr->it_present |=
+ cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) |
+ cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT));
+ put_unaligned_le32(status->vendor_radiotap_bitmap, pos);
+ pos += 4;
+ }
+
/* the order of the following fields is important */
/* IEEE80211_RADIOTAP_TSFT */
@@ -190,11 +218,26 @@ ieee80211_add_rx_radiotap_header(struct
/* IEEE80211_RADIOTAP_RX_FLAGS */
/* ensure 2 byte alignment for the 2 byte field as required */
if ((pos - (u8 *)rthdr) & 1)
- pos++;
+ *pos++ = 0;
if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP;
put_unaligned_le16(rx_flags, pos);
pos += 2;
+
+ if (status->vendor_radiotap_len) {
+ /* ensure 2 byte alignment for the vendor field as required */
+ if ((pos - (u8 *)rthdr) & 1)
+ *pos++ = 0;
+ *pos++ = status->vendor_radiotap_oui[0];
+ *pos++ = status->vendor_radiotap_oui[1];
+ *pos++ = status->vendor_radiotap_oui[2];
+ *pos++ = status->vendor_radiotap_subns;
+ put_unaligned_le16(status->vendor_radiotap_len, pos);
+ pos += 2;
+ /* align the actual payload as requested */
+ while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1))
+ *pos++ = 0;
+ }
}
/*
@@ -223,7 +266,7 @@ ieee80211_rx_monitor(struct ieee80211_lo
*/
/* room for the radiotap header based on driver features */
- needed_headroom = ieee80211_rx_radiotap_len(local, status);
+ needed_headroom = ieee80211_rx_radiotap_space(local, status);
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
present_fcs_len = FCS_LEN;
--- wireless-testing.orig/drivers/net/wireless/mac80211_hwsim.c 2010-05-01 08:46:27.000000000 +0200
+++ wireless-testing/drivers/net/wireless/mac80211_hwsim.c 2010-05-01 19:04:57.000000000 +0200
@@ -484,6 +484,7 @@ static bool mac80211_hwsim_tx_frame(stru
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_rx_status rx_status;
+ u8 *vendor_data;
if (data->idle) {
printk(KERN_DEBUG "%s: Trying to TX when idle - reject\n",
@@ -509,6 +510,20 @@ static bool mac80211_hwsim_tx_frame(stru
secpath_reset(skb);
nf_reset(skb);
+ vendor_data = skb_push(skb, 4);
+ rx_status.vendor_radiotap_len = 4;
+ rx_status.vendor_radiotap_align = 4;
+ rx_status.vendor_radiotap_oui[0] = 0xff;
+ rx_status.vendor_radiotap_oui[1] = 0xff;
+ rx_status.vendor_radiotap_oui[2] = 0xff;
+ rx_status.vendor_radiotap_subns = 129;
+ rx_status.vendor_radiotap_bitmap = 0x1;
+
+ *vendor_data++ = 1;
+ *vendor_data++ = 2;
+ *vendor_data++ = 3;
+ *vendor_data++ = 4;
+
/* Copy skb to all enabled radios that are on the current frequency */
spin_lock(&hwsim_radio_lock);
list_for_each_entry(data2, &hwsim_radios, list) {
@@ -535,6 +550,8 @@ static bool mac80211_hwsim_tx_frame(stru
}
spin_unlock(&hwsim_radio_lock);
+ skb_pull(skb, 4);
+
return ack;
}
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Gábor Stefanik @ 2010-05-01 17:13 UTC (permalink / raw)
To: Michael Buesch; +Cc: John W. Linville, linux-wireless, b43-dev, Larry Finger
In-Reply-To: <201005011907.05603.mb@bu3sch.de>
2010/5/1 Michael Buesch <mb@bu3sch.de>:
> On Saturday 01 May 2010 18:29:06 Gábor Stefanik wrote:
>> + ssb_write16(cc->dev, SSB_MMIO_POWERUP_DELAY, delay);
>> }
>>
>> void ssb_chipco_suspend(struct ssb_chipcommon *cc)
>> Index: wireless-testing/include/linux/ssb/ssb_regs.h
>> ===================================================================
>> --- wireless-testing.orig/include/linux/ssb/ssb_regs.h
>> +++ wireless-testing/include/linux/ssb/ssb_regs.h
>> @@ -26,6 +26,7 @@
>> #define SSB_EUART (SSB_EXTIF_BASE + 0x00800000)
>> #define SSB_LED (SSB_EXTIF_BASE + 0x00900000)
>>
>> +#define SSB_MMIO_POWERUP_DELAY 0x06A8
>
> I think you are really confusing something here.
> That register is a wireless core register and we already write it in b43.
>
> --
> Greetings, Michael.
>
This is what I am implementing: http://bcm-v4.sipsolutions.net/802.11/Init
Here, it clearly says MMIO offset.
--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
^ permalink raw reply
* Re: ar9170-fw II
From: Christian Lamparter @ 2010-05-01 17:19 UTC (permalink / raw)
To: David H. Lynch Jr.; +Cc: linux-wireless
In-Reply-To: <4BDC001F.9050202@dlasys.net>
On Saturday 01 May 2010 12:19:11 David H. Lynch Jr. wrote:
> I have ethernet driver experience but not wifi. I have a project to
> add some features to the ar9170 that will require additions to the
> firmware. I would appreciate pointers for docs etc. to get me started.
Well, for starters the ar9170 uses a ZyDas MAC (aka ZD1221)
and a AR900x PHY/Radio. Therefore the phy code and registers
are very similar to those #definitions you can find in ath9k.
And for the MAC code & registers you can look into zd1211rw,
or look into drivers/staging/otus (original vendor driver,
shares some code with their windows drivers)
AFAICT, there are no technical documents about the AR9170
solution available w/o signing a NDA with Atheros
(probably because the devices are still produced and sold in high quantities?).
> What is available for the ar9170 itself ?
> How does the firmware and the linux driver communicate?
> Is there an overview of the firmware - what is where ?
not really, apart from the headers of the original firmware
and vendor drivers.
But if you really need to implement some of your 'features'
(what are they, if I may ask?) into the firmware you could
save some time by migrating to carl9170 code base:
( http://www.kernel.org/pub/linux/kernel/people/chr/carl9170/1.0.5
+ linville's wireless-testing.git )
The advantages over the original firmware code (from a developers POV) are:
* customizable/configurable fw
+ driver can auto detect all selected fw features
* userspace testbench ( carlu ) for the usb subsystem
(allows you to run usb stress-test, dump the device's eeprom content
to stdout and of course: you can implement your own routines
and test & develop without crashing the kernel)
* all hardware & firmware interface definitions are all located
in a single directory /include/shared/*.h
version.h - carl9170 API/ABI version
eeprom.h - eeprom layout
phy.h - AR900x PHY/Radio definitions
fwcmd.h - implemented firmware commands
fwdesc.h - layout of the firmware descriptor (e.g. available/activated features)
hw.h - ZD1221 MAC + (Faraday USB) definitions
wlan.h - (part of hw.h & phy.h) contains all the information about
tx & rx frame formats.
* (tiny) printf + hexdump (obviously, you want those ;-) )
* follows linux' kernel coding style :-D
Regards,
Chr
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Michael Buesch @ 2010-05-01 17:19 UTC (permalink / raw)
To: Gábor Stefanik
Cc: John W. Linville, linux-wireless, b43-dev, Larry Finger
In-Reply-To: <AANLkTimXBlIETHVLapuSrkI8uTIU8JPepLWvAEq6_D4T@mail.gmail.com>
On Saturday 01 May 2010 19:13:31 Gábor Stefanik wrote:
> 2010/5/1 Michael Buesch <mb@bu3sch.de>:
> > On Saturday 01 May 2010 18:29:06 Gábor Stefanik wrote:
> >> + ssb_write16(cc->dev, SSB_MMIO_POWERUP_DELAY, delay);
> >> }
> >>
> >> void ssb_chipco_suspend(struct ssb_chipcommon *cc)
> >> Index: wireless-testing/include/linux/ssb/ssb_regs.h
> >> ===================================================================
> >> --- wireless-testing.orig/include/linux/ssb/ssb_regs.h
> >> +++ wireless-testing/include/linux/ssb/ssb_regs.h
> >> @@ -26,6 +26,7 @@
> >> #define SSB_EUART (SSB_EXTIF_BASE + 0x00800000)
> >> #define SSB_LED (SSB_EXTIF_BASE + 0x00900000)
> >>
> >> +#define SSB_MMIO_POWERUP_DELAY 0x06A8
> >
> > I think you are really confusing something here.
> > That register is a wireless core register and we already write it in b43.
> >
> > --
> > Greetings, Michael.
> >
>
> This is what I am implementing: http://bcm-v4.sipsolutions.net/802.11/Init
> Here, it clearly says MMIO offset.
Yeah. Just what I said. It is an 802.11 core register.
We already write it in b43/main.c/b43_chip_init().
It is _wrong_ to write to the chipcommon at that offset.
--
Greetings, Michael.
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Gábor Stefanik @ 2010-05-01 17:19 UTC (permalink / raw)
To: Michael Buesch; +Cc: John W. Linville, linux-wireless, b43-dev, Larry Finger
In-Reply-To: <AANLkTimXBlIETHVLapuSrkI8uTIU8JPepLWvAEq6_D4T@mail.gmail.com>
2010/5/1 Gábor Stefanik <netrolller.3d@gmail.com>:
> 2010/5/1 Michael Buesch <mb@bu3sch.de>:
>> On Saturday 01 May 2010 18:29:06 Gábor Stefanik wrote:
>>> + ssb_write16(cc->dev, SSB_MMIO_POWERUP_DELAY, delay);
>>> }
>>>
>>> void ssb_chipco_suspend(struct ssb_chipcommon *cc)
>>> Index: wireless-testing/include/linux/ssb/ssb_regs.h
>>> ===================================================================
>>> --- wireless-testing.orig/include/linux/ssb/ssb_regs.h
>>> +++ wireless-testing/include/linux/ssb/ssb_regs.h
>>> @@ -26,6 +26,7 @@
>>> #define SSB_EUART (SSB_EXTIF_BASE + 0x00800000)
>>> #define SSB_LED (SSB_EXTIF_BASE + 0x00900000)
>>>
>>> +#define SSB_MMIO_POWERUP_DELAY 0x06A8
>>
>> I think you are really confusing something here.
>> That register is a wireless core register and we already write it in b43.
>>
>> --
>> Greetings, Michael.
>>
>
> This is what I am implementing: http://bcm-v4.sipsolutions.net/802.11/Init
> Here, it clearly says MMIO offset.
>
> --
> Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
>
Sorry, now I understand. The MMIO write is unnecessary.
--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Larry Finger @ 2010-05-01 17:42 UTC (permalink / raw)
To: Michael Buesch
Cc: Gábor Stefanik, John W. Linville, linux-wireless, b43-dev
In-Reply-To: <201005011919.42294.mb@bu3sch.de>
On 05/01/2010 12:19 PM, Michael Buesch wrote:
> On Saturday 01 May 2010 19:13:31 Gábor Stefanik wrote:
>> 2010/5/1 Michael Buesch <mb@bu3sch.de>:
>>> On Saturday 01 May 2010 18:29:06 Gábor Stefanik wrote:
>>>> + ssb_write16(cc->dev, SSB_MMIO_POWERUP_DELAY, delay);
>>>> }
>>>>
>>>> void ssb_chipco_suspend(struct ssb_chipcommon *cc)
>>>> Index: wireless-testing/include/linux/ssb/ssb_regs.h
>>>> ===================================================================
>>>> --- wireless-testing.orig/include/linux/ssb/ssb_regs.h
>>>> +++ wireless-testing/include/linux/ssb/ssb_regs.h
>>>> @@ -26,6 +26,7 @@
>>>> #define SSB_EUART (SSB_EXTIF_BASE + 0x00800000)
>>>> #define SSB_LED (SSB_EXTIF_BASE + 0x00900000)
>>>>
>>>> +#define SSB_MMIO_POWERUP_DELAY 0x06A8
>>>
>>> I think you are really confusing something here.
>>> That register is a wireless core register and we already write it in b43.
>>>
>>> --
>>> Greetings, Michael.
>>>
>>
>> This is what I am implementing: http://bcm-v4.sipsolutions.net/802.11/Init
>> Here, it clearly says MMIO offset.
>
> Yeah. Just what I said. It is an 802.11 core register.
> We already write it in b43/main.c/b43_chip_init().
> It is _wrong_ to write to the chipcommon at that offset.
I may have gotten the MMIO offset part wrong in the specs, but the
Broadcom driver definitely writes to offset 0x648 at that point.
I know that b43 writes that location; however, it is much later in the
startup sequence. Whether that is important is unknown at this point.
The previous code resulted in a value of zero being written to the
location in question, but the value for the 4315 is 7000.
Larry
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Gábor Stefanik @ 2010-05-01 17:48 UTC (permalink / raw)
To: Larry Finger; +Cc: Michael Buesch, John W. Linville, linux-wireless, b43-dev
In-Reply-To: <4BDC6803.9030805@lwfinger.net>
On Sat, May 1, 2010 at 7:42 PM, Larry Finger <Larry.Finger@lwfinger.net> wrote:
> On 05/01/2010 12:19 PM, Michael Buesch wrote:
>> On Saturday 01 May 2010 19:13:31 Gábor Stefanik wrote:
>>> 2010/5/1 Michael Buesch <mb@bu3sch.de>:
>>>> On Saturday 01 May 2010 18:29:06 Gábor Stefanik wrote:
>>>>> + ssb_write16(cc->dev, SSB_MMIO_POWERUP_DELAY, delay);
>>>>> }
>>>>>
>>>>> void ssb_chipco_suspend(struct ssb_chipcommon *cc)
>>>>> Index: wireless-testing/include/linux/ssb/ssb_regs.h
>>>>> ===================================================================
>>>>> --- wireless-testing.orig/include/linux/ssb/ssb_regs.h
>>>>> +++ wireless-testing/include/linux/ssb/ssb_regs.h
>>>>> @@ -26,6 +26,7 @@
>>>>> #define SSB_EUART (SSB_EXTIF_BASE + 0x00800000)
>>>>> #define SSB_LED (SSB_EXTIF_BASE + 0x00900000)
>>>>>
>>>>> +#define SSB_MMIO_POWERUP_DELAY 0x06A8
>>>>
>>>> I think you are really confusing something here.
>>>> That register is a wireless core register and we already write it in b43.
>>>>
>>>> --
>>>> Greetings, Michael.
>>>>
>>>
>>> This is what I am implementing: http://bcm-v4.sipsolutions.net/802.11/Init
>>> Here, it clearly says MMIO offset.
>>
>> Yeah. Just what I said. It is an 802.11 core register.
>> We already write it in b43/main.c/b43_chip_init().
>> It is _wrong_ to write to the chipcommon at that offset.
>
> I may have gotten the MMIO offset part wrong in the specs, but the
> Broadcom driver definitely writes to offset 0x648 at that point.
>
> I know that b43 writes that location; however, it is much later in the
> startup sequence. Whether that is important is unknown at this point.
>
> The previous code resulted in a value of zero being written to the
> location in question, but the value for the 4315 is 7000.
>
> Larry
>
According to http://bcm-v4.sipsolutions.net/802.11/Init, b43 is right
- the write should go to the 802.11 core, not ChipCommon.
--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Michael Buesch @ 2010-05-01 18:15 UTC (permalink / raw)
To: Larry Finger
Cc: Gábor Stefanik, John W. Linville, linux-wireless, b43-dev
In-Reply-To: <4BDC6803.9030805@lwfinger.net>
On Saturday 01 May 2010 19:42:27 Larry Finger wrote:
> I may have gotten the MMIO offset part wrong in the specs, but the
> Broadcom driver definitely writes to offset 0x648 at that point.
I do not think you are right.
First: The write has to happen to the 802.11 core and not to the chipcommon core.
Second: The code that was touched by Gábor is _very_ early in the SSB init.
Way ahead of the wireless core init. The specs state that the delay value has to be written
after the wireless core init is nearly done.
We do _exactly_ that in b43.
The only thing that needs to be done is to add the additional switch statement.
No MMIO writes have to be touched.
--
Greetings, Michael.
^ permalink raw reply
* Re: ar9170-fw II
From: David H. Lynch Jr. @ 2010-05-01 18:23 UTC (permalink / raw)
To: Christian Lamparter, linux-wireless
In-Reply-To: <201005011919.32016.chunkeey@googlemail.com>
On 05/01/2010 01:19 PM, Christian Lamparter wrote:
>
> Well, for starters the ar9170 uses a ZyDas MAC (aka ZD1221)
> and a AR900x PHY/Radio. Therefore the phy code and registers
> are very similar to those #definitions you can find in ath9k.
> And for the MAC code& registers you can look into zd1211rw,
> or look into drivers/staging/otus (original vendor driver,
> shares some code with their windows drivers)
>
> AFAICT, there are no technical documents about the AR9170
> solution available w/o signing a NDA with Atheros
> (probably because the devices are still produced and sold in high quantities?).
>
Thanks;
I did just discover a reasonably good 150p spec. in what I
received from my client.
If I can I will share it. I am under an NDA, but the client
also told me that they received no cooperation from atheros.
>> What is available for the ar9170 itself ?
>> How does the firmware and the linux driver communicate?
>> Is there an overview of the firmware - what is where ?
>>
> not really, apart from the headers of the original firmware
> and vendor drivers.
>
> But if you really need to implement some of your 'features'
> (what are they, if I may ask?)
I think I can tell you what I am supposed add - I need to be able
to provide userspace apps with precise timing information for each packet.
Since i am working on GPL'd code and the results are going to be
provided to third parties whatever I do is GPL'd too.
Why gets into the NDA.
Right now i have an NDA with a new client and though I am
exercising care. But they seem fairly mellow. I am probably just being
overly cautious.
> into the firmware you could
> save some time by migrating to carl9170 code base:
> ( http://www.kernel.org/pub/linux/kernel/people/chr/carl9170/1.0.5
> + linville's wireless-testing.git )
>
The carl9170 code is the expected future of the ar9170 in Linux ?
If so that is where I want to be working.
> The advantages over the original firmware code (from a developers POV) are:
> * customizable/configurable fw
> + driver can auto detect all selected fw features
>
> * userspace testbench ( carlu ) for the usb subsystem
> (allows you to run usb stress-test, dump the device's eeprom content
> to stdout and of course: you can implement your own routines
> and test& develop without crashing the kernel)
>
> * all hardware& firmware interface definitions are all located
> in a single directory /include/shared/*.h
>
> version.h - carl9170 API/ABI version
> eeprom.h - eeprom layout
> phy.h - AR900x PHY/Radio definitions
> fwcmd.h - implemented firmware commands
> fwdesc.h - layout of the firmware descriptor (e.g. available/activated features)
> hw.h - ZD1221 MAC + (Faraday USB) definitions
> wlan.h - (part of hw.h& phy.h) contains all the information about
> tx& rx frame formats.
>
> * (tiny) printf + hexdump (obviously, you want those ;-) )
>
> * follows linux' kernel coding style :-D
>
Thanks alot.
I will look seriously at that.
While I want to keep the scope of what I am doing small, and as
narrowly confined as a I can,
it would be nice if atleast some of my work was useful beyond the
unique needs of my client.
> Regards,
> Chr
>
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.587.7774 dhlii@dlasys.net http://www.dlasys.net
Over 25 years' experience in platforms, languages, and technologies too numerous to list.
"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Larry Finger @ 2010-05-01 18:27 UTC (permalink / raw)
To: Michael Buesch
Cc: Gábor Stefanik, John W. Linville, linux-wireless, b43-dev
In-Reply-To: <201005012015.50601.mb@bu3sch.de>
On 05/01/2010 01:15 PM, Michael Buesch wrote:
> On Saturday 01 May 2010 19:42:27 Larry Finger wrote:
>> I may have gotten the MMIO offset part wrong in the specs, but the
>> Broadcom driver definitely writes to offset 0x648 at that point.
>
> I do not think you are right.
>
> First: The write has to happen to the 802.11 core and not to the chipcommon core.
>
> Second: The code that was touched by Gábor is _very_ early in the SSB init.
> Way ahead of the wireless core init. The specs state that the delay value has to be written
> after the wireless core init is nearly done.
> We do _exactly_ that in b43.
>
> The only thing that needs to be done is to add the additional switch statement.
> No MMIO writes have to be touched.
OK, I changed the spec to remove the write.
Larry
^ permalink raw reply
* Re: Issues setting up a 5GHz 802.11N AP
From: Luis R. Rodriguez @ 2010-05-01 18:34 UTC (permalink / raw)
To: Joshua Smith; +Cc: linux-wireless
In-Reply-To: <7F414AFA-E125-40AD-A745-30AEC442B1E8@kaon.com>
On Thu, Apr 29, 2010 at 10:17 AM, Joshua Smith <jesmith@kaon.com> wrote:
> Hello! I hope this is the right mailing this for this question. If not, please redirect me as you see fit!
>
> I am trying to put together a Linux PC that can act as a 5 GHz 802.11N Access Point. I got a lot of conflicting info in my searches, so I figured I'd just buy some hardware and figure out what works.
>
> I am using this kernel:
>
> Linux vosk 2.6.27.8 #1 SMP Sun Dec 7 08:30:31 i686 Intel(R) Core(TM) i7 CPU 930 @ 2.80GHz GenuineIntel GNU/Linux
>
> And I am using compat-wireless 2010-04-26 (complete build).
>
> So far, I have an Intel Wi-Fi Link 6300AGN:
>
> iwlagn 0000:07:00.0: Detected Intel(R) Centrino(R) Ultimate-N 6300 AGN, REV=0x74
>
> An Atheros-based Belkin N1 Wireless ExpressCard:
>
> phy1: Atheros AR5418 MAC/BB Rev:2 AR2122 RF Rev:81 mem=0xf9fa0000, irq=16
>
> And an RaLink-based Asus PCE-N13 PCI adapter:
>
> 03:00.0 Network controller: RaLink RT2860
>
> When I do 'iw list' for these three cards, I find:
>
> Intel: has 5GHz band, but does not support AP mode
> Atheros: supports AP mode, but does not show 5GHz band
> RaLink: supports AP mode, but does not show 5GHz band
>
> I think the Intel is correct. I've found many sources that say this chipset simply does not support AP/Master mode.
>
> However, both the Atheros and RaLink claim to support 300Mbps speeds, which I believe means they should have some 5Ghz channels, right?
No, if you see no 5GHz information with 'iw list' then it means your
cards do not support 5 GHz. Its a physical limitation of the actual
hardware. To support 5 GHz your card would need a 5 GHz radio, and it
simply does not come with one. For your Atheros card specifically the
output shows a AR2122 RF, this is a 2.4 GHz radio only.
Luis
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Michael Buesch @ 2010-05-01 18:40 UTC (permalink / raw)
To: Larry Finger
Cc: Gábor Stefanik, John W. Linville, linux-wireless, b43-dev
In-Reply-To: <4BDC729E.5060202@lwfinger.net>
On Saturday 01 May 2010 20:27:42 Larry Finger wrote:
> OK, I changed the spec to remove the write.
Uhm, I think the spec was perfecly fine.
--
Greetings, Michael.
^ permalink raw reply
* Re: [PATCH] ssb: Implement fast powerup delay calculation
From: Gábor Stefanik @ 2010-05-01 18:43 UTC (permalink / raw)
To: Michael Buesch; +Cc: Larry Finger, John W. Linville, linux-wireless, b43-dev
In-Reply-To: <201005012040.42916.mb@bu3sch.de>
On Sat, May 1, 2010 at 8:40 PM, Michael Buesch <mb@bu3sch.de> wrote:
> On Saturday 01 May 2010 20:27:42 Larry Finger wrote:
>> OK, I changed the spec to remove the write.
>
> Uhm, I think the spec was perfecly fine.
>
> --
> Greetings, Michael.
>
Yes. The specs stated "do this during 802.11 core init", the problem
was the patch doing the write during ChipCommon init, much earlier.
--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
^ permalink raw reply
* Re: ar9170-fw II
From: Christian Lamparter @ 2010-05-01 20:45 UTC (permalink / raw)
To: David H. Lynch Jr.; +Cc: linux-wireless
In-Reply-To: <4BDC719E.3060505@dlasys.net>
On Saturday 01 May 2010 20:23:26 David H. Lynch Jr. wrote:
> On 05/01/2010 01:19 PM, Christian Lamparter wrote:
> >
> > Well, for starters the ar9170 uses a ZyDas MAC (aka ZD1221)
> > and a AR900x PHY/Radio. Therefore the phy code and registers
> > are very similar to those #definitions you can find in ath9k.
> > And for the MAC code& registers you can look into zd1211rw,
> > or look into drivers/staging/otus (original vendor driver,
> > shares some code with their windows drivers)
> >
> > AFAICT, there are no technical documents about the AR9170
> > solution available w/o signing a NDA with Atheros
> > (probably because the devices are still produced and sold in high quantities?).
> >
> Thanks;
>
> I did just discover a reasonably good 150p spec. In what I received from
> my client. If I can I will share it. I am under an NDA, but the client also
> told me that they received no cooperation from atheros.
hmm, only 150 pages? That's sounds a bit thin, as a matter of
fact I know that the ath5k docs (rf+mac+eeprom) are at least
around 300-400 pages.
Well, we'll see. But just in case, we already have a small
library of hardware docs (but most from different vendors):
http://wireless.kernel.org/en/developers/Documentation/specs
and we would welcome such an addition ;-)
> >> What is available for the ar9170 itself ?
> >> How does the firmware and the linux driver communicate?
> >> Is there an overview of the firmware - what is where ?
> >>
> > not really, apart from the headers of the original firmware
> > and vendor drivers.
> >
> > But if you really need to implement some of your 'features'
> > (what are they, if I may ask?)
>
> I think I can tell you what I am supposed add - I need to be able
> to provide userspace apps with precise timing information for each packet.
> Since i am working on GPL'd code and the results are going to be
> provided to third parties whatever I do is GPL'd too.
if by precise timing you mean "exact mac time in TU/usecs when frame
was received at the radio", then you might have a _problem_.
You see, the firmware already receives fully packed frames from
the MAC processor and only _forwards_ them all [as is] in
one big DMA to the USB subsystem.
(this is done in src/wlan.c handle_rx())
So, unless the HW has a _magic_ flag to enable this capability...
you are sort of screwed :-/.
> Why gets into the NDA.
> Right now i have an NDA with a new client and though I am
> exercising care. But they seem fairly mellow. I am probably just being
> overly cautious.
k, understood.
^ permalink raw reply
* Re: ar9170-fw II
From: Benoit Papillault @ 2010-05-02 7:47 UTC (permalink / raw)
To: Christian Lamparter; +Cc: David H. Lynch Jr., linux-wireless
In-Reply-To: <201005012245.36589.chunkeey@googlemail.com>
Le 01/05/2010 22:45, Christian Lamparter a écrit :
> On Saturday 01 May 2010 20:23:26 David H. Lynch Jr. wrote:
>> I think I can tell you what I am supposed add - I need to be able
>> to provide userspace apps with precise timing information for each packet.
>> Since i am working on GPL'd code and the results are going to be
>> provided to third parties whatever I do is GPL'd too.
>
> if by precise timing you mean "exact mac time in TU/usecs when frame
> was received at the radio", then you might have a _problem_.
> You see, the firmware already receives fully packed frames from
> the MAC processor and only _forwards_ them all [as is] in
> one big DMA to the USB subsystem.
> (this is done in src/wlan.c handle_rx())
>
> So, unless the HW has a _magic_ flag to enable this capability...
> you are sort of screwed :-/.
I would love this feature as well. I have a device to test if that can
help. I share the feeling of Christian however... but maybe your
documentation says something about a special flag.
Regards,
Benoit
^ permalink raw reply
* Re: [PATCH] rtl8180: fix tx status reporting
From: Adrian Bassett @ 2010-05-02 9:02 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <1272496482-12687-1-git-send-email-linville@tuxdriver.com>
John W. Linville <linville@...> writes:
>
> When reporting Tx status, indicate that only one rate was used.
> Otherwise, the rate is frozen at rate index 0 (i.e. 1Mb/s).
>
> Signed-off-by: John W. Linville <linville@...>
> ---
> drivers/net/wireless/rtl818x/rtl8180_dev.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c
b/drivers/net/wireless/rtl818x/rtl8180_dev.c
> index d84ad05..8487327 100644
> --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
> +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
> @@ -188,6 +188,7 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev,
unsigned int prio)
> info->flags |= IEEE80211_TX_STAT_ACK;
>
> info->status.rates[0].count = (flags & 0xFF) + 1;
> + info->status.rates[1].idx = -1;
>
> ieee80211_tx_status_irqsafe(dev, skb);
> if (ring->entries - skb_queue_len(&ring->queue) == 2)
John,
I can confirm that this patch fixes the regression reported in the thread at
http://marc.info/?l=linux-wireless&m=123720659723688&w=2 so that the rtl8180
wireless driver and the minstrel rate controller now play together OK. I would
endorse the suggestion that this patch is backported to stable. Any chance of
late inclusion in 2.6.34?
Stats for info:
2.6.34-rc6-wl-00-47739-g27957c6
Rate control from /sys/kernel/debug/ieee80211/phy0/rc/name: minstrel
Stats from /sys/kernel/debug/ieee80211/phy0/stations/xx:xx:xx:xx:xx:xx/rc_stats
rate throughput ewma prob this prob this succ/attempt success attempts
P 1 0.9 98.1 100.0 0( 0) 137 142
2 1.8 95.7 100.0 0( 0) 11 11
5.5 4.8 95.7 100.0 0( 0) 11 11
11 9.1 95.7 100.0 0( 0) 11 11
6 5.4 95.9 100.0 0( 0) 18 20
9 8.0 95.2 100.0 0( 0) 14 16
12 10.5 95.3 100.0 0( 0) 13 14
18 15.5 95.2 100.0 0( 0) 21 28
24 20.3 95.4 100.0 0( 0) 65 110
t 36 24.8 81.5 100.0 0( 0) 443 600
T 48 34.7 89.0 100.0 1( 1) 5348 6735
54 17.8 41.1 25.0 0( 0) 16939 20381
Total packet count:: ideal 2794 lookaround 147
Thanks,
Adrian Bassett
^ permalink raw reply
* Re: ar9170-fw II
From: David H. Lynch Jr. @ 2010-05-02 11:14 UTC (permalink / raw)
To: Benoit Papillault; +Cc: Christian Lamparter, linux-wireless
In-Reply-To: <4BDD2E05.40203@free.fr>
On 05/02/2010 03:47 AM, Benoit Papillault wrote:
> Le 01/05/2010 22:45, Christian Lamparter a écrit :
>> On Saturday 01 May 2010 20:23:26 David H. Lynch Jr. wrote:
>>> I think I can tell you what I am supposed add - I need to be able
>>> to provide userspace apps with precise timing information for each
>>> packet.
>>> Since i am working on GPL'd code and the results are going to be
>>> provided to third parties whatever I do is GPL'd too.
>>
>> if by precise timing you mean "exact mac time in TU/usecs when frame
>> was received at the radio", then you might have a _problem_.
>> You see, the firmware already receives fully packed frames from
>> the MAC processor and only _forwards_ them all [as is] in
>> one big DMA to the USB subsystem.
>> (this is done in src/wlan.c handle_rx())
>>
>> So, unless the HW has a _magic_ flag to enable this capability...
>> you are sort of screwed :-/.
>
> I would love this feature as well. I have a device to test if that can
> help. I share the feeling of Christian however... but maybe your
> documentation says something about a special flag.
I am interested in round trip time as measured from some fixed point
in the sending process to some fixed point in the packet acknowledgement.
The more accurate the better. Preferably measured by events at the
radio rather than on the linux side. I am interested in tx packets
rather than rx packets.
If necessary I can measure the times myself as delta's from one
event to another withing the SH2.
I have not digested the docs I have thoroughly yet but a cursory
review suggests a less than trivial project.
I have not yet found a good high resolution clock inside the ar9170
there are alot of clocks but they all seem to be 16bit. Probably that
will make things harder.
I was expecting to have to make changes to the ar9170 firmware. I
was expecting to have to devise some means of passing that information
to the Linux driver and to the userspace application. I would be happy
to do that in some fashion that conformed to an existing or future
standard, but I was not anticipating a broad desire for what I am
doing. Variable latencies are highly undesirable in this application,
but the userspace application will be aggregating large amounts of
information, if latencies in what is measured are constrained and the
unit of time measurement is small enough everything will work.
If it comes to that we switch to different hardware, but my project
is bringing a concept that was demonstrated with an expensive SDR to an
ar9170.
I am still coming up to speed on some aspects of Wireless - I am
not a complete noob, I have done ethernet drivers, and other very low
level work. I have also worked with non-802.11 wireless, and network
communications. But three days ago I had only cursory understanding of
how 802.11 works.
I already greatly appreciate your assistance.
>
> Regards,
> Benoit
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.587.7774 dhlii@dlasys.net http://www.dlasys.net
Over 25 years' experience in platforms, languages, and technologies too numerous to list.
"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
^ permalink raw reply
* Re: ar9170-fw II
From: Christian Lamparter @ 2010-05-02 12:52 UTC (permalink / raw)
To: David H. Lynch Jr.; +Cc: Benoit Papillault, linux-wireless
In-Reply-To: <4BDD5EB3.7020802@dlasys.net>
On Sunday 02 May 2010 13:14:59 David H. Lynch Jr. wrote:
> On 05/02/2010 03:47 AM, Benoit Papillault wrote:
> > Le 01/05/2010 22:45, Christian Lamparter a écrit :
> >> On Saturday 01 May 2010 20:23:26 David H. Lynch Jr. wrote:
> >>> I think I can tell you what I am supposed add - I need to be able
> >>> to provide userspace apps with precise timing information for each
> >>> packet.
> >>> Since i am working on GPL'd code and the results are going to be
> >>> provided to third parties whatever I do is GPL'd too.
> >>
> >> if by precise timing you mean "exact mac time in TU/usecs when frame
> >> was received at the radio", then you might have a _problem_.
> >> You see, the firmware already receives fully packed frames from
> >> the MAC processor and only _forwards_ them all [as is] in
> >> one big DMA to the USB subsystem.
> >> (this is done in src/wlan.c handle_rx())
> >>
> >> So, unless the HW has a _magic_ flag to enable this capability...
> >> you are sort of screwed :-/.
> >
> > I would love this feature as well. I have a device to test if that can
> > help. I share the feeling of Christian however... but maybe your
> > documentation says something about a special flag.
> I am interested in round trip time as measured from some fixed point
> in the sending process to some fixed point in the packet acknowledgement.
> The more accurate the better. Preferably measured by events at the
> radio rather than on the linux side.
> I am interested in tx packets rather than rx packets.
ahh, well... there goes' benoit interest ;).
> If necessary I can measure the times myself as delta's from one
> event to another withing the SH2.
>
> I have not digested the docs I have thoroughly yet but a cursory
> review suggests a less than trivial project.
> I have not yet found a good high resolution clock inside the ar9170
> there are alot of clocks but they all seem to be 16bit. Probably that
> will make things harder.
TSF timer could be used for this. (see 802.11-2007, Section 11 et seq.)
It's a 2^64 bit timer with a 1us resolution and a accuracy _better_
or equal to +/- 0.01%.
The register address are at:
- 0x1c3514 (low, AR9170_MAC_REG_TSF_L, read only)
- 0x1c3518 (high, AR9170_MAC_REG_TSF_H, read only)
But it comes at a small price: this timer is sometimes
update & synchronized (802.11 11.1.3.4 and 11.1.4) in
station or ad-hoc mode. The exact details are hidden
inside MAC chip, but it should be possible to disable
both by selecting the monitor mode.
> I was expecting to have to make changes to the ar9170 firmware. I
> was expecting to have to devise some means of passing that information
> to the Linux driver and to the userspace application.
Well, then you have two more good reasons why to use carl9170:
* the ar9170usb driver and ar9170 firmware don't track tx frames.
carl9170 on the other hand does (every frame has a 8 bit "cookie").
This feature was necessary to generate an accurate tx transmission
feedback report for every individual frame for the driver.
* carl9170 has the ability to store additional per-frame data.
In fact, if you don't need to have a different retry rates
you could realloc the 3 * 32 bit "rr" (as in retry rate)
array in the carl9170_tx_superdesc and _carl9170_tx_superdesc
struct (see wlan.h) for your purposes (storage for your time values).
And if you fetched all the data, everything will be sent
with an ordinary tx status feedback report to the application
(add the timer fields into carl9170_tx_status and _carl9170_tx_status
struct - see fwcmd.h)
(* talked about this earlier, but you never know...
carlu _tool_ already provides a low-level HW driver for userspace.
This has the obvious advantage that you won't need to mess with
the kernel driver and network stacks.
The only work you'll have to do is: get the kernel code for
the MAC & PHY initialization and put it into carlu.
But the framework is already there so it's mostly copy + paste )
> I would be happy to do that in some fashion that conformed to an existing
> or future standard, but I was not anticipating a broad desire for what I am
> doing. Variable latencies are highly undesirable in this application,
> but the userspace application will be aggregating large amounts of
> information, if latencies in what is measured are constrained and the
> unit of time measurement is small enough everything will work.
> If it comes to that we switch to different hardware, but my project
> is bringing a concept that was demonstrated with an expensive SDR to an
> ar9170.
It's always nice to have some "added value" for cheap and generic devices.
e.g.: Atheros AR92xx chips can be used as among other stuff as a
full range spectrum analyzer.
Regards,
Chr
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox