dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'wl12xx-next' into for-linville

This commit is contained in:
Luciano Coelho 2012-06-26 22:43:29 +03:00
commit a572ac1a3d
22 changed files with 1256 additions and 474 deletions

View File

@ -598,8 +598,10 @@ static const int wl12xx_rtable[REG_TABLE_LEN] = {
#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" #define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" #define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
{ {
int ret;
if (wl->chip.id != CHIP_ID_1283_PG20) { if (wl->chip.id != CHIP_ID_1283_PG20) {
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
struct wl127x_rx_mem_pool_addr rx_mem_addr; struct wl127x_rx_mem_pool_addr rx_mem_addr;
@ -616,9 +618,13 @@ static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
rx_mem_addr.addr_extra = rx_mem_addr.addr + 4; rx_mem_addr.addr_extra = rx_mem_addr.addr + 4;
wl1271_write(wl, WL1271_SLV_REG_DATA, ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr,
&rx_mem_addr, sizeof(rx_mem_addr), false); sizeof(rx_mem_addr), false);
if (ret < 0)
return ret;
} }
return 0;
} }
static int wl12xx_identify_chip(struct wl1271 *wl) static int wl12xx_identify_chip(struct wl1271 *wl)
@ -682,64 +688,95 @@ out:
return ret; return ret;
} }
static void wl12xx_top_reg_write(struct wl1271 *wl, int addr, u16 val) static int __must_check wl12xx_top_reg_write(struct wl1271 *wl, int addr,
u16 val)
{ {
int ret;
/* write address >> 1 + 0x30000 to OCP_POR_CTR */ /* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000; addr = (addr >> 1) + 0x30000;
wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr);
if (ret < 0)
goto out;
/* write value to OCP_POR_WDATA */ /* write value to OCP_POR_WDATA */
wl1271_write32(wl, WL12XX_OCP_DATA_WRITE, val); ret = wlcore_write32(wl, WL12XX_OCP_DATA_WRITE, val);
if (ret < 0)
goto out;
/* write 1 to OCP_CMD */ /* write 1 to OCP_CMD */
wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE); ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE);
if (ret < 0)
goto out;
out:
return ret;
} }
static u16 wl12xx_top_reg_read(struct wl1271 *wl, int addr) static int __must_check wl12xx_top_reg_read(struct wl1271 *wl, int addr,
u16 *out)
{ {
u32 val; u32 val;
int timeout = OCP_CMD_LOOP; int timeout = OCP_CMD_LOOP;
int ret;
/* write address >> 1 + 0x30000 to OCP_POR_CTR */ /* write address >> 1 + 0x30000 to OCP_POR_CTR */
addr = (addr >> 1) + 0x30000; addr = (addr >> 1) + 0x30000;
wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr);
if (ret < 0)
return ret;
/* write 2 to OCP_CMD */ /* write 2 to OCP_CMD */
wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ); ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ);
if (ret < 0)
return ret;
/* poll for data ready */ /* poll for data ready */
do { do {
val = wl1271_read32(wl, WL12XX_OCP_DATA_READ); ret = wlcore_read32(wl, WL12XX_OCP_DATA_READ, &val);
if (ret < 0)
return ret;
} while (!(val & OCP_READY_MASK) && --timeout); } while (!(val & OCP_READY_MASK) && --timeout);
if (!timeout) { if (!timeout) {
wl1271_warning("Top register access timed out."); wl1271_warning("Top register access timed out.");
return 0xffff; return -ETIMEDOUT;
} }
/* check data status and return if OK */ /* check data status and return if OK */
if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) if ((val & OCP_STATUS_MASK) != OCP_STATUS_OK) {
return val & 0xffff;
else {
wl1271_warning("Top register access returned error."); wl1271_warning("Top register access returned error.");
return 0xffff; return -EIO;
} }
if (out)
*out = val & 0xffff;
return 0;
} }
static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
{ {
u16 spare_reg; u16 spare_reg;
int ret;
/* Mask bits [2] & [8:4] in the sys_clk_cfg register */ /* Mask bits [2] & [8:4] in the sys_clk_cfg register */
spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg);
if (ret < 0)
return ret;
if (spare_reg == 0xFFFF) if (spare_reg == 0xFFFF)
return -EFAULT; return -EFAULT;
spare_reg |= (BIT(3) | BIT(5) | BIT(6)); spare_reg |= (BIT(3) | BIT(5) | BIT(6));
wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
if (ret < 0)
return ret;
/* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */
wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG, ret = wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG,
WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
if (ret < 0)
return ret;
/* Delay execution for 15msec, to let the HW settle */ /* Delay execution for 15msec, to let the HW settle */
mdelay(15); mdelay(15);
@ -750,8 +787,12 @@ static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
static bool wl128x_is_tcxo_valid(struct wl1271 *wl) static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
{ {
u16 tcxo_detection; u16 tcxo_detection;
int ret;
ret = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG, &tcxo_detection);
if (ret < 0)
return false;
tcxo_detection = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG);
if (tcxo_detection & TCXO_DET_FAILED) if (tcxo_detection & TCXO_DET_FAILED)
return false; return false;
@ -761,8 +802,12 @@ static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
static bool wl128x_is_fref_valid(struct wl1271 *wl) static bool wl128x_is_fref_valid(struct wl1271 *wl)
{ {
u16 fref_detection; u16 fref_detection;
int ret;
ret = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG, &fref_detection);
if (ret < 0)
return false;
fref_detection = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG);
if (fref_detection & FREF_CLK_DETECT_FAIL) if (fref_detection & FREF_CLK_DETECT_FAIL)
return false; return false;
@ -771,11 +816,21 @@ static bool wl128x_is_fref_valid(struct wl1271 *wl)
static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl)
{ {
wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); int ret;
wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL);
return 0; ret = wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
if (ret < 0)
goto out;
ret = wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
if (ret < 0)
goto out;
ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG,
MCS_PLL_CONFIG_REG_VAL);
out:
return ret;
} }
static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
@ -784,13 +839,19 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
u16 pll_config; u16 pll_config;
u8 input_freq; u8 input_freq;
struct wl12xx_priv *priv = wl->priv; struct wl12xx_priv *priv = wl->priv;
int ret;
/* Mask bits [3:1] in the sys_clk_cfg register */ /* Mask bits [3:1] in the sys_clk_cfg register */
spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg);
if (ret < 0)
return ret;
if (spare_reg == 0xFFFF) if (spare_reg == 0xFFFF)
return -EFAULT; return -EFAULT;
spare_reg |= BIT(2); spare_reg |= BIT(2);
wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
if (ret < 0)
return ret;
/* Handle special cases of the TCXO clock */ /* Handle special cases of the TCXO clock */
if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
@ -800,14 +861,17 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
/* Set the input frequency according to the selected clock source */ /* Set the input frequency according to the selected clock source */
input_freq = (clk & 1) + 1; input_freq = (clk & 1) + 1;
pll_config = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG); ret = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG, &pll_config);
if (ret < 0)
return ret;
if (pll_config == 0xFFFF) if (pll_config == 0xFFFF)
return -EFAULT; return -EFAULT;
pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT);
pll_config |= MCS_PLL_ENABLE_HP; pll_config |= MCS_PLL_ENABLE_HP;
wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config);
return 0; return ret;
} }
/* /*
@ -821,6 +885,7 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
{ {
struct wl12xx_priv *priv = wl->priv; struct wl12xx_priv *priv = wl->priv;
u16 sys_clk_cfg; u16 sys_clk_cfg;
int ret;
/* For XTAL-only modes, FREF will be used after switching from TCXO */ /* For XTAL-only modes, FREF will be used after switching from TCXO */
if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL || if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
@ -831,7 +896,10 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
} }
/* Query the HW, to determine which clock source we should use */ /* Query the HW, to determine which clock source we should use */
sys_clk_cfg = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG); ret = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG, &sys_clk_cfg);
if (ret < 0)
return ret;
if (sys_clk_cfg == 0xFFFF) if (sys_clk_cfg == 0xFFFF)
return -EINVAL; return -EINVAL;
if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF)
@ -866,6 +934,7 @@ static int wl127x_boot_clk(struct wl1271 *wl)
struct wl12xx_priv *priv = wl->priv; struct wl12xx_priv *priv = wl->priv;
u32 pause; u32 pause;
u32 clk; u32 clk;
int ret;
if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION; wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION;
@ -886,48 +955,74 @@ static int wl127x_boot_clk(struct wl1271 *wl)
if (priv->ref_clock != CONF_REF_CLK_19_2_E) { if (priv->ref_clock != CONF_REF_CLK_19_2_E) {
u16 val; u16 val;
/* Set clock type (open drain) */ /* Set clock type (open drain) */
val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE); ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE, &val);
if (ret < 0)
goto out;
val &= FREF_CLK_TYPE_BITS; val &= FREF_CLK_TYPE_BITS;
wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val); ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
if (ret < 0)
goto out;
/* Set clock pull mode (no pull) */ /* Set clock pull mode (no pull) */
val = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL); ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL, &val);
if (ret < 0)
goto out;
val |= NO_PULL; val |= NO_PULL;
wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val); ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val);
if (ret < 0)
goto out;
} else { } else {
u16 val; u16 val;
/* Set clock polarity */ /* Set clock polarity */
val = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY); ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY, &val);
if (ret < 0)
goto out;
val &= FREF_CLK_POLARITY_BITS; val &= FREF_CLK_POLARITY_BITS;
val |= CLK_REQ_OUTN_SEL; val |= CLK_REQ_OUTN_SEL;
wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
if (ret < 0)
goto out;
} }
wl1271_write32(wl, WL12XX_PLL_PARAMETERS, clk); ret = wlcore_write32(wl, WL12XX_PLL_PARAMETERS, clk);
if (ret < 0)
goto out;
pause = wl1271_read32(wl, WL12XX_PLL_PARAMETERS); ret = wlcore_read32(wl, WL12XX_PLL_PARAMETERS, &pause);
if (ret < 0)
goto out;
wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
pause &= ~(WU_COUNTER_PAUSE_VAL); pause &= ~(WU_COUNTER_PAUSE_VAL);
pause |= WU_COUNTER_PAUSE_VAL; pause |= WU_COUNTER_PAUSE_VAL;
wl1271_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause); ret = wlcore_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause);
return 0; out:
return ret;
} }
static int wl1271_boot_soft_reset(struct wl1271 *wl) static int wl1271_boot_soft_reset(struct wl1271 *wl)
{ {
unsigned long timeout; unsigned long timeout;
u32 boot_data; u32 boot_data;
int ret = 0;
/* perform soft reset */ /* perform soft reset */
wl1271_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); ret = wlcore_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
if (ret < 0)
goto out;
/* SOFT_RESET is self clearing */ /* SOFT_RESET is self clearing */
timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
while (1) { while (1) {
boot_data = wl1271_read32(wl, WL12XX_SLV_SOFT_RESET); ret = wlcore_read32(wl, WL12XX_SLV_SOFT_RESET, &boot_data);
if (ret < 0)
goto out;
wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break; break;
@ -943,12 +1038,15 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
} }
/* disable Rx/Tx */ /* disable Rx/Tx */
wl1271_write32(wl, WL12XX_ENABLE, 0x0); ret = wlcore_write32(wl, WL12XX_ENABLE, 0x0);
if (ret < 0)
goto out;
/* disable auto calibration on start*/ /* disable auto calibration on start*/
wl1271_write32(wl, WL12XX_SPARE_A2, 0xffff); ret = wlcore_write32(wl, WL12XX_SPARE_A2, 0xffff);
return 0; out:
return ret;
} }
static int wl12xx_pre_boot(struct wl1271 *wl) static int wl12xx_pre_boot(struct wl1271 *wl)
@ -969,16 +1067,23 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
} }
/* Continue the ELP wake up sequence */ /* Continue the ELP wake up sequence */
wl1271_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
if (ret < 0)
goto out;
udelay(500); udelay(500);
wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
if (ret < 0)
goto out;
/* Read-modify-write DRPW_SCRATCH_START register (see next state) /* Read-modify-write DRPW_SCRATCH_START register (see next state)
to be used by DRPw FW. The RTRIM value will be added by the FW to be used by DRPw FW. The RTRIM value will be added by the FW
before taking DRPw out of reset */ before taking DRPw out of reset */
clk = wl1271_read32(wl, WL12XX_DRPW_SCRATCH_START); ret = wlcore_read32(wl, WL12XX_DRPW_SCRATCH_START, &clk);
if (ret < 0)
goto out;
wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
@ -987,12 +1092,18 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
else else
clk |= (priv->ref_clock << 1) << 4; clk |= (priv->ref_clock << 1) << 4;
wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk); ret = wlcore_write32(wl, WL12XX_DRPW_SCRATCH_START, clk);
if (ret < 0)
goto out;
wlcore_set_partition(wl, &wl->ptable[PART_WORK]); ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
if (ret < 0)
goto out;
/* Disable interrupts */ /* Disable interrupts */
wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
if (ret < 0)
goto out;
ret = wl1271_boot_soft_reset(wl); ret = wl1271_boot_soft_reset(wl);
if (ret < 0) if (ret < 0)
@ -1002,47 +1113,72 @@ out:
return ret; return ret;
} }
static void wl12xx_pre_upload(struct wl1271 *wl) static int wl12xx_pre_upload(struct wl1271 *wl)
{ {
u32 tmp, polarity; u32 tmp;
u16 polarity;
int ret;
/* write firmware's last address (ie. it's length) to /* write firmware's last address (ie. it's length) to
* ACX_EEPROMLESS_IND_REG */ * ACX_EEPROMLESS_IND_REG */
wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
wl1271_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND); ret = wlcore_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND);
if (ret < 0)
goto out;
tmp = wlcore_read_reg(wl, REG_CHIP_ID_B); ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp);
if (ret < 0)
goto out;
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
/* 6. read the EEPROM parameters */ /* 6. read the EEPROM parameters */
tmp = wl1271_read32(wl, WL12XX_SCR_PAD2); ret = wlcore_read32(wl, WL12XX_SCR_PAD2, &tmp);
if (ret < 0)
goto out;
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
* to upload_fw) */ * to upload_fw) */
if (wl->chip.id == CHIP_ID_1283_PG20) if (wl->chip.id == CHIP_ID_1283_PG20) {
wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
if (ret < 0)
goto out;
}
/* polarity must be set before the firmware is loaded */ /* polarity must be set before the firmware is loaded */
polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY); ret = wl12xx_top_reg_read(wl, OCP_REG_POLARITY, &polarity);
if (ret < 0)
goto out;
/* We use HIGH polarity, so unset the LOW bit */ /* We use HIGH polarity, so unset the LOW bit */
polarity &= ~POLARITY_LOW; polarity &= ~POLARITY_LOW;
wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity); ret = wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity);
out:
return ret;
} }
static void wl12xx_enable_interrupts(struct wl1271 *wl) static int wl12xx_enable_interrupts(struct wl1271 *wl)
{ {
wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL12XX_ACX_ALL_EVENTS_VECTOR); int ret;
ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
WL12XX_ACX_ALL_EVENTS_VECTOR);
if (ret < 0)
goto out;
wlcore_enable_interrupts(wl); wlcore_enable_interrupts(wl);
wlcore_write_reg(wl, REG_INTERRUPT_MASK, ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK)); WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
if (ret < 0)
goto out;
wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL); ret = wlcore_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
out:
return ret;
} }
static int wl12xx_boot(struct wl1271 *wl) static int wl12xx_boot(struct wl1271 *wl)
@ -1057,7 +1193,9 @@ static int wl12xx_boot(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out; goto out;
wl12xx_pre_upload(wl); ret = wl12xx_pre_upload(wl);
if (ret < 0)
goto out;
ret = wlcore_boot_upload_firmware(wl); ret = wlcore_boot_upload_firmware(wl);
if (ret < 0) if (ret < 0)
@ -1067,22 +1205,30 @@ static int wl12xx_boot(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out; goto out;
wl12xx_enable_interrupts(wl); ret = wl12xx_enable_interrupts(wl);
out: out:
return ret; return ret;
} }
static void wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, static int wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
void *buf, size_t len) void *buf, size_t len)
{ {
wl1271_write(wl, cmd_box_addr, buf, len, false); int ret;
wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD);
ret = wlcore_write(wl, cmd_box_addr, buf, len, false);
if (ret < 0)
return ret;
ret = wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD);
return ret;
} }
static void wl12xx_ack_event(struct wl1271 *wl) static int wl12xx_ack_event(struct wl1271 *wl)
{ {
wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_EVENT_ACK); return wlcore_write_reg(wl, REG_INTERRUPT_TRIG,
WL12XX_INTR_TRIG_EVENT_ACK);
} }
static u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) static u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
@ -1162,13 +1308,13 @@ static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
return data_len - sizeof(*desc) - desc->pad_len; return data_len - sizeof(*desc) - desc->pad_len;
} }
static void wl12xx_tx_delayed_compl(struct wl1271 *wl) static int wl12xx_tx_delayed_compl(struct wl1271 *wl)
{ {
if (wl->fw_status_1->tx_results_counter == if (wl->fw_status_1->tx_results_counter ==
(wl->tx_results_count & 0xff)) (wl->tx_results_count & 0xff))
return; return 0;
wl1271_tx_complete(wl); return wlcore_tx_complete(wl);
} }
static int wl12xx_hw_init(struct wl1271 *wl) static int wl12xx_hw_init(struct wl1271 *wl)
@ -1269,39 +1415,58 @@ static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
return supported; return supported;
} }
static void wl12xx_get_fuse_mac(struct wl1271 *wl) static int wl12xx_get_fuse_mac(struct wl1271 *wl)
{ {
u32 mac1, mac2; u32 mac1, mac2;
int ret;
wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
if (ret < 0)
goto out;
mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1); ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1, &mac1);
mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2); if (ret < 0)
goto out;
ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2, &mac2);
if (ret < 0)
goto out;
/* these are the two parts of the BD_ADDR */ /* these are the two parts of the BD_ADDR */
wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
((mac1 & 0xff000000) >> 24); ((mac1 & 0xff000000) >> 24);
wl->fuse_nic_addr = mac1 & 0xffffff; wl->fuse_nic_addr = mac1 & 0xffffff;
wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
out:
return ret;
} }
static s8 wl12xx_get_pg_ver(struct wl1271 *wl) static int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
{ {
u32 die_info; u16 die_info;
int ret;
if (wl->chip.id == CHIP_ID_1283_PG20) if (wl->chip.id == CHIP_ID_1283_PG20)
die_info = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1,
&die_info);
else else
die_info = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); ret = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1,
&die_info);
return (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET; if (ret >= 0 && ver)
*ver = (s8)((die_info & PG_VER_MASK) >> PG_VER_OFFSET);
return ret;
} }
static void wl12xx_get_mac(struct wl1271 *wl) static int wl12xx_get_mac(struct wl1271 *wl)
{ {
if (wl12xx_mac_in_fuse(wl)) if (wl12xx_mac_in_fuse(wl))
wl12xx_get_fuse_mac(wl); return wl12xx_get_fuse_mac(wl);
return 0;
} }
static void wl12xx_set_tx_desc_csum(struct wl1271 *wl, static void wl12xx_set_tx_desc_csum(struct wl1271 *wl,

View File

@ -32,24 +32,20 @@ enum {
/* numbers of bits the length field takes (add 1 for the actual number) */ /* numbers of bits the length field takes (add 1 for the actual number) */
#define WL18XX_HOST_IF_LEN_SIZE_FIELD 15 #define WL18XX_HOST_IF_LEN_SIZE_FIELD 15
#define WL18XX_ACX_EVENTS_VECTOR_PG1 (WL1271_ACX_INTR_WATCHDOG | \ #define WL18XX_ACX_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \
WL1271_ACX_INTR_INIT_COMPLETE | \ WL1271_ACX_INTR_INIT_COMPLETE | \
WL1271_ACX_INTR_EVENT_A | \ WL1271_ACX_INTR_EVENT_A | \
WL1271_ACX_INTR_EVENT_B | \ WL1271_ACX_INTR_EVENT_B | \
WL1271_ACX_INTR_CMD_COMPLETE | \ WL1271_ACX_INTR_CMD_COMPLETE | \
WL1271_ACX_INTR_HW_AVAILABLE | \ WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_DATA) WL1271_ACX_INTR_DATA | \
#define WL18XX_ACX_EVENTS_VECTOR_PG2 (WL18XX_ACX_EVENTS_VECTOR_PG1 | \
WL1271_ACX_SW_INTR_WATCHDOG) WL1271_ACX_SW_INTR_WATCHDOG)
#define WL18XX_INTR_MASK_PG1 (WL1271_ACX_INTR_WATCHDOG | \ #define WL18XX_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \
WL1271_ACX_INTR_EVENT_A | \ WL1271_ACX_INTR_EVENT_A | \
WL1271_ACX_INTR_EVENT_B | \ WL1271_ACX_INTR_EVENT_B | \
WL1271_ACX_INTR_HW_AVAILABLE | \ WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_DATA) WL1271_ACX_INTR_DATA | \
#define WL18XX_INTR_MASK_PG2 (WL18XX_INTR_MASK_PG1 | \
WL1271_ACX_SW_INTR_WATCHDOG) WL1271_ACX_SW_INTR_WATCHDOG)
struct wl18xx_acx_host_config_bitmap { struct wl18xx_acx_host_config_bitmap {

View File

@ -24,37 +24,52 @@
#include "io.h" #include "io.h"
void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val) int wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val)
{ {
u32 tmp; u32 tmp;
int ret;
if (WARN_ON(addr % 2)) if (WARN_ON(addr % 2))
return; return -EINVAL;
if ((addr % 4) == 0) { if ((addr % 4) == 0) {
tmp = wl1271_read32(wl, addr); ret = wlcore_read32(wl, addr, &tmp);
if (ret < 0)
goto out;
tmp = (tmp & 0xffff0000) | val; tmp = (tmp & 0xffff0000) | val;
wl1271_write32(wl, addr, tmp); ret = wlcore_write32(wl, addr, tmp);
} else { } else {
tmp = wl1271_read32(wl, addr - 2); ret = wlcore_read32(wl, addr - 2, &tmp);
if (ret < 0)
goto out;
tmp = (tmp & 0xffff) | (val << 16); tmp = (tmp & 0xffff) | (val << 16);
wl1271_write32(wl, addr - 2, tmp); ret = wlcore_write32(wl, addr - 2, tmp);
}
} }
u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr) out:
return ret;
}
int wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out)
{ {
u32 val; u32 val;
int ret;
if (WARN_ON(addr % 2)) if (WARN_ON(addr % 2))
return 0; return -EINVAL;
if ((addr % 4) == 0) { if ((addr % 4) == 0) {
/* address is 4-bytes aligned */ /* address is 4-bytes aligned */
val = wl1271_read32(wl, addr); ret = wlcore_read32(wl, addr, &val);
return val & 0xffff; if (ret >= 0 && out)
*out = val & 0xffff;
} else { } else {
val = wl1271_read32(wl, addr - 2); ret = wlcore_read32(wl, addr - 2, &val);
return (val & 0xffff0000) >> 16; if (ret >= 0 && out)
*out = (val & 0xffff0000) >> 16;
} }
return ret;
} }

View File

@ -22,7 +22,7 @@
#ifndef __WL18XX_IO_H__ #ifndef __WL18XX_IO_H__
#define __WL18XX_IO_H__ #define __WL18XX_IO_H__
void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val); int __must_check wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val);
u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr); int __must_check wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out);
#endif /* __WL18XX_IO_H__ */ #endif /* __WL18XX_IO_H__ */

View File

@ -612,20 +612,11 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
WLCORE_QUIRK_TX_PAD_LAST_FRAME; WLCORE_QUIRK_TX_PAD_LAST_FRAME;
break; break;
case CHIP_ID_185x_PG10: case CHIP_ID_185x_PG10:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG10)", wl1271_warning("chip id 0x%x (185x PG10) is deprecated",
wl->chip.id); wl->chip.id);
wl->sr_fw_name = WL18XX_FW_NAME; ret = -ENODEV;
/* wl18xx uses the same firmware for PLT */ goto out;
wl->plt_fw_name = WL18XX_FW_NAME;
wl->quirks |= WLCORE_QUIRK_NO_ELP |
WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED |
WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
/* PG 1.0 has some problems with MCS_13, so disable it */
wl->ht_cap[IEEE80211_BAND_2GHZ].mcs.rx_mask[1] &= ~BIT(5);
break;
default: default:
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV; ret = -ENODEV;
@ -636,123 +627,178 @@ out:
return ret; return ret;
} }
static void wl18xx_set_clk(struct wl1271 *wl) static int wl18xx_set_clk(struct wl1271 *wl)
{ {
u32 clk_freq; u16 clk_freq;
int ret;
wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
if (ret < 0)
goto out;
/* TODO: PG2: apparently we need to read the clk type */ /* TODO: PG2: apparently we need to read the clk type */
clk_freq = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT); ret = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT, &clk_freq);
if (ret < 0)
goto out;
wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq, wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq,
wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m, wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m,
wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q, wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q,
wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit"); wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit");
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N, wl18xx_clk_table[clk_freq].n); ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N,
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M, wl18xx_clk_table[clk_freq].m); wl18xx_clk_table[clk_freq].n);
if (ret < 0)
goto out;
ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M,
wl18xx_clk_table[clk_freq].m);
if (ret < 0)
goto out;
if (wl18xx_clk_table[clk_freq].swallow) { if (wl18xx_clk_table[clk_freq].swallow) {
/* first the 16 lower bits */ /* first the 16 lower bits */
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1, ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1,
wl18xx_clk_table[clk_freq].q & wl18xx_clk_table[clk_freq].q &
PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK); PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK);
if (ret < 0)
goto out;
/* then the 16 higher bits, masked out */ /* then the 16 higher bits, masked out */
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2, ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2,
(wl18xx_clk_table[clk_freq].q >> 16) & (wl18xx_clk_table[clk_freq].q >> 16) &
PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK); PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK);
if (ret < 0)
goto out;
/* first the 16 lower bits */ /* first the 16 lower bits */
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1, ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1,
wl18xx_clk_table[clk_freq].p & wl18xx_clk_table[clk_freq].p &
PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK); PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK);
if (ret < 0)
goto out;
/* then the 16 higher bits, masked out */ /* then the 16 higher bits, masked out */
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2, ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2,
(wl18xx_clk_table[clk_freq].p >> 16) & (wl18xx_clk_table[clk_freq].p >> 16) &
PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK); PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK);
} else { } else {
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN, ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN,
PLLSH_WCS_PLL_SWALLOW_EN_VAL2); PLLSH_WCS_PLL_SWALLOW_EN_VAL2);
} }
out:
return ret;
} }
static void wl18xx_boot_soft_reset(struct wl1271 *wl) static int wl18xx_boot_soft_reset(struct wl1271 *wl)
{ {
int ret;
/* disable Rx/Tx */ /* disable Rx/Tx */
wl1271_write32(wl, WL18XX_ENABLE, 0x0); ret = wlcore_write32(wl, WL18XX_ENABLE, 0x0);
if (ret < 0)
goto out;
/* disable auto calibration on start*/ /* disable auto calibration on start*/
wl1271_write32(wl, WL18XX_SPARE_A2, 0xffff); ret = wlcore_write32(wl, WL18XX_SPARE_A2, 0xffff);
out:
return ret;
} }
static int wl18xx_pre_boot(struct wl1271 *wl) static int wl18xx_pre_boot(struct wl1271 *wl)
{ {
wl18xx_set_clk(wl); int ret;
ret = wl18xx_set_clk(wl);
if (ret < 0)
goto out;
/* Continue the ELP wake up sequence */ /* Continue the ELP wake up sequence */
wl1271_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); ret = wlcore_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
if (ret < 0)
goto out;
udelay(500); udelay(500);
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
if (ret < 0)
goto out;
/* Disable interrupts */ /* Disable interrupts */
wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
if (ret < 0)
goto out;
wl18xx_boot_soft_reset(wl); ret = wl18xx_boot_soft_reset(wl);
return 0; out:
return ret;
} }
static void wl18xx_pre_upload(struct wl1271 *wl) static int wl18xx_pre_upload(struct wl1271 *wl)
{ {
u32 tmp; u32 tmp;
int ret;
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
if (ret < 0)
goto out;
/* TODO: check if this is all needed */ /* TODO: check if this is all needed */
wl1271_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND); ret = wlcore_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND);
if (ret < 0)
goto out;
tmp = wlcore_read_reg(wl, REG_CHIP_ID_B); ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp);
if (ret < 0)
goto out;
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
tmp = wl1271_read32(wl, WL18XX_SCR_PAD2); ret = wlcore_read32(wl, WL18XX_SCR_PAD2, &tmp);
out:
return ret;
} }
static void wl18xx_set_mac_and_phy(struct wl1271 *wl) static int wl18xx_set_mac_and_phy(struct wl1271 *wl)
{ {
struct wl18xx_priv *priv = wl->priv; struct wl18xx_priv *priv = wl->priv;
size_t len; int ret;
/* the parameters struct is smaller for PG1 */ ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
if (wl->chip.id == CHIP_ID_185x_PG10) if (ret < 0)
len = offsetof(struct wl18xx_mac_and_phy_params, psat) + 1; goto out;
else
len = sizeof(struct wl18xx_mac_and_phy_params);
wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]); ret = wlcore_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy,
wl1271_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy, len, sizeof(struct wl18xx_mac_and_phy_params), false);
false);
out:
return ret;
} }
static void wl18xx_enable_interrupts(struct wl1271 *wl) static int wl18xx_enable_interrupts(struct wl1271 *wl)
{ {
u32 event_mask, intr_mask; u32 event_mask, intr_mask;
int ret;
if (wl->chip.id == CHIP_ID_185x_PG10) { event_mask = WL18XX_ACX_EVENTS_VECTOR;
event_mask = WL18XX_ACX_EVENTS_VECTOR_PG1; intr_mask = WL18XX_INTR_MASK;
intr_mask = WL18XX_INTR_MASK_PG1;
} else {
event_mask = WL18XX_ACX_EVENTS_VECTOR_PG2;
intr_mask = WL18XX_INTR_MASK_PG2;
}
wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask); ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask);
if (ret < 0)
goto out;
wlcore_enable_interrupts(wl); wlcore_enable_interrupts(wl);
wlcore_write_reg(wl, REG_INTERRUPT_MASK,
ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~intr_mask); WL1271_ACX_INTR_ALL & ~intr_mask);
out:
return ret;
} }
static int wl18xx_boot(struct wl1271 *wl) static int wl18xx_boot(struct wl1271 *wl)
@ -763,25 +809,29 @@ static int wl18xx_boot(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out; goto out;
wl18xx_pre_upload(wl); ret = wl18xx_pre_upload(wl);
if (ret < 0)
goto out;
ret = wlcore_boot_upload_firmware(wl); ret = wlcore_boot_upload_firmware(wl);
if (ret < 0) if (ret < 0)
goto out; goto out;
wl18xx_set_mac_and_phy(wl); ret = wl18xx_set_mac_and_phy(wl);
if (ret < 0)
goto out;
ret = wlcore_boot_run_firmware(wl); ret = wlcore_boot_run_firmware(wl);
if (ret < 0) if (ret < 0)
goto out; goto out;
wl18xx_enable_interrupts(wl); ret = wl18xx_enable_interrupts(wl);
out: out:
return ret; return ret;
} }
static void wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, static int wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
void *buf, size_t len) void *buf, size_t len)
{ {
struct wl18xx_priv *priv = wl->priv; struct wl18xx_priv *priv = wl->priv;
@ -789,13 +839,14 @@ static void wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
memcpy(priv->cmd_buf, buf, len); memcpy(priv->cmd_buf, buf, len);
memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len); memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len);
wl1271_write(wl, cmd_box_addr, priv->cmd_buf, WL18XX_CMD_MAX_SIZE, return wlcore_write(wl, cmd_box_addr, priv->cmd_buf,
false); WL18XX_CMD_MAX_SIZE, false);
} }
static void wl18xx_ack_event(struct wl1271 *wl) static int wl18xx_ack_event(struct wl1271 *wl)
{ {
wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL18XX_INTR_TRIG_EVENT_ACK); return wlcore_write_reg(wl, REG_INTERRUPT_TRIG,
WL18XX_INTR_TRIG_EVENT_ACK);
} }
static u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) static u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
@ -977,34 +1028,32 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
} else if (!strcmp(ht_mode_param, "mimo")) { } else if (!strcmp(ht_mode_param, "mimo")) {
wl1271_debug(DEBUG_ACX, "using MIMO rate mask"); wl1271_debug(DEBUG_ACX, "using MIMO rate mask");
/*
* PG 1.0 has some problems with MCS_13, so disable it
*
* TODO: instead of hacking this in here, we should
* make it more general and change a bit in the
* wlvif->rate_set instead.
*/
if (wl->chip.id == CHIP_ID_185x_PG10)
return CONF_TX_MIMO_RATES & ~CONF_HW_BIT_RATE_MCS_13;
return CONF_TX_MIMO_RATES; return CONF_TX_MIMO_RATES;
} else { } else {
return 0; return 0;
} }
} }
static s8 wl18xx_get_pg_ver(struct wl1271 *wl) static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
{ {
u32 fuse; u32 fuse;
int ret;
wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
if (ret < 0)
goto out;
fuse = wl1271_read32(wl, WL18XX_REG_FUSE_DATA_1_3); ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse);
fuse = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; if (ret < 0)
goto out;
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); if (ver)
*ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
return (s8)fuse; ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
out:
return ret;
} }
#define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin" #define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin"
@ -1070,26 +1119,41 @@ out:
static int wl18xx_plt_init(struct wl1271 *wl) static int wl18xx_plt_init(struct wl1271 *wl)
{ {
wl1271_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT); int ret;
ret = wlcore_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT);
if (ret < 0)
return ret;
return wl->ops->boot(wl); return wl->ops->boot(wl);
} }
static void wl18xx_get_mac(struct wl1271 *wl) static int wl18xx_get_mac(struct wl1271 *wl)
{ {
u32 mac1, mac2; u32 mac1, mac2;
int ret;
wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
if (ret < 0)
goto out;
mac1 = wl1271_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1); ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1, &mac1);
mac2 = wl1271_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2); if (ret < 0)
goto out;
ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2, &mac2);
if (ret < 0)
goto out;
/* these are the two parts of the BD_ADDR */ /* these are the two parts of the BD_ADDR */
wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
((mac1 & 0xff000000) >> 24); ((mac1 & 0xff000000) >> 24);
wl->fuse_nic_addr = (mac1 & 0xffffff); wl->fuse_nic_addr = (mac1 & 0xffffff);
wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
out:
return ret;
} }
static int wl18xx_handle_static_data(struct wl1271 *wl, static int wl18xx_handle_static_data(struct wl1271 *wl,

View File

@ -33,16 +33,22 @@
#include "rx.h" #include "rx.h"
#include "hw_ops.h" #include "hw_ops.h"
static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) static int wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
{ {
u32 cpu_ctrl; u32 cpu_ctrl;
int ret;
/* 10.5.0 run the firmware (I) */ /* 10.5.0 run the firmware (I) */
cpu_ctrl = wlcore_read_reg(wl, REG_ECPU_CONTROL); ret = wlcore_read_reg(wl, REG_ECPU_CONTROL, &cpu_ctrl);
if (ret < 0)
goto out;
/* 10.5.1 run the firmware (II) */ /* 10.5.1 run the firmware (II) */
cpu_ctrl |= flag; cpu_ctrl |= flag;
wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl); ret = wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
out:
return ret;
} }
static int wlcore_boot_parse_fw_ver(struct wl1271 *wl, static int wlcore_boot_parse_fw_ver(struct wl1271 *wl,
@ -87,7 +93,9 @@ static int wlcore_boot_static_data(struct wl1271 *wl)
goto out; goto out;
} }
wl1271_read(wl, wl->cmd_box_addr, static_data, len, false); ret = wlcore_read(wl, wl->cmd_box_addr, static_data, len, false);
if (ret < 0)
goto out_free;
ret = wlcore_boot_parse_fw_ver(wl, static_data); ret = wlcore_boot_parse_fw_ver(wl, static_data);
if (ret < 0) if (ret < 0)
@ -109,6 +117,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
struct wlcore_partition_set partition; struct wlcore_partition_set partition;
int addr, chunk_num, partition_limit; int addr, chunk_num, partition_limit;
u8 *p, *chunk; u8 *p, *chunk;
int ret;
/* whal_FwCtrl_LoadFwImageSm() */ /* whal_FwCtrl_LoadFwImageSm() */
@ -130,7 +139,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition)); memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition));
partition.mem.start = dest; partition.mem.start = dest;
wlcore_set_partition(wl, &partition); ret = wlcore_set_partition(wl, &partition);
if (ret < 0)
return ret;
/* 10.1 set partition limit and chunk num */ /* 10.1 set partition limit and chunk num */
chunk_num = 0; chunk_num = 0;
@ -144,7 +155,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
partition_limit = chunk_num * CHUNK_SIZE + partition_limit = chunk_num * CHUNK_SIZE +
wl->ptable[PART_DOWN].mem.size; wl->ptable[PART_DOWN].mem.size;
partition.mem.start = addr; partition.mem.start = addr;
wlcore_set_partition(wl, &partition); ret = wlcore_set_partition(wl, &partition);
if (ret < 0)
return ret;
} }
/* 10.3 upload the chunk */ /* 10.3 upload the chunk */
@ -153,7 +166,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, CHUNK_SIZE); memcpy(chunk, p, CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr); p, addr);
wl1271_write(wl, addr, chunk, CHUNK_SIZE, false); ret = wlcore_write(wl, addr, chunk, CHUNK_SIZE, false);
if (ret < 0)
goto out;
chunk_num++; chunk_num++;
} }
@ -164,10 +179,11 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, fw_data_len % CHUNK_SIZE); memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr); fw_data_len % CHUNK_SIZE, p, addr);
wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); ret = wlcore_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
out:
kfree(chunk); kfree(chunk);
return 0; return ret;
} }
int wlcore_boot_upload_firmware(struct wl1271 *wl) int wlcore_boot_upload_firmware(struct wl1271 *wl)
@ -210,6 +226,7 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
int i; int i;
u32 dest_addr, val; u32 dest_addr, val;
u8 *nvs_ptr, *nvs_aligned; u8 *nvs_ptr, *nvs_aligned;
int ret;
if (wl->nvs == NULL) { if (wl->nvs == NULL) {
wl1271_error("NVS file is needed during boot"); wl1271_error("NVS file is needed during boot");
@ -307,7 +324,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, wl1271_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x", "nvs burst write 0x%x: 0x%x",
dest_addr, val); dest_addr, val);
wl1271_write32(wl, dest_addr, val); ret = wlcore_write32(wl, dest_addr, val);
if (ret < 0)
return ret;
nvs_ptr += 4; nvs_ptr += 4;
dest_addr += 4; dest_addr += 4;
@ -333,7 +352,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
nvs_len -= nvs_ptr - (u8 *)wl->nvs; nvs_len -= nvs_ptr - (u8 *)wl->nvs;
/* Now we must set the partition correctly */ /* Now we must set the partition correctly */
wlcore_set_partition(wl, &wl->ptable[PART_WORK]); ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
if (ret < 0)
return ret;
/* Copy the NVS tables to a new block to ensure alignment */ /* Copy the NVS tables to a new block to ensure alignment */
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
@ -341,11 +362,11 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
return -ENOMEM; return -ENOMEM;
/* And finally we upload the NVS tables */ /* And finally we upload the NVS tables */
wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, ret = wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, nvs_aligned, nvs_len,
nvs_aligned, nvs_len, false); false);
kfree(nvs_aligned); kfree(nvs_aligned);
return 0; return ret;
out_badnvs: out_badnvs:
wl1271_error("nvs data is malformed"); wl1271_error("nvs data is malformed");
@ -359,11 +380,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
u32 chip_id, intr; u32 chip_id, intr;
/* Make sure we have the boot partition */ /* Make sure we have the boot partition */
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
if (ret < 0)
return ret;
wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); ret = wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
if (ret < 0)
return ret;
chip_id = wlcore_read_reg(wl, REG_CHIP_ID_B); ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &chip_id);
if (ret < 0)
return ret;
wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
@ -376,7 +403,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
loop = 0; loop = 0;
while (loop++ < INIT_LOOP) { while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY); udelay(INIT_LOOP_DELAY);
intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0)
return ret;
if (intr == 0xffffffff) { if (intr == 0xffffffff) {
wl1271_error("error reading hardware complete " wl1271_error("error reading hardware complete "
@ -385,8 +414,10 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
} }
/* check that ACX_INTR_INIT_COMPLETE is enabled */ /* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
wlcore_write_reg(wl, REG_INTERRUPT_ACK, ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE); WL1271_ACX_INTR_INIT_COMPLETE);
if (ret < 0)
return ret;
break; break;
} }
} }
@ -398,12 +429,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
} }
/* get hardware config command mail box */ /* get hardware config command mail box */
wl->cmd_box_addr = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR); ret = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR, &wl->cmd_box_addr);
if (ret < 0)
return ret;
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr); wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr);
/* get hardware config event mail box */ /* get hardware config event mail box */
wl->mbox_ptr[0] = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR); ret = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR, &wl->mbox_ptr[0]);
if (ret < 0)
return ret;
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x", wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
@ -445,9 +481,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
} }
/* set the working partition to its "running" mode offset */ /* set the working partition to its "running" mode offset */
wlcore_set_partition(wl, &wl->ptable[PART_WORK]); ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
/* firmware startup completed */ /* firmware startup completed */
return 0; return ret;
} }
EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware); EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware);

View File

@ -65,17 +65,24 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
WARN_ON(len % 4 != 0); WARN_ON(len % 4 != 0);
WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags));
wl1271_write(wl, wl->cmd_box_addr, buf, len, false); ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false);
if (ret < 0)
goto fail;
/* /*
* TODO: we just need this because one bit is in a different * TODO: we just need this because one bit is in a different
* place. Is there any better way? * place. Is there any better way?
*/ */
wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len);
if (ret < 0)
goto fail;
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0)
goto fail;
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout"); wl1271_error("command complete timeout");
@ -89,13 +96,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
else else
msleep(1); msleep(1);
intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0)
goto fail;
} }
/* read back the status code of the command */ /* read back the status code of the command */
if (res_len == 0) if (res_len == 0)
res_len = sizeof(struct wl1271_cmd_header); res_len = sizeof(struct wl1271_cmd_header);
wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false);
ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false);
if (ret < 0)
goto fail;
status = le16_to_cpu(cmd->status); status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) { if (status != CMD_STATUS_SUCCESS) {
@ -104,11 +116,14 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
goto fail; goto fail;
} }
wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
if (ret < 0)
goto fail;
return 0; return 0;
fail: fail:
WARN_ON(1);
wl12xx_queue_recovery_work(wl); wl12xx_queue_recovery_work(wl);
return ret; return ret;
} }
@ -117,35 +132,45 @@ fail:
* Poll the mailbox event field until any of the bits in the mask is set or a * Poll the mailbox event field until any of the bits in the mask is set or a
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs) * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
*/ */
static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
u32 mask, bool *timeout)
{ {
u32 *events_vector; u32 *events_vector;
u32 event; u32 event;
unsigned long timeout; unsigned long timeout_time;
int ret = 0; int ret = 0;
*timeout = false;
events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA); events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA);
if (!events_vector) if (!events_vector)
return -ENOMEM; return -ENOMEM;
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
do { do {
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout_time)) {
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
(int)mask); (int)mask);
ret = -ETIMEDOUT; *timeout = true;
goto out; goto out;
} }
msleep(1); msleep(1);
/* read from both event fields */ /* read from both event fields */
wl1271_read(wl, wl->mbox_ptr[0], events_vector, ret = wlcore_read(wl, wl->mbox_ptr[0], events_vector,
sizeof(*events_vector), false); sizeof(*events_vector), false);
if (ret < 0)
goto out;
event = *events_vector & mask; event = *events_vector & mask;
wl1271_read(wl, wl->mbox_ptr[1], events_vector,
ret = wlcore_read(wl, wl->mbox_ptr[1], events_vector,
sizeof(*events_vector), false); sizeof(*events_vector), false);
if (ret < 0)
goto out;
event |= *events_vector & mask; event |= *events_vector & mask;
} while (!event); } while (!event);
@ -157,9 +182,10 @@ out:
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
{ {
int ret; int ret;
bool timeout = false;
ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout);
if (ret != 0) { if (ret != 0 || timeout) {
wl12xx_queue_recovery_work(wl); wl12xx_queue_recovery_work(wl);
return ret; return ret;
} }
@ -1412,6 +1438,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
{ {
struct wl12xx_cmd_remove_peer *cmd; struct wl12xx_cmd_remove_peer *cmd;
int ret; int ret;
bool timeout = false;
wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid);
@ -1432,12 +1459,16 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
goto out_free; goto out_free;
} }
ret = wl1271_cmd_wait_for_event_or_timeout(wl,
PEER_REMOVE_COMPLETE_EVENT_ID,
&timeout);
/* /*
* We are ok with a timeout here. The event is sometimes not sent * We are ok with a timeout here. The event is sometimes not sent
* due to a firmware bug. * due to a firmware bug. In case of another error (like SDIO timeout)
* queue a recovery.
*/ */
wl1271_cmd_wait_for_event_or_timeout(wl, if (ret)
PEER_REMOVE_COMPLETE_EVENT_ID); wl12xx_queue_recovery_work(wl);
out_free: out_free:
kfree(cmd); kfree(cmd);
@ -1754,7 +1785,9 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
return -EINVAL; return -EINVAL;
/* flush all pending packets */ /* flush all pending packets */
wl1271_tx_work_locked(wl); ret = wlcore_tx_work_locked(wl);
if (ret < 0)
goto out;
if (test_bit(wlvif->dev_role_id, wl->roc_map)) { if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
ret = wl12xx_croc(wl, wlvif->dev_role_id); ret = wl12xx_croc(wl, wlvif->dev_role_id);

View File

@ -38,6 +38,8 @@
/* ms */ /* ms */
#define WL1271_DEBUGFS_STATS_LIFETIME 1000 #define WL1271_DEBUGFS_STATS_LIFETIME 1000
#define WLCORE_MAX_BLOCK_SIZE ((size_t)(4*PAGE_SIZE))
/* debugfs macros idea from mac80211 */ /* debugfs macros idea from mac80211 */
int wl1271_format_buffer(char __user *userbuf, size_t count, int wl1271_format_buffer(char __user *userbuf, size_t count,
loff_t *ppos, char *fmt, ...) loff_t *ppos, char *fmt, ...)
@ -1025,6 +1027,195 @@ static const struct file_operations sleep_auth_ops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t dev_mem_read(struct file *file,
char __user *user_buf, size_t count,
loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
struct wlcore_partition_set part, old_part;
size_t bytes = count;
int ret;
char *buf;
/* only requests of dword-aligned size and offset are supported */
if (bytes % 4)
return -EINVAL;
if (*ppos % 4)
return -EINVAL;
/* function should return in reasonable time */
bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
if (bytes == 0)
return -EINVAL;
memset(&part, 0, sizeof(part));
part.mem.start = file->f_pos;
part.mem.size = bytes;
buf = kmalloc(bytes, GFP_KERNEL);
if (!buf)
return -ENOMEM;
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
ret = -EFAULT;
goto skip_read;
}
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto skip_read;
/* store current partition and switch partition */
memcpy(&old_part, &wl->curr_part, sizeof(old_part));
ret = wlcore_set_partition(wl, &part);
if (ret < 0)
goto part_err;
ret = wlcore_raw_read(wl, 0, buf, bytes, false);
if (ret < 0)
goto read_err;
read_err:
/* recover partition */
ret = wlcore_set_partition(wl, &old_part);
if (ret < 0)
goto part_err;
part_err:
wl1271_ps_elp_sleep(wl);
skip_read:
mutex_unlock(&wl->mutex);
if (ret == 0) {
ret = copy_to_user(user_buf, buf, bytes);
if (ret < bytes) {
bytes -= ret;
*ppos += bytes;
ret = 0;
} else {
ret = -EFAULT;
}
}
kfree(buf);
return ((ret == 0) ? bytes : ret);
}
static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct wl1271 *wl = file->private_data;
struct wlcore_partition_set part, old_part;
size_t bytes = count;
int ret;
char *buf;
/* only requests of dword-aligned size and offset are supported */
if (bytes % 4)
return -EINVAL;
if (*ppos % 4)
return -EINVAL;
/* function should return in reasonable time */
bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
if (bytes == 0)
return -EINVAL;
memset(&part, 0, sizeof(part));
part.mem.start = file->f_pos;
part.mem.size = bytes;
buf = kmalloc(bytes, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = copy_from_user(buf, user_buf, bytes);
if (ret) {
ret = -EFAULT;
goto err_out;
}
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
ret = -EFAULT;
goto skip_write;
}
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto skip_write;
/* store current partition and switch partition */
memcpy(&old_part, &wl->curr_part, sizeof(old_part));
ret = wlcore_set_partition(wl, &part);
if (ret < 0)
goto part_err;
ret = wlcore_raw_write(wl, 0, buf, bytes, false);
if (ret < 0)
goto write_err;
write_err:
/* recover partition */
ret = wlcore_set_partition(wl, &old_part);
if (ret < 0)
goto part_err;
part_err:
wl1271_ps_elp_sleep(wl);
skip_write:
mutex_unlock(&wl->mutex);
if (ret == 0)
*ppos += bytes;
err_out:
kfree(buf);
return ((ret == 0) ? bytes : ret);
}
static loff_t dev_mem_seek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
/* only requests of dword-aligned size and offset are supported */
if (offset % 4)
return -EINVAL;
switch (orig) {
case SEEK_SET:
file->f_pos = offset;
ret = file->f_pos;
break;
case SEEK_CUR:
file->f_pos += offset;
ret = file->f_pos;
break;
default:
ret = -EINVAL;
}
return ret;
}
static const struct file_operations dev_mem_ops = {
.open = simple_open,
.read = dev_mem_read,
.write = dev_mem_write,
.llseek = dev_mem_seek,
};
static int wl1271_debugfs_add_files(struct wl1271 *wl, static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir) struct dentry *rootdir)
{ {
@ -1059,6 +1250,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming); DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming);
DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming); DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming);
DEBUGFS_ADD_PREFIX(dev, mem, rootdir);
return 0; return 0;

View File

@ -105,6 +105,7 @@ static int wl1271_event_process(struct wl1271 *wl)
u32 vector; u32 vector;
bool disconnect_sta = false; bool disconnect_sta = false;
unsigned long sta_bitmap = 0; unsigned long sta_bitmap = 0;
int ret;
wl1271_event_mbox_dump(mbox); wl1271_event_mbox_dump(mbox);
@ -228,7 +229,9 @@ static int wl1271_event_process(struct wl1271 *wl)
if ((vector & DUMMY_PACKET_EVENT_ID)) { if ((vector & DUMMY_PACKET_EVENT_ID)) {
wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
wl1271_tx_dummy_packet(wl); ret = wl1271_tx_dummy_packet(wl);
if (ret < 0)
return ret;
} }
/* /*
@ -301,8 +304,10 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return -EINVAL; return -EINVAL;
/* first we read the mbox descriptor */ /* first we read the mbox descriptor */
wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox, ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
sizeof(*wl->mbox), false); sizeof(*wl->mbox), false);
if (ret < 0)
return ret;
/* process the descriptor */ /* process the descriptor */
ret = wl1271_event_process(wl); ret = wl1271_event_process(wl);
@ -313,7 +318,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
* TODO: we just need this because one bit is in a different * TODO: we just need this because one bit is in a different
* place. Is there any better way? * place. Is there any better way?
*/ */
wl->ops->ack_event(wl); ret = wl->ops->ack_event(wl);
return 0; return ret;
} }

View File

@ -65,11 +65,13 @@ wlcore_hw_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
return wl->ops->get_rx_buf_align(wl, rx_desc); return wl->ops->get_rx_buf_align(wl, rx_desc);
} }
static inline void static inline int
wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
{ {
if (wl->ops->prepare_read) if (wl->ops->prepare_read)
wl->ops->prepare_read(wl, rx_desc, len); return wl->ops->prepare_read(wl, rx_desc, len);
return 0;
} }
static inline u32 static inline u32
@ -81,10 +83,12 @@ wlcore_hw_get_rx_packet_len(struct wl1271 *wl, void *rx_data, u32 data_len)
return wl->ops->get_rx_packet_len(wl, rx_data, data_len); return wl->ops->get_rx_packet_len(wl, rx_data, data_len);
} }
static inline void wlcore_hw_tx_delayed_compl(struct wl1271 *wl) static inline int wlcore_hw_tx_delayed_compl(struct wl1271 *wl)
{ {
if (wl->ops->tx_delayed_compl) if (wl->ops->tx_delayed_compl)
wl->ops->tx_delayed_compl(wl); return wl->ops->tx_delayed_compl(wl);
return 0;
} }
static inline void wlcore_hw_tx_immediate_compl(struct wl1271 *wl) static inline void wlcore_hw_tx_immediate_compl(struct wl1271 *wl)

View File

@ -48,6 +48,12 @@ void wlcore_disable_interrupts(struct wl1271 *wl)
} }
EXPORT_SYMBOL_GPL(wlcore_disable_interrupts); EXPORT_SYMBOL_GPL(wlcore_disable_interrupts);
void wlcore_disable_interrupts_nosync(struct wl1271 *wl)
{
disable_irq_nosync(wl->irq);
}
EXPORT_SYMBOL_GPL(wlcore_disable_interrupts_nosync);
void wlcore_enable_interrupts(struct wl1271 *wl) void wlcore_enable_interrupts(struct wl1271 *wl)
{ {
enable_irq(wl->irq); enable_irq(wl->irq);
@ -122,9 +128,11 @@ EXPORT_SYMBOL_GPL(wlcore_translate_addr);
* | | * | |
* *
*/ */
void wlcore_set_partition(struct wl1271 *wl, int wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p) const struct wlcore_partition_set *p)
{ {
int ret;
/* copy partition info */ /* copy partition info */
memcpy(&wl->curr_part, p, sizeof(*p)); memcpy(&wl->curr_part, p, sizeof(*p));
@ -137,29 +145,42 @@ void wlcore_set_partition(struct wl1271 *wl,
wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X", wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X",
p->mem3.start, p->mem3.size); p->mem3.start, p->mem3.size);
wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); ret = wlcore_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); if (ret < 0)
wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); goto out;
wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); ret = wlcore_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); if (ret < 0)
goto out;
ret = wlcore_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
if (ret < 0)
goto out;
ret = wlcore_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
if (ret < 0)
goto out;
ret = wlcore_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
if (ret < 0)
goto out;
ret = wlcore_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
if (ret < 0)
goto out;
/* /*
* We don't need the size of the last partition, as it is * We don't need the size of the last partition, as it is
* automatically calculated based on the total memory size and * automatically calculated based on the total memory size and
* the sizes of the previous partitions. * the sizes of the previous partitions.
*/ */
wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
out:
return ret;
} }
EXPORT_SYMBOL_GPL(wlcore_set_partition); EXPORT_SYMBOL_GPL(wlcore_set_partition);
void wlcore_select_partition(struct wl1271 *wl, u8 part)
{
wl1271_debug(DEBUG_IO, "setting partition %d", part);
wlcore_set_partition(wl, &wl->ptable[part]);
}
EXPORT_SYMBOL_GPL(wlcore_select_partition);
void wl1271_io_reset(struct wl1271 *wl) void wl1271_io_reset(struct wl1271 *wl)
{ {
if (wl->if_ops->reset) if (wl->if_ops->reset)

View File

@ -45,6 +45,7 @@
struct wl1271; struct wl1271;
void wlcore_disable_interrupts(struct wl1271 *wl); void wlcore_disable_interrupts(struct wl1271 *wl);
void wlcore_disable_interrupts_nosync(struct wl1271 *wl);
void wlcore_enable_interrupts(struct wl1271 *wl); void wlcore_enable_interrupts(struct wl1271 *wl);
void wl1271_io_reset(struct wl1271 *wl); void wl1271_io_reset(struct wl1271 *wl);
@ -52,81 +53,115 @@ void wl1271_io_init(struct wl1271 *wl);
int wlcore_translate_addr(struct wl1271 *wl, int addr); int wlcore_translate_addr(struct wl1271 *wl, int addr);
/* Raw target IO, address is not translated */ /* Raw target IO, address is not translated */
static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl->if_ops->write(wl->dev, addr, buf, len, fixed); int ret;
if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags))
return -EIO;
ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed);
if (ret)
set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags);
return ret;
} }
static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl->if_ops->read(wl->dev, addr, buf, len, fixed); int ret;
if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags))
return -EIO;
ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed);
if (ret)
set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags);
return ret;
} }
static inline void wlcore_raw_read_data(struct wl1271 *wl, int reg, void *buf, static inline int __must_check wlcore_raw_read_data(struct wl1271 *wl, int reg,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl1271_raw_read(wl, wl->rtable[reg], buf, len, fixed); return wlcore_raw_read(wl, wl->rtable[reg], buf, len, fixed);
} }
static inline void wlcore_raw_write_data(struct wl1271 *wl, int reg, void *buf, static inline int __must_check wlcore_raw_write_data(struct wl1271 *wl, int reg,
size_t len, bool fixed) void *buf, size_t len,
bool fixed)
{ {
wl1271_raw_write(wl, wl->rtable[reg], buf, len, fixed); return wlcore_raw_write(wl, wl->rtable[reg], buf, len, fixed);
} }
static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
u32 *val)
{ {
wl1271_raw_read(wl, addr, &wl->buffer_32, int ret;
ret = wlcore_raw_read(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false); sizeof(wl->buffer_32), false);
if (ret < 0)
return ret;
return le32_to_cpu(wl->buffer_32); if (val)
*val = le32_to_cpu(wl->buffer_32);
return 0;
} }
static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr,
u32 val)
{ {
wl->buffer_32 = cpu_to_le32(val); wl->buffer_32 = cpu_to_le32(val);
wl1271_raw_write(wl, addr, &wl->buffer_32, return wlcore_raw_write(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false); sizeof(wl->buffer_32), false);
} }
static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf, static inline int __must_check wlcore_read(struct wl1271 *wl, int addr,
size_t len, bool fixed)
{
int physical;
physical = wlcore_translate_addr(wl, addr);
wl1271_raw_read(wl, physical, buf, len, fixed);
}
static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
{
int physical;
physical = wlcore_translate_addr(wl, addr);
wl1271_raw_write(wl, physical, buf, len, fixed);
}
static inline void wlcore_write_data(struct wl1271 *wl, int reg, void *buf,
size_t len, bool fixed)
{
wl1271_write(wl, wl->rtable[reg], buf, len, fixed);
}
static inline void wlcore_read_data(struct wl1271 *wl, int reg, void *buf,
size_t len, bool fixed)
{
wl1271_read(wl, wl->rtable[reg], buf, len, fixed);
}
static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
void *buf, size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
int physical; int physical;
physical = wlcore_translate_addr(wl, addr);
return wlcore_raw_read(wl, physical, buf, len, fixed);
}
static inline int __must_check wlcore_write(struct wl1271 *wl, int addr,
void *buf, size_t len, bool fixed)
{
int physical;
physical = wlcore_translate_addr(wl, addr);
return wlcore_raw_write(wl, physical, buf, len, fixed);
}
static inline int __must_check wlcore_write_data(struct wl1271 *wl, int reg,
void *buf, size_t len,
bool fixed)
{
return wlcore_write(wl, wl->rtable[reg], buf, len, fixed);
}
static inline int __must_check wlcore_read_data(struct wl1271 *wl, int reg,
void *buf, size_t len,
bool fixed)
{
return wlcore_read(wl, wl->rtable[reg], buf, len, fixed);
}
static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr,
void *buf, size_t len,
bool fixed)
{
int physical;
int addr; int addr;
/* Addresses are stored internally as addresses to 32 bytes blocks */ /* Addresses are stored internally as addresses to 32 bytes blocks */
@ -134,33 +169,46 @@ static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
physical = wlcore_translate_addr(wl, addr); physical = wlcore_translate_addr(wl, addr);
wl1271_raw_read(wl, physical, buf, len, fixed); return wlcore_raw_read(wl, physical, buf, len, fixed);
} }
static inline u32 wl1271_read32(struct wl1271 *wl, int addr) static inline int __must_check wlcore_read32(struct wl1271 *wl, int addr,
u32 *val)
{ {
return wl1271_raw_read32(wl, wlcore_translate_addr(wl, addr)); return wlcore_raw_read32(wl, wlcore_translate_addr(wl, addr), val);
} }
static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) static inline int __must_check wlcore_write32(struct wl1271 *wl, int addr,
u32 val)
{ {
wl1271_raw_write32(wl, wlcore_translate_addr(wl, addr), val); return wlcore_raw_write32(wl, wlcore_translate_addr(wl, addr), val);
} }
static inline u32 wlcore_read_reg(struct wl1271 *wl, int reg) static inline int __must_check wlcore_read_reg(struct wl1271 *wl, int reg,
u32 *val)
{ {
return wl1271_raw_read32(wl, return wlcore_raw_read32(wl,
wlcore_translate_addr(wl, wl->rtable[reg])); wlcore_translate_addr(wl, wl->rtable[reg]),
val);
} }
static inline void wlcore_write_reg(struct wl1271 *wl, int reg, u32 val) static inline int __must_check wlcore_write_reg(struct wl1271 *wl, int reg,
u32 val)
{ {
wl1271_raw_write32(wl, wlcore_translate_addr(wl, wl->rtable[reg]), val); return wlcore_raw_write32(wl,
wlcore_translate_addr(wl, wl->rtable[reg]),
val);
} }
static inline void wl1271_power_off(struct wl1271 *wl) static inline void wl1271_power_off(struct wl1271 *wl)
{ {
wl->if_ops->power(wl->dev, false); int ret;
if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags))
return;
ret = wl->if_ops->power(wl->dev, false);
if (!ret)
clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
} }
@ -173,7 +221,7 @@ static inline int wl1271_power_on(struct wl1271 *wl)
return ret; return ret;
} }
void wlcore_set_partition(struct wl1271 *wl, int wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p); const struct wlcore_partition_set *p);
bool wl1271_set_block_size(struct wl1271 *wl); bool wl1271_set_block_size(struct wl1271 *wl);
@ -182,6 +230,4 @@ bool wl1271_set_block_size(struct wl1271 *wl);
int wl1271_tx_dummy_packet(struct wl1271 *wl); int wl1271_tx_dummy_packet(struct wl1271 *wl);
void wlcore_select_partition(struct wl1271 *wl, u8 part);
#endif #endif

View File

@ -378,7 +378,7 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
} }
} }
static void wl12xx_fw_status(struct wl1271 *wl, static int wlcore_fw_status(struct wl1271 *wl,
struct wl_fw_status_1 *status_1, struct wl_fw_status_1 *status_1,
struct wl_fw_status_2 *status_2) struct wl_fw_status_2 *status_2)
{ {
@ -388,12 +388,15 @@ static void wl12xx_fw_status(struct wl1271 *wl,
int avail, freed_blocks; int avail, freed_blocks;
int i; int i;
size_t status_len; size_t status_len;
int ret;
status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) + status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
sizeof(*status_2) + wl->fw_status_priv_len; sizeof(*status_2) + wl->fw_status_priv_len;
wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1, ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
status_len, false); status_len, false);
if (ret < 0)
return ret;
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)", "drv_rx_counter = %d, tx_results_counter = %d)",
@ -462,6 +465,8 @@ static void wl12xx_fw_status(struct wl1271 *wl,
getnstimeofday(&ts); getnstimeofday(&ts);
wl->time_offset = (timespec_to_ns(&ts) >> 10) - wl->time_offset = (timespec_to_ns(&ts) >> 10) -
(s64)le32_to_cpu(status_2->fw_localtime); (s64)le32_to_cpu(status_2->fw_localtime);
return 0;
} }
static void wl1271_flush_deferred_work(struct wl1271 *wl) static void wl1271_flush_deferred_work(struct wl1271 *wl)
@ -489,20 +494,15 @@ static void wl1271_netstack_work(struct work_struct *work)
#define WL1271_IRQ_MAX_LOOPS 256 #define WL1271_IRQ_MAX_LOOPS 256
static irqreturn_t wl1271_irq(int irq, void *cookie) static int wlcore_irq_locked(struct wl1271 *wl)
{ {
int ret; int ret = 0;
u32 intr; u32 intr;
int loopcount = WL1271_IRQ_MAX_LOOPS; int loopcount = WL1271_IRQ_MAX_LOOPS;
struct wl1271 *wl = (struct wl1271 *)cookie;
bool done = false; bool done = false;
unsigned int defer_count; unsigned int defer_count;
unsigned long flags; unsigned long flags;
/* TX might be handled here, avoid redundant work */
set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
cancel_work_sync(&wl->tx_work);
/* /*
* In case edge triggered interrupt must be used, we cannot iterate * In case edge triggered interrupt must be used, we cannot iterate
* more than once without introducing race conditions with the hardirq. * more than once without introducing race conditions with the hardirq.
@ -510,8 +510,6 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
loopcount = 1; loopcount = 1;
mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_IRQ, "IRQ work"); wl1271_debug(DEBUG_IRQ, "IRQ work");
if (unlikely(wl->state == WL1271_STATE_OFF)) if (unlikely(wl->state == WL1271_STATE_OFF))
@ -530,7 +528,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2); ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
if (ret < 0)
goto out;
wlcore_hw_tx_immediate_compl(wl); wlcore_hw_tx_immediate_compl(wl);
@ -544,7 +544,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
wl1271_error("HW watchdog interrupt received! starting recovery."); wl1271_error("HW watchdog interrupt received! starting recovery.");
wl->watchdog_recovery = true; wl->watchdog_recovery = true;
wl12xx_queue_recovery_work(wl); ret = -EIO;
/* restarting the chip. ignore any other interrupt. */ /* restarting the chip. ignore any other interrupt. */
goto out; goto out;
@ -554,7 +554,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl1271_error("SW watchdog interrupt received! " wl1271_error("SW watchdog interrupt received! "
"starting recovery."); "starting recovery.");
wl->watchdog_recovery = true; wl->watchdog_recovery = true;
wl12xx_queue_recovery_work(wl); ret = -EIO;
/* restarting the chip. ignore any other interrupt. */ /* restarting the chip. ignore any other interrupt. */
goto out; goto out;
@ -563,7 +563,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
if (likely(intr & WL1271_ACX_INTR_DATA)) { if (likely(intr & WL1271_ACX_INTR_DATA)) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
wl12xx_rx(wl, wl->fw_status_1); ret = wlcore_rx(wl, wl->fw_status_1);
if (ret < 0)
goto out;
/* Check if any tx blocks were freed */ /* Check if any tx blocks were freed */
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
@ -574,13 +576,17 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
* In order to avoid starvation of the TX path, * In order to avoid starvation of the TX path,
* call the work function directly. * call the work function directly.
*/ */
wl1271_tx_work_locked(wl); ret = wlcore_tx_work_locked(wl);
if (ret < 0)
goto out;
} else { } else {
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
} }
/* check for tx results */ /* check for tx results */
wlcore_hw_tx_delayed_compl(wl); ret = wlcore_hw_tx_delayed_compl(wl);
if (ret < 0)
goto out;
/* Make sure the deferred queues don't get too long */ /* Make sure the deferred queues don't get too long */
defer_count = skb_queue_len(&wl->deferred_tx_queue) + defer_count = skb_queue_len(&wl->deferred_tx_queue) +
@ -591,12 +597,16 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
if (intr & WL1271_ACX_INTR_EVENT_A) { if (intr & WL1271_ACX_INTR_EVENT_A) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
wl1271_event_handle(wl, 0); ret = wl1271_event_handle(wl, 0);
if (ret < 0)
goto out;
} }
if (intr & WL1271_ACX_INTR_EVENT_B) { if (intr & WL1271_ACX_INTR_EVENT_B) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
wl1271_event_handle(wl, 1); ret = wl1271_event_handle(wl, 1);
if (ret < 0)
goto out;
} }
if (intr & WL1271_ACX_INTR_INIT_COMPLETE) if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
@ -610,6 +620,25 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out: out:
return ret;
}
static irqreturn_t wlcore_irq(int irq, void *cookie)
{
int ret;
unsigned long flags;
struct wl1271 *wl = cookie;
/* TX might be handled here, avoid redundant work */
set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
cancel_work_sync(&wl->tx_work);
mutex_lock(&wl->mutex);
ret = wlcore_irq_locked(wl);
if (ret)
wl12xx_queue_recovery_work(wl);
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
/* In case TX was not handled here, queue TX work */ /* In case TX was not handled here, queue TX work */
clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags); clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
@ -743,9 +772,14 @@ out:
void wl12xx_queue_recovery_work(struct wl1271 *wl) void wl12xx_queue_recovery_work(struct wl1271 *wl)
{ {
if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
/* Avoid a recursive recovery */
if (!test_and_set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
wlcore_disable_interrupts_nosync(wl);
ieee80211_queue_work(wl->hw, &wl->recovery_work); ieee80211_queue_work(wl->hw, &wl->recovery_work);
} }
}
size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
{ {
@ -778,6 +812,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
u32 offset; u32 offset;
u32 end_of_log; u32 end_of_log;
u8 *block; u8 *block;
int ret;
if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) || if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
(wl->conf.fwlog.mem_blocks == 0)) (wl->conf.fwlog.mem_blocks == 0))
@ -799,7 +834,10 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
wl12xx_cmd_stop_fwlog(wl); wl12xx_cmd_stop_fwlog(wl);
/* Read the first memory block address */ /* Read the first memory block address */
wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2); ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
if (ret < 0)
goto out;
addr = le32_to_cpu(wl->fw_status_2->log_start_addr); addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
if (!addr) if (!addr)
goto out; goto out;
@ -815,8 +853,10 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
/* Traverse the memory blocks linked list */ /* Traverse the memory blocks linked list */
do { do {
memset(block, 0, WL12XX_HW_BLOCK_SIZE); memset(block, 0, WL12XX_HW_BLOCK_SIZE);
wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE, ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
false); false);
if (ret < 0)
goto out;
/* /*
* Memory blocks are linked to one another. The first 4 bytes * Memory blocks are linked to one another. The first 4 bytes
@ -836,6 +876,34 @@ out:
kfree(block); kfree(block);
} }
static void wlcore_print_recovery(struct wl1271 *wl)
{
u32 pc = 0;
u32 hint_sts = 0;
int ret;
wl1271_info("Hardware recovery in progress. FW ver: %s",
wl->chip.fw_ver_str);
/* change partitions momentarily so we can read the FW pc */
ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
if (ret < 0)
return;
ret = wlcore_read_reg(wl, REG_PC_ON_RECOVERY, &pc);
if (ret < 0)
return;
ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &hint_sts);
if (ret < 0)
return;
wl1271_info("pc: 0x%x, hint_sts: 0x%08x", pc, hint_sts);
wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
}
static void wl1271_recovery_work(struct work_struct *work) static void wl1271_recovery_work(struct work_struct *work)
{ {
struct wl1271 *wl = struct wl1271 *wl =
@ -848,19 +916,9 @@ static void wl1271_recovery_work(struct work_struct *work)
if (wl->state != WL1271_STATE_ON || wl->plt) if (wl->state != WL1271_STATE_ON || wl->plt)
goto out_unlock; goto out_unlock;
/* Avoid a recursive recovery */
set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
wl12xx_read_fwlog_panic(wl); wl12xx_read_fwlog_panic(wl);
/* change partitions momentarily so we can read the FW pc */ wlcore_print_recovery(wl);
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x "
"hint_sts: 0x%08x",
wl->chip.fw_ver_str,
wlcore_read_reg(wl, REG_PC_ON_RECOVERY),
wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR));
wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
BUG_ON(bug_on_recovery && BUG_ON(bug_on_recovery &&
!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
@ -902,8 +960,6 @@ static void wl1271_recovery_work(struct work_struct *work)
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
wl1271_op_stop(wl->hw); wl1271_op_stop(wl->hw);
clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
ieee80211_restart_hw(wl->hw); ieee80211_restart_hw(wl->hw);
/* /*
@ -917,9 +973,9 @@ out_unlock:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
} }
static void wl1271_fw_wakeup(struct wl1271 *wl) static int wlcore_fw_wakeup(struct wl1271 *wl)
{ {
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); return wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
} }
static int wl1271_setup(struct wl1271 *wl) static int wl1271_setup(struct wl1271 *wl)
@ -955,13 +1011,21 @@ static int wl12xx_set_power_on(struct wl1271 *wl)
wl1271_io_reset(wl); wl1271_io_reset(wl);
wl1271_io_init(wl); wl1271_io_init(wl);
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
if (ret < 0)
goto fail;
/* ELP module wake up */ /* ELP module wake up */
wl1271_fw_wakeup(wl); ret = wlcore_fw_wakeup(wl);
if (ret < 0)
goto fail;
out: out:
return ret; return ret;
fail:
wl1271_power_off(wl);
return ret;
} }
static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt) static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
@ -1184,7 +1248,7 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl)
/* The FW is low on RX memory blocks, so send the dummy packet asap */ /* The FW is low on RX memory blocks, so send the dummy packet asap */
if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
wl1271_tx_work_locked(wl); return wlcore_tx_work_locked(wl);
/* /*
* If the FW TX is busy, TX work will be scheduled by the threaded * If the FW TX is busy, TX work will be scheduled by the threaded
@ -1451,8 +1515,15 @@ static int wl1271_configure_wowlan(struct wl1271 *wl,
int i, ret; int i, ret;
if (!wow || wow->any || !wow->n_patterns) { if (!wow || wow->any || !wow->n_patterns) {
wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL); ret = wl1271_acx_default_rx_filter_enable(wl, 0,
wl1271_rx_filter_clear_all(wl); FILTER_SIGNAL);
if (ret)
goto out;
ret = wl1271_rx_filter_clear_all(wl);
if (ret)
goto out;
return 0; return 0;
} }
@ -1468,8 +1539,13 @@ static int wl1271_configure_wowlan(struct wl1271 *wl,
} }
} }
wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL); ret = wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
wl1271_rx_filter_clear_all(wl); if (ret)
goto out;
ret = wl1271_rx_filter_clear_all(wl);
if (ret)
goto out;
/* Translate WoWLAN patterns into filters */ /* Translate WoWLAN patterns into filters */
for (i = 0; i < wow->n_patterns; i++) { for (i = 0; i < wow->n_patterns; i++) {
@ -1511,7 +1587,10 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0) if (ret < 0)
goto out; goto out;
wl1271_configure_wowlan(wl, wow); ret = wl1271_configure_wowlan(wl, wow);
if (ret < 0)
goto out_sleep;
ret = wl1271_acx_wake_up_conditions(wl, wlvif, ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.suspend_wake_up_event, wl->conf.conn.suspend_wake_up_event,
wl->conf.conn.suspend_listen_interval); wl->conf.conn.suspend_listen_interval);
@ -1519,8 +1598,8 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0) if (ret < 0)
wl1271_error("suspend: set wake up conditions failed: %d", ret); wl1271_error("suspend: set wake up conditions failed: %d", ret);
out_sleep:
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out: out:
return ret; return ret;
@ -1599,6 +1678,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
WARN_ON(!wow); WARN_ON(!wow);
/* we want to perform the recovery before suspending */
if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
wl1271_warning("postponing suspend to perform recovery");
return -EBUSY;
}
wl1271_tx_flush(wl); wl1271_tx_flush(wl);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
@ -1639,7 +1724,8 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
unsigned long flags; unsigned long flags;
bool run_irq_work = false; bool run_irq_work = false, pending_recovery;
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
wl->wow_enabled); wl->wow_enabled);
@ -1655,17 +1741,37 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
run_irq_work = true; run_irq_work = true;
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
mutex_lock(&wl->mutex);
/* test the recovery flag before calling any SDIO functions */
pending_recovery = test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
&wl->flags);
if (run_irq_work) { if (run_irq_work) {
wl1271_debug(DEBUG_MAC80211, wl1271_debug(DEBUG_MAC80211,
"run postponed irq_work directly"); "run postponed irq_work directly");
wl1271_irq(0, wl);
/* don't talk to the HW if recovery is pending */
if (!pending_recovery) {
ret = wlcore_irq_locked(wl);
if (ret)
wl12xx_queue_recovery_work(wl);
}
wlcore_enable_interrupts(wl); wlcore_enable_interrupts(wl);
} }
mutex_lock(&wl->mutex); if (pending_recovery) {
wl1271_warning("queuing forgotten recovery on resume");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
goto out;
}
wl12xx_for_each_wlvif(wl, wlvif) { wl12xx_for_each_wlvif(wl, wlvif) {
wl1271_configure_resume(wl, wlvif); wl1271_configure_resume(wl, wlvif);
} }
out:
wl->wow_enabled = false; wl->wow_enabled = false;
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
@ -1706,6 +1812,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wlcore_disable_interrupts(wl); wlcore_disable_interrupts(wl);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) { if (wl->state == WL1271_STATE_OFF) {
if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
&wl->flags))
wlcore_enable_interrupts(wl);
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
/* /*
@ -1737,6 +1847,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
wl1271_power_off(wl); wl1271_power_off(wl);
/*
* In case a recovery was scheduled, interrupts were disabled to avoid
* an interrupt storm. Now that the power is down, it is safe to
* re-enable interrupts to balance the disable depth
*/
if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
wlcore_enable_interrupts(wl);
wl->band = IEEE80211_BAND_2GHZ; wl->band = IEEE80211_BAND_2GHZ;
@ -2475,7 +2592,10 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
(wlvif->channel != channel) || (wlvif->channel != channel) ||
(wlvif->channel_type != conf->channel_type))) { (wlvif->channel_type != conf->channel_type))) {
/* send all pending packets */ /* send all pending packets */
wl1271_tx_work_locked(wl); ret = wlcore_tx_work_locked(wl);
if (ret < 0)
return ret;
wlvif->band = conf->channel->band; wlvif->band = conf->channel->band;
wlvif->channel = channel; wlvif->channel = channel;
wlvif->channel_type = conf->channel_type; wlvif->channel_type = conf->channel_type;
@ -4934,18 +5054,22 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out; goto out;
wl->chip.id = wlcore_read_reg(wl, REG_CHIP_ID_B); ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id);
if (ret < 0)
goto out;
wl->fuse_oui_addr = 0; wl->fuse_oui_addr = 0;
wl->fuse_nic_addr = 0; wl->fuse_nic_addr = 0;
wl->hw_pg_ver = wl->ops->get_pg_ver(wl); ret = wl->ops->get_pg_ver(wl, &wl->hw_pg_ver);
if (ret < 0)
goto out;
if (wl->ops->get_mac) if (wl->ops->get_mac)
wl->ops->get_mac(wl); ret = wl->ops->get_mac(wl);
wl1271_power_off(wl);
out: out:
wl1271_power_off(wl);
return ret; return ret;
} }
@ -5372,7 +5496,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
else else
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq, ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wlcore_irq,
irqflags, irqflags,
pdev->name, wl); pdev->name, wl);
if (ret < 0) { if (ret < 0) {
@ -5398,12 +5522,12 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
ret = wl12xx_get_hw_info(wl); ret = wl12xx_get_hw_info(wl);
if (ret < 0) { if (ret < 0) {
wl1271_error("couldn't get hw info"); wl1271_error("couldn't get hw info");
goto out; goto out_irq;
} }
ret = wl->ops->identify_chip(wl); ret = wl->ops->identify_chip(wl);
if (ret < 0) if (ret < 0)
goto out; goto out_irq;
ret = wl1271_init_ieee80211(wl); ret = wl1271_init_ieee80211(wl);
if (ret) if (ret)
@ -5417,7 +5541,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
ret = device_create_file(wl->dev, &dev_attr_bt_coex_state); ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
if (ret < 0) { if (ret < 0) {
wl1271_error("failed to create sysfs file bt_coex_state"); wl1271_error("failed to create sysfs file bt_coex_state");
goto out_irq; goto out_unreg;
} }
/* Create sysfs file to get HW PG version */ /* Create sysfs file to get HW PG version */
@ -5442,6 +5566,9 @@ out_hw_pg_ver:
out_bt_coex_state: out_bt_coex_state:
device_remove_file(wl->dev, &dev_attr_bt_coex_state); device_remove_file(wl->dev, &dev_attr_bt_coex_state);
out_unreg:
wl1271_unregister_hw(wl);
out_irq: out_irq:
free_irq(wl->irq, wl); free_irq(wl->irq, wl);

View File

@ -35,6 +35,7 @@ void wl1271_elp_work(struct work_struct *work)
struct delayed_work *dwork; struct delayed_work *dwork;
struct wl1271 *wl; struct wl1271 *wl;
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
int ret;
dwork = container_of(work, struct delayed_work, work); dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, elp_work); wl = container_of(dwork, struct wl1271, elp_work);
@ -63,7 +64,12 @@ void wl1271_elp_work(struct work_struct *work)
} }
wl1271_debug(DEBUG_PSM, "chip to elp"); wl1271_debug(DEBUG_PSM, "chip to elp");
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP); ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP);
if (ret < 0) {
wl12xx_queue_recovery_work(wl);
goto out;
}
set_bit(WL1271_FLAG_IN_ELP, &wl->flags); set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
out: out:
@ -135,7 +141,11 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
wl->elp_compl = &compl; wl->elp_compl = &compl;
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
if (ret < 0) {
wl12xx_queue_recovery_work(wl);
goto err;
}
if (!pending) { if (!pending) {
ret = wait_for_completion_timeout( ret = wait_for_completion_timeout(

View File

@ -200,7 +200,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return is_data; return is_data;
} }
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
{ {
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
u32 buf_size; u32 buf_size;
@ -211,6 +211,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
u32 pkt_offset, des; u32 pkt_offset, des;
u8 hlid; u8 hlid;
enum wl_rx_buf_align rx_align; enum wl_rx_buf_align rx_align;
int ret = 0;
while (drv_rx_counter != fw_rx_counter) { while (drv_rx_counter != fw_rx_counter) {
buf_size = 0; buf_size = 0;
@ -234,9 +235,14 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
/* Read all available packets at once */ /* Read all available packets at once */
des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]); des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
wlcore_hw_prepare_read(wl, des, buf_size); ret = wlcore_hw_prepare_read(wl, des, buf_size);
wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, if (ret < 0)
goto out;
ret = wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_size, true); buf_size, true);
if (ret < 0)
goto out;
/* Split data into separate packets */ /* Split data into separate packets */
pkt_offset = 0; pkt_offset = 0;
@ -273,11 +279,17 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
* Write the driver's packet counter to the FW. This is only required * Write the driver's packet counter to the FW. This is only required
* for older hardware revisions * for older hardware revisions
*/ */
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER, ret = wlcore_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
wl->rx_counter); wl->rx_counter);
if (ret < 0)
goto out;
}
wl12xx_rearm_rx_streaming(wl, active_hlids); wl12xx_rearm_rx_streaming(wl, active_hlids);
out:
return ret;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
@ -306,14 +318,19 @@ int wl1271_rx_filter_enable(struct wl1271 *wl,
return 0; return 0;
} }
void wl1271_rx_filter_clear_all(struct wl1271 *wl) int wl1271_rx_filter_clear_all(struct wl1271 *wl)
{ {
int i; int i, ret = 0;
for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) { for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) {
if (!wl->rx_filter_enabled[i]) if (!wl->rx_filter_enabled[i])
continue; continue;
wl1271_rx_filter_enable(wl, i, 0, NULL); ret = wl1271_rx_filter_enable(wl, i, 0, NULL);
if (ret)
goto out;
} }
out:
return ret;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */

View File

@ -143,11 +143,11 @@ struct wl1271_rx_descriptor {
u8 reserved; u8 reserved;
} __packed; } __packed;
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status); int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
int wl1271_rx_filter_enable(struct wl1271 *wl, int wl1271_rx_filter_enable(struct wl1271 *wl,
int index, bool enable, int index, bool enable,
struct wl12xx_rx_filter *filter); struct wl12xx_rx_filter *filter);
void wl1271_rx_filter_clear_all(struct wl1271 *wl); int wl1271_rx_filter_clear_all(struct wl1271 *wl);
#endif #endif

View File

@ -71,8 +71,8 @@ static void wl1271_sdio_set_block_size(struct device *child,
sdio_release_host(func); sdio_release_host(func);
} }
static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, static int __must_check wl12xx_sdio_raw_read(struct device *child, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
int ret; int ret;
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
@ -103,12 +103,14 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
sdio_release_host(func); sdio_release_host(func);
if (ret) if (WARN_ON(ret))
dev_err(child->parent, "sdio read failed (%d)\n", ret); dev_err(child->parent, "sdio read failed (%d)\n", ret);
return ret;
} }
static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, static int __must_check wl12xx_sdio_raw_write(struct device *child, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
int ret; int ret;
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
@ -139,26 +141,31 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
sdio_release_host(func); sdio_release_host(func);
if (ret) if (WARN_ON(ret))
dev_err(child->parent, "sdio write failed (%d)\n", ret); dev_err(child->parent, "sdio write failed (%d)\n", ret);
return ret;
} }
static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue)
{ {
int ret; int ret;
struct sdio_func *func = dev_to_sdio_func(glue->dev); struct sdio_func *func = dev_to_sdio_func(glue->dev);
struct mmc_card *card = func->card;
/* If enabled, tell runtime PM not to power off the card */ ret = pm_runtime_get_sync(&card->dev);
if (pm_runtime_enabled(&func->dev)) { if (ret) {
ret = pm_runtime_get_sync(&func->dev); /*
if (ret < 0) * Runtime PM might be temporarily disabled, or the device
goto out; * might have a positive reference counter. Make sure it is
} else { * really powered on.
/* Runtime PM is disabled: power up the card manually */ */
ret = mmc_power_restore_host(func->card->host); ret = mmc_power_restore_host(card->host);
if (ret < 0) if (ret < 0) {
pm_runtime_put_sync(&card->dev);
goto out; goto out;
} }
}
sdio_claim_host(func); sdio_claim_host(func);
sdio_enable_func(func); sdio_enable_func(func);
@ -172,20 +179,21 @@ static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue)
{ {
int ret; int ret;
struct sdio_func *func = dev_to_sdio_func(glue->dev); struct sdio_func *func = dev_to_sdio_func(glue->dev);
struct mmc_card *card = func->card;
sdio_claim_host(func); sdio_claim_host(func);
sdio_disable_func(func); sdio_disable_func(func);
sdio_release_host(func); sdio_release_host(func);
/* Power off the card manually, even if runtime PM is enabled. */ /* Power off the card manually in case it wasn't powered off above */
ret = mmc_power_save_host(func->card->host); ret = mmc_power_save_host(card->host);
if (ret < 0) if (ret < 0)
return ret; goto out;
/* If enabled, let runtime PM know the card is powered off */ /* Let runtime PM know the card is powered off */
if (pm_runtime_enabled(&func->dev)) pm_runtime_put_sync(&card->dev);
ret = pm_runtime_put_sync(&func->dev);
out:
return ret; return ret;
} }

View File

@ -193,8 +193,8 @@ static int wl12xx_spi_read_busy(struct device *child)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, static int __must_check wl12xx_spi_raw_read(struct device *child, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
struct wl1271 *wl = dev_get_drvdata(child); struct wl1271 *wl = dev_get_drvdata(child);
@ -238,7 +238,7 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
wl12xx_spi_read_busy(child)) { wl12xx_spi_read_busy(child)) {
memset(buf, 0, chunk_len); memset(buf, 0, chunk_len);
return; return 0;
} }
spi_message_init(&m); spi_message_init(&m);
@ -256,10 +256,12 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
buf += chunk_len; buf += chunk_len;
len -= chunk_len; len -= chunk_len;
} }
return 0;
} }
static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf, static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
size_t len, bool fixed) void *buf, size_t len, bool fixed)
{ {
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
@ -304,6 +306,8 @@ static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf,
} }
spi_sync(to_spi_device(glue->dev), &m); spi_sync(to_spi_device(glue->dev), &m);
return 0;
} }
static struct wl1271_if_operations spi_ops = { static struct wl1271_if_operations spi_ops = {

View File

@ -352,8 +352,10 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
bool is_dummy; bool is_dummy;
bool is_gem = false; bool is_gem = false;
if (!skb) if (!skb) {
wl1271_error("discarding null skb");
return -EINVAL; return -EINVAL;
}
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
@ -662,7 +664,17 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids)
} }
} }
void wl1271_tx_work_locked(struct wl1271 *wl) /*
* Returns failure values only in case of failed bus ops within this function.
* wl1271_prepare_tx_frame retvals won't be returned in order to avoid
* triggering recovery by higher layers when not necessary.
* In case a FW command fails within wl1271_prepare_tx_frame fails a recovery
* will be queued in wl1271_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame
* can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING
* within prepare_tx_frame code but there's nothing we should do about those
* as well.
*/
int wlcore_tx_work_locked(struct wl1271 *wl)
{ {
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
struct sk_buff *skb; struct sk_buff *skb;
@ -670,10 +682,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
u32 buf_offset = 0, last_len = 0; u32 buf_offset = 0, last_len = 0;
bool sent_packets = false; bool sent_packets = false;
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
int ret; int ret = 0;
int bus_ret = 0;
if (unlikely(wl->state == WL1271_STATE_OFF)) if (unlikely(wl->state == WL1271_STATE_OFF))
return; return 0;
while ((skb = wl1271_skb_dequeue(wl))) { while ((skb = wl1271_skb_dequeue(wl))) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@ -694,8 +707,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset,
last_len); last_len);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA,
buf_offset, true); wl->aggr_buf, buf_offset, true);
if (bus_ret < 0)
goto out;
sent_packets = true; sent_packets = true;
buf_offset = 0; buf_offset = 0;
continue; continue;
@ -731,8 +747,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
out_ack: out_ack:
if (buf_offset) { if (buf_offset) {
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len); buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true); buf_offset, true);
if (bus_ret < 0)
goto out;
sent_packets = true; sent_packets = true;
} }
if (sent_packets) { if (sent_packets) {
@ -740,13 +759,19 @@ out_ack:
* Interrupt the firmware with the new packets. This is only * Interrupt the firmware with the new packets. This is only
* required for older hardware revisions * required for older hardware revisions
*/ */
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
wl1271_write32(wl, WL12XX_HOST_WR_ACCESS, bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS,
wl->tx_packets_count); wl->tx_packets_count);
if (bus_ret < 0)
goto out;
}
wl1271_handle_tx_low_watermark(wl); wl1271_handle_tx_low_watermark(wl);
} }
wl12xx_rearm_rx_streaming(wl, active_hlids); wl12xx_rearm_rx_streaming(wl, active_hlids);
out:
return bus_ret;
} }
void wl1271_tx_work(struct work_struct *work) void wl1271_tx_work(struct work_struct *work)
@ -759,7 +784,11 @@ void wl1271_tx_work(struct work_struct *work)
if (ret < 0) if (ret < 0)
goto out; goto out;
wl1271_tx_work_locked(wl); ret = wlcore_tx_work_locked(wl);
if (ret < 0) {
wl12xx_queue_recovery_work(wl);
goto out;
}
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out: out:
@ -881,22 +910,28 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
} }
/* Called upon reception of a TX complete interrupt */ /* Called upon reception of a TX complete interrupt */
void wl1271_tx_complete(struct wl1271 *wl) int wlcore_tx_complete(struct wl1271 *wl)
{ {
struct wl1271_acx_mem_map *memmap = struct wl1271_acx_mem_map *memmap =
(struct wl1271_acx_mem_map *)wl->target_mem_map; (struct wl1271_acx_mem_map *)wl->target_mem_map;
u32 count, fw_counter; u32 count, fw_counter;
u32 i; u32 i;
int ret;
/* read the tx results from the chipset */ /* read the tx results from the chipset */
wl1271_read(wl, le32_to_cpu(memmap->tx_result), ret = wlcore_read(wl, le32_to_cpu(memmap->tx_result),
wl->tx_res_if, sizeof(*wl->tx_res_if), false); wl->tx_res_if, sizeof(*wl->tx_res_if), false);
if (ret < 0)
goto out;
fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter);
/* write host counter to chipset (to ack) */ /* write host counter to chipset (to ack) */
wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + ret = wlcore_write32(wl, le32_to_cpu(memmap->tx_result) +
offsetof(struct wl1271_tx_hw_res_if, offsetof(struct wl1271_tx_hw_res_if,
tx_result_host_counter), fw_counter); tx_result_host_counter), fw_counter);
if (ret < 0)
goto out;
count = fw_counter - wl->tx_results_count; count = fw_counter - wl->tx_results_count;
wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
@ -916,8 +951,11 @@ void wl1271_tx_complete(struct wl1271 *wl)
wl->tx_results_count++; wl->tx_results_count++;
} }
out:
return ret;
} }
EXPORT_SYMBOL(wl1271_tx_complete); EXPORT_SYMBOL(wlcore_tx_complete);
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
{ {

View File

@ -234,8 +234,8 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl)
} }
void wl1271_tx_work(struct work_struct *work); void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_work_locked(struct wl1271 *wl); int wlcore_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl); int wlcore_tx_complete(struct wl1271 *wl);
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
void wl12xx_tx_reset(struct wl1271 *wl); void wl12xx_tx_reset(struct wl1271 *wl);
void wl1271_tx_flush(struct wl1271 *wl); void wl1271_tx_flush(struct wl1271 *wl);

View File

@ -41,9 +41,9 @@ struct wlcore_ops {
int (*identify_fw)(struct wl1271 *wl); int (*identify_fw)(struct wl1271 *wl);
int (*boot)(struct wl1271 *wl); int (*boot)(struct wl1271 *wl);
int (*plt_init)(struct wl1271 *wl); int (*plt_init)(struct wl1271 *wl);
void (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr, int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
void *buf, size_t len); void *buf, size_t len);
void (*ack_event)(struct wl1271 *wl); int (*ack_event)(struct wl1271 *wl);
u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks); u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks);
void (*set_tx_desc_blocks)(struct wl1271 *wl, void (*set_tx_desc_blocks)(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc, struct wl1271_tx_hw_descr *desc,
@ -53,17 +53,17 @@ struct wlcore_ops {
struct sk_buff *skb); struct sk_buff *skb);
enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl, enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl,
u32 rx_desc); u32 rx_desc);
void (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len); int (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len);
u32 (*get_rx_packet_len)(struct wl1271 *wl, void *rx_data, u32 (*get_rx_packet_len)(struct wl1271 *wl, void *rx_data,
u32 data_len); u32 data_len);
void (*tx_delayed_compl)(struct wl1271 *wl); int (*tx_delayed_compl)(struct wl1271 *wl);
void (*tx_immediate_compl)(struct wl1271 *wl); void (*tx_immediate_compl)(struct wl1271 *wl);
int (*hw_init)(struct wl1271 *wl); int (*hw_init)(struct wl1271 *wl);
int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif); int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl, u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl,
struct wl12xx_vif *wlvif); struct wl12xx_vif *wlvif);
s8 (*get_pg_ver)(struct wl1271 *wl); int (*get_pg_ver)(struct wl1271 *wl, s8 *ver);
void (*get_mac)(struct wl1271 *wl); int (*get_mac)(struct wl1271 *wl);
void (*set_tx_desc_csum)(struct wl1271 *wl, void (*set_tx_desc_csum)(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc, struct wl1271_tx_hw_descr *desc,
struct sk_buff *skb); struct sk_buff *skb);

View File

@ -209,10 +209,10 @@ struct wl1271_scan {
}; };
struct wl1271_if_operations { struct wl1271_if_operations {
void (*read)(struct device *child, int addr, void *buf, size_t len, int __must_check (*read)(struct device *child, int addr, void *buf,
bool fixed); size_t len, bool fixed);
void (*write)(struct device *child, int addr, void *buf, size_t len, int __must_check (*write)(struct device *child, int addr, void *buf,
bool fixed); size_t len, bool fixed);
void (*reset)(struct device *child); void (*reset)(struct device *child);
void (*init)(struct device *child); void (*init)(struct device *child);
int (*power)(struct device *child, bool enable); int (*power)(struct device *child, bool enable);
@ -247,6 +247,7 @@ enum wl12xx_flags {
WL1271_FLAG_RECOVERY_IN_PROGRESS, WL1271_FLAG_RECOVERY_IN_PROGRESS,
WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
WL1271_FLAG_INTENDED_FW_RECOVERY, WL1271_FLAG_INTENDED_FW_RECOVERY,
WL1271_FLAG_SDIO_FAILED,
}; };
enum wl12xx_vif_flags { enum wl12xx_vif_flags {