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_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) {
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
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;
wl1271_write(wl, WL1271_SLV_REG_DATA,
&rx_mem_addr, sizeof(rx_mem_addr), false);
ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr,
sizeof(rx_mem_addr), false);
if (ret < 0)
return ret;
}
return 0;
}
static int wl12xx_identify_chip(struct wl1271 *wl)
@ -682,64 +688,95 @@ out:
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 */
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 */
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 */
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;
int timeout = OCP_CMD_LOOP;
int ret;
/* write address >> 1 + 0x30000 to OCP_POR_CTR */
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 */
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 */
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);
if (!timeout) {
wl1271_warning("Top register access timed out.");
return 0xffff;
return -ETIMEDOUT;
}
/* check data status and return if OK */
if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
return val & 0xffff;
else {
if ((val & OCP_STATUS_MASK) != OCP_STATUS_OK) {
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)
{
u16 spare_reg;
int ret;
/* 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)
return -EFAULT;
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 */
wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG,
WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
ret = wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG,
WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
if (ret < 0)
return ret;
/* Delay execution for 15msec, to let the HW settle */
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)
{
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)
return false;
@ -761,8 +802,12 @@ static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
static bool wl128x_is_fref_valid(struct wl1271 *wl)
{
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)
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)
{
wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
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);
int ret;
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)
@ -784,13 +839,19 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
u16 pll_config;
u8 input_freq;
struct wl12xx_priv *priv = wl->priv;
int ret;
/* 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)
return -EFAULT;
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 */
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 */
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)
return -EFAULT;
pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT);
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;
u16 sys_clk_cfg;
int ret;
/* For XTAL-only modes, FREF will be used after switching from TCXO */
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 */
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)
return -EINVAL;
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;
u32 pause;
u32 clk;
int ret;
if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
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) {
u16 val;
/* 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;
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) */
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;
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 {
u16 val;
/* 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 |= 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);
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)
{
unsigned long timeout;
u32 boot_data;
int ret = 0;
/* 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 */
timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
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);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
@ -943,12 +1038,15 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
}
/* 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*/
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)
@ -969,16 +1067,23 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
}
/* 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);
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)
to be used by DRPw FW. The RTRIM value will be added by the FW
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);
@ -987,12 +1092,18 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
else
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 */
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);
if (ret < 0)
@ -1002,47 +1113,72 @@ out:
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
* 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);
/* 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
* to upload_fw) */
if (wl->chip.id == CHIP_ID_1283_PG20)
wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
if (wl->chip.id == CHIP_ID_1283_PG20) {
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 = 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 */
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_write_reg(wl, REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
ret = wlcore_write_reg(wl, REG_INTERRUPT_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)
@ -1057,7 +1193,9 @@ static int wl12xx_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
wl12xx_pre_upload(wl);
ret = wl12xx_pre_upload(wl);
if (ret < 0)
goto out;
ret = wlcore_boot_upload_firmware(wl);
if (ret < 0)
@ -1067,22 +1205,30 @@ static int wl12xx_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
wl12xx_enable_interrupts(wl);
ret = wl12xx_enable_interrupts(wl);
out:
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)
{
wl1271_write(wl, cmd_box_addr, buf, len, false);
wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD);
int ret;
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)
@ -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;
}
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 ==
(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)
@ -1269,39 +1415,58 @@ static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
return supported;
}
static void wl12xx_get_fuse_mac(struct wl1271 *wl)
static int wl12xx_get_fuse_mac(struct wl1271 *wl)
{
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);
mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1, &mac1);
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 */
wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
((mac1 & 0xff000000) >> 24);
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)
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
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))
wl12xx_get_fuse_mac(wl);
return wl12xx_get_fuse_mac(wl);
return 0;
}
static void wl12xx_set_tx_desc_csum(struct wl1271 *wl,

View File

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

View File

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

View File

@ -22,7 +22,7 @@
#ifndef __WL18XX_IO_H__
#define __WL18XX_IO_H__
void 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_write(struct wl1271 *wl, int addr, u16 val);
int __must_check wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out);
#endif /* __WL18XX_IO_H__ */

View File

@ -612,20 +612,11 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
WLCORE_QUIRK_TX_PAD_LAST_FRAME;
break;
case CHIP_ID_185x_PG10:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG10)",
wl->chip.id);
wl->sr_fw_name = WL18XX_FW_NAME;
/* wl18xx uses the same firmware for PLT */
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;
wl1271_warning("chip id 0x%x (185x PG10) is deprecated",
wl->chip.id);
ret = -ENODEV;
goto out;
/* 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:
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
@ -636,123 +627,178 @@ out:
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 */
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,
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].swallow ? "swallow" : "spit");
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N, wl18xx_clk_table[clk_freq].n);
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M, wl18xx_clk_table[clk_freq].m);
ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N,
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) {
/* first the 16 lower bits */
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1,
wl18xx_clk_table[clk_freq].q &
PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK);
ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1,
wl18xx_clk_table[clk_freq].q &
PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK);
if (ret < 0)
goto out;
/* then the 16 higher bits, masked out */
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2,
(wl18xx_clk_table[clk_freq].q >> 16) &
PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK);
ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2,
(wl18xx_clk_table[clk_freq].q >> 16) &
PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK);
if (ret < 0)
goto out;
/* first the 16 lower bits */
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1,
wl18xx_clk_table[clk_freq].p &
PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK);
ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1,
wl18xx_clk_table[clk_freq].p &
PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK);
if (ret < 0)
goto out;
/* then the 16 higher bits, masked out */
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2,
(wl18xx_clk_table[clk_freq].p >> 16) &
PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK);
ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2,
(wl18xx_clk_table[clk_freq].p >> 16) &
PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK);
} else {
wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN,
PLLSH_WCS_PLL_SWALLOW_EN_VAL2);
ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN,
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 */
wl1271_write32(wl, WL18XX_ENABLE, 0x0);
ret = wlcore_write32(wl, WL18XX_ENABLE, 0x0);
if (ret < 0)
goto out;
/* 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)
{
wl18xx_set_clk(wl);
int ret;
ret = wl18xx_set_clk(wl);
if (ret < 0)
goto out;
/* 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);
wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
if (ret < 0)
goto out;
/* 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;
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 */
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);
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;
size_t len;
int ret;
/* the parameters struct is smaller for PG1 */
if (wl->chip.id == CHIP_ID_185x_PG10)
len = offsetof(struct wl18xx_mac_and_phy_params, psat) + 1;
else
len = sizeof(struct wl18xx_mac_and_phy_params);
ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
if (ret < 0)
goto out;
wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
wl1271_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy, len,
false);
ret = wlcore_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy,
sizeof(struct wl18xx_mac_and_phy_params), 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;
int ret;
if (wl->chip.id == CHIP_ID_185x_PG10) {
event_mask = WL18XX_ACX_EVENTS_VECTOR_PG1;
intr_mask = WL18XX_INTR_MASK_PG1;
} else {
event_mask = WL18XX_ACX_EVENTS_VECTOR_PG2;
intr_mask = WL18XX_INTR_MASK_PG2;
}
event_mask = WL18XX_ACX_EVENTS_VECTOR;
intr_mask = WL18XX_INTR_MASK;
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_write_reg(wl, REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~intr_mask);
ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~intr_mask);
out:
return ret;
}
static int wl18xx_boot(struct wl1271 *wl)
@ -763,25 +809,29 @@ static int wl18xx_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
wl18xx_pre_upload(wl);
ret = wl18xx_pre_upload(wl);
if (ret < 0)
goto out;
ret = wlcore_boot_upload_firmware(wl);
if (ret < 0)
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);
if (ret < 0)
goto out;
wl18xx_enable_interrupts(wl);
ret = wl18xx_enable_interrupts(wl);
out:
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)
{
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);
memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len);
wl1271_write(wl, cmd_box_addr, priv->cmd_buf, WL18XX_CMD_MAX_SIZE,
false);
return wlcore_write(wl, cmd_box_addr, priv->cmd_buf,
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)
@ -977,34 +1028,32 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
} else if (!strcmp(ht_mode_param, "mimo")) {
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;
} else {
return 0;
}
}
static s8 wl18xx_get_pg_ver(struct wl1271 *wl)
static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
{
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);
fuse = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse);
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"
@ -1070,26 +1119,41 @@ out:
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);
}
static void wl18xx_get_mac(struct wl1271 *wl)
static int wl18xx_get_mac(struct wl1271 *wl)
{
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);
mac2 = wl1271_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2);
ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1, &mac1);
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 */
wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
((mac1 & 0xff000000) >> 24);
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,

View File

@ -33,16 +33,22 @@
#include "rx.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;
int ret;
/* 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) */
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,
@ -87,7 +93,9 @@ static int wlcore_boot_static_data(struct wl1271 *wl)
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);
if (ret < 0)
@ -109,6 +117,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
struct wlcore_partition_set partition;
int addr, chunk_num, partition_limit;
u8 *p, *chunk;
int ret;
/* 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));
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 */
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 +
wl->ptable[PART_DOWN].mem.size;
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 */
@ -153,7 +166,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
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++;
}
@ -164,10 +179,11 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
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);
return 0;
return ret;
}
int wlcore_boot_upload_firmware(struct wl1271 *wl)
@ -210,6 +226,7 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
int i;
u32 dest_addr, val;
u8 *nvs_ptr, *nvs_aligned;
int ret;
if (wl->nvs == NULL) {
wl1271_error("NVS file is needed during boot");
@ -307,7 +324,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x",
dest_addr, val);
wl1271_write32(wl, dest_addr, val);
ret = wlcore_write32(wl, dest_addr, val);
if (ret < 0)
return ret;
nvs_ptr += 4;
dest_addr += 4;
@ -333,7 +352,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
nvs_len -= nvs_ptr - (u8 *)wl->nvs;
/* 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 */
nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
@ -341,11 +362,11 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
return -ENOMEM;
/* And finally we upload the NVS tables */
wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS,
nvs_aligned, nvs_len, false);
ret = wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, nvs_aligned, nvs_len,
false);
kfree(nvs_aligned);
return 0;
return ret;
out_badnvs:
wl1271_error("nvs data is malformed");
@ -359,11 +380,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
u32 chip_id, intr;
/* 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);
@ -376,7 +403,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
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) {
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 */
else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE);
ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE);
if (ret < 0)
return ret;
break;
}
}
@ -398,12 +429,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
}
/* 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);
/* 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);
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 */
wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
/* firmware startup completed */
return 0;
return ret;
}
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(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
* 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);
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)) {
if (time_after(jiffies, 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
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 */
if (res_len == 0)
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);
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;
}
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;
fail:
WARN_ON(1);
wl12xx_queue_recovery_work(wl);
return ret;
}
@ -117,35 +132,45 @@ fail:
* Poll the mailbox event field until any of the bits in the mask is set or a
* 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 event;
unsigned long timeout;
unsigned long timeout_time;
int ret = 0;
*timeout = false;
events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA);
if (!events_vector)
return -ENOMEM;
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
do {
if (time_after(jiffies, timeout)) {
if (time_after(jiffies, timeout_time)) {
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
(int)mask);
ret = -ETIMEDOUT;
*timeout = true;
goto out;
}
msleep(1);
/* read from both event fields */
wl1271_read(wl, wl->mbox_ptr[0], events_vector,
sizeof(*events_vector), false);
ret = wlcore_read(wl, wl->mbox_ptr[0], events_vector,
sizeof(*events_vector), false);
if (ret < 0)
goto out;
event = *events_vector & mask;
wl1271_read(wl, wl->mbox_ptr[1], events_vector,
sizeof(*events_vector), false);
ret = wlcore_read(wl, wl->mbox_ptr[1], events_vector,
sizeof(*events_vector), false);
if (ret < 0)
goto out;
event |= *events_vector & mask;
} while (!event);
@ -157,9 +182,10 @@ out:
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
{
int ret;
bool timeout = false;
ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
if (ret != 0) {
ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout);
if (ret != 0 || timeout) {
wl12xx_queue_recovery_work(wl);
return ret;
}
@ -1412,6 +1438,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
{
struct wl12xx_cmd_remove_peer *cmd;
int ret;
bool timeout = false;
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;
}
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
* 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,
PEER_REMOVE_COMPLETE_EVENT_ID);
if (ret)
wl12xx_queue_recovery_work(wl);
out_free:
kfree(cmd);
@ -1754,7 +1785,9 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
return -EINVAL;
/* 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)) {
ret = wl12xx_croc(wl, wlvif->dev_role_id);

View File

@ -38,6 +38,8 @@
/* ms */
#define WL1271_DEBUGFS_STATS_LIFETIME 1000
#define WLCORE_MAX_BLOCK_SIZE ((size_t)(4*PAGE_SIZE))
/* debugfs macros idea from mac80211 */
int wl1271_format_buffer(char __user *userbuf, size_t count,
loff_t *ppos, char *fmt, ...)
@ -1025,6 +1027,195 @@ static const struct file_operations sleep_auth_ops = {
.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,
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, always, streaming);
DEBUGFS_ADD_PREFIX(dev, mem, rootdir);
return 0;

View File

@ -105,6 +105,7 @@ static int wl1271_event_process(struct wl1271 *wl)
u32 vector;
bool disconnect_sta = false;
unsigned long sta_bitmap = 0;
int ret;
wl1271_event_mbox_dump(mbox);
@ -228,7 +229,9 @@ static int wl1271_event_process(struct wl1271 *wl)
if ((vector & DUMMY_PACKET_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;
/* first we read the mbox descriptor */
wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
sizeof(*wl->mbox), false);
ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
sizeof(*wl->mbox), false);
if (ret < 0)
return ret;
/* process the descriptor */
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
* 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);
}
static inline void
static inline int
wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
{
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
@ -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);
}
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)
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)

View File

@ -48,6 +48,12 @@ void wlcore_disable_interrupts(struct wl1271 *wl)
}
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)
{
enable_irq(wl->irq);
@ -122,9 +128,11 @@ EXPORT_SYMBOL_GPL(wlcore_translate_addr);
* | |
*
*/
void wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p)
int wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p)
{
int ret;
/* copy partition info */
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",
p->mem3.start, p->mem3.size);
wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
ret = wlcore_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
if (ret < 0)
goto out;
ret = wlcore_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.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
* automatically calculated based on the total memory size and
* 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);
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)
{
if (wl->if_ops->reset)

View File

@ -45,6 +45,7 @@
struct wl1271;
void wlcore_disable_interrupts(struct wl1271 *wl);
void wlcore_disable_interrupts_nosync(struct wl1271 *wl);
void wlcore_enable_interrupts(struct wl1271 *wl);
void wl1271_io_reset(struct wl1271 *wl);
@ -52,79 +53,113 @@ void wl1271_io_init(struct wl1271 *wl);
int wlcore_translate_addr(struct wl1271 *wl, int addr);
/* Raw target IO, address is not translated */
static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr,
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,
size_t len, bool fixed)
static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr,
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,
size_t len, bool fixed)
static inline int __must_check wlcore_raw_read_data(struct wl1271 *wl, int reg,
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,
size_t len, bool fixed)
static inline int __must_check wlcore_raw_write_data(struct wl1271 *wl, int reg,
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,
sizeof(wl->buffer_32), false);
int ret;
return le32_to_cpu(wl->buffer_32);
ret = wlcore_raw_read(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
if (ret < 0)
return ret;
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);
wl1271_raw_write(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
return wlcore_raw_write(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
}
static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed)
static inline int __must_check wlcore_read(struct wl1271 *wl, int addr,
void *buf, size_t len, bool fixed)
{
int physical;
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 void wl1271_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool 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);
wl1271_raw_write(wl, physical, buf, len, fixed);
return wlcore_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)
static inline int __must_check wlcore_write_data(struct wl1271 *wl, int reg,
void *buf, size_t len,
bool fixed)
{
wl1271_write(wl, wl->rtable[reg], buf, len, fixed);
return wlcore_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)
static inline int __must_check wlcore_read_data(struct wl1271 *wl, int reg,
void *buf, size_t len,
bool fixed)
{
wl1271_read(wl, wl->rtable[reg], buf, len, fixed);
return wlcore_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)
static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr,
void *buf, size_t len,
bool fixed)
{
int physical;
int addr;
@ -134,34 +169,47 @@ static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
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,
wlcore_translate_addr(wl, wl->rtable[reg]));
return wlcore_raw_read32(wl,
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)
{
wl->if_ops->power(wl->dev, false);
clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
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);
}
static inline int wl1271_power_on(struct wl1271 *wl)
@ -173,8 +221,8 @@ static inline int wl1271_power_on(struct wl1271 *wl)
return ret;
}
void wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p);
int wlcore_set_partition(struct wl1271 *wl,
const struct wlcore_partition_set *p);
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);
void wlcore_select_partition(struct wl1271 *wl, u8 part);
#endif

View File

@ -378,9 +378,9 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
}
}
static void wl12xx_fw_status(struct wl1271 *wl,
struct wl_fw_status_1 *status_1,
struct wl_fw_status_2 *status_2)
static int wlcore_fw_status(struct wl1271 *wl,
struct wl_fw_status_1 *status_1,
struct wl_fw_status_2 *status_2)
{
struct wl12xx_vif *wlvif;
struct timespec ts;
@ -388,12 +388,15 @@ static void wl12xx_fw_status(struct wl1271 *wl,
int avail, freed_blocks;
int i;
size_t status_len;
int ret;
status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
sizeof(*status_2) + wl->fw_status_priv_len;
wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
status_len, false);
ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
status_len, false);
if (ret < 0)
return ret;
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
@ -462,6 +465,8 @@ static void wl12xx_fw_status(struct wl1271 *wl,
getnstimeofday(&ts);
wl->time_offset = (timespec_to_ns(&ts) >> 10) -
(s64)le32_to_cpu(status_2->fw_localtime);
return 0;
}
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
static irqreturn_t wl1271_irq(int irq, void *cookie)
static int wlcore_irq_locked(struct wl1271 *wl)
{
int ret;
int ret = 0;
u32 intr;
int loopcount = WL1271_IRQ_MAX_LOOPS;
struct wl1271 *wl = (struct wl1271 *)cookie;
bool done = false;
unsigned int defer_count;
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
* 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)
loopcount = 1;
mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_IRQ, "IRQ work");
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);
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);
@ -544,7 +544,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
wl1271_error("HW watchdog interrupt received! starting recovery.");
wl->watchdog_recovery = true;
wl12xx_queue_recovery_work(wl);
ret = -EIO;
/* restarting the chip. ignore any other interrupt. */
goto out;
@ -554,7 +554,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl1271_error("SW watchdog interrupt received! "
"starting recovery.");
wl->watchdog_recovery = true;
wl12xx_queue_recovery_work(wl);
ret = -EIO;
/* restarting the chip. ignore any other interrupt. */
goto out;
@ -563,7 +563,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
if (likely(intr & 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 */
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,
* call the work function directly.
*/
wl1271_tx_work_locked(wl);
ret = wlcore_tx_work_locked(wl);
if (ret < 0)
goto out;
} else {
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
/* 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 */
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) {
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) {
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)
@ -610,6 +620,25 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl1271_ps_elp_sleep(wl);
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);
/* In case TX was not handled here, queue TX work */
clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
@ -743,8 +772,13 @@ out:
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);
}
}
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 end_of_log;
u8 *block;
int ret;
if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
(wl->conf.fwlog.mem_blocks == 0))
@ -799,7 +834,10 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
wl12xx_cmd_stop_fwlog(wl);
/* 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);
if (!addr)
goto out;
@ -815,8 +853,10 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
/* Traverse the memory blocks linked list */
do {
memset(block, 0, WL12XX_HW_BLOCK_SIZE);
wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
false);
ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
false);
if (ret < 0)
goto out;
/*
* Memory blocks are linked to one another. The first 4 bytes
@ -836,6 +876,34 @@ out:
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)
{
struct wl1271 *wl =
@ -848,19 +916,9 @@ static void wl1271_recovery_work(struct work_struct *work)
if (wl->state != WL1271_STATE_ON || wl->plt)
goto out_unlock;
/* Avoid a recursive recovery */
set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
wl12xx_read_fwlog_panic(wl);
/* change partitions momentarily so we can read the FW pc */
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]);
wlcore_print_recovery(wl);
BUG_ON(bug_on_recovery &&
!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);
wl1271_op_stop(wl->hw);
clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
ieee80211_restart_hw(wl->hw);
/*
@ -917,9 +973,9 @@ out_unlock:
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)
@ -955,13 +1011,21 @@ static int wl12xx_set_power_on(struct wl1271 *wl)
wl1271_io_reset(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 */
wl1271_fw_wakeup(wl);
ret = wlcore_fw_wakeup(wl);
if (ret < 0)
goto fail;
out:
return ret;
fail:
wl1271_power_off(wl);
return ret;
}
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 */
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
@ -1451,8 +1515,15 @@ static int wl1271_configure_wowlan(struct wl1271 *wl,
int i, ret;
if (!wow || wow->any || !wow->n_patterns) {
wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
wl1271_rx_filter_clear_all(wl);
ret = wl1271_acx_default_rx_filter_enable(wl, 0,
FILTER_SIGNAL);
if (ret)
goto out;
ret = wl1271_rx_filter_clear_all(wl);
if (ret)
goto out;
return 0;
}
@ -1468,8 +1539,13 @@ static int wl1271_configure_wowlan(struct wl1271 *wl,
}
}
wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
wl1271_rx_filter_clear_all(wl);
ret = wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
if (ret)
goto out;
ret = wl1271_rx_filter_clear_all(wl);
if (ret)
goto out;
/* Translate WoWLAN patterns into filters */
for (i = 0; i < wow->n_patterns; i++) {
@ -1511,7 +1587,10 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0)
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,
wl->conf.conn.suspend_wake_up_event,
wl->conf.conn.suspend_listen_interval);
@ -1519,8 +1598,8 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0)
wl1271_error("suspend: set wake up conditions failed: %d", ret);
out_sleep:
wl1271_ps_elp_sleep(wl);
out:
return ret;
@ -1599,6 +1678,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!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);
mutex_lock(&wl->mutex);
@ -1639,7 +1724,8 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif;
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",
wl->wow_enabled);
@ -1655,17 +1741,37 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
run_irq_work = true;
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) {
wl1271_debug(DEBUG_MAC80211,
"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);
}
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) {
wl1271_configure_resume(wl, wlvif);
}
out:
wl->wow_enabled = false;
mutex_unlock(&wl->mutex);
@ -1706,6 +1812,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wlcore_disable_interrupts(wl);
mutex_lock(&wl->mutex);
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);
/*
@ -1737,6 +1847,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
mutex_lock(&wl->mutex);
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;
@ -2475,7 +2592,10 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
(wlvif->channel != channel) ||
(wlvif->channel_type != conf->channel_type))) {
/* 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->channel = channel;
wlvif->channel_type = conf->channel_type;
@ -4934,18 +5054,22 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
if (ret < 0)
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_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)
wl->ops->get_mac(wl);
ret = wl->ops->get_mac(wl);
wl1271_power_off(wl);
out:
wl1271_power_off(wl);
return ret;
}
@ -5372,7 +5496,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
else
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,
pdev->name, wl);
if (ret < 0) {
@ -5398,12 +5522,12 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
ret = wl12xx_get_hw_info(wl);
if (ret < 0) {
wl1271_error("couldn't get hw info");
goto out;
goto out_irq;
}
ret = wl->ops->identify_chip(wl);
if (ret < 0)
goto out;
goto out_irq;
ret = wl1271_init_ieee80211(wl);
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);
if (ret < 0) {
wl1271_error("failed to create sysfs file bt_coex_state");
goto out_irq;
goto out_unreg;
}
/* Create sysfs file to get HW PG version */
@ -5442,6 +5566,9 @@ out_hw_pg_ver:
out_bt_coex_state:
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
out_unreg:
wl1271_unregister_hw(wl);
out_irq:
free_irq(wl->irq, wl);

View File

@ -35,6 +35,7 @@ void wl1271_elp_work(struct work_struct *work)
struct delayed_work *dwork;
struct wl1271 *wl;
struct wl12xx_vif *wlvif;
int ret;
dwork = container_of(work, struct delayed_work, 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_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);
out:
@ -135,7 +141,11 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
wl->elp_compl = &compl;
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) {
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;
}
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};
u32 buf_size;
@ -211,6 +211,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
u32 pkt_offset, des;
u8 hlid;
enum wl_rx_buf_align rx_align;
int ret = 0;
while (drv_rx_counter != fw_rx_counter) {
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 */
des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
wlcore_hw_prepare_read(wl, des, buf_size);
wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_size, true);
ret = wlcore_hw_prepare_read(wl, des, buf_size);
if (ret < 0)
goto out;
ret = wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_size, true);
if (ret < 0)
goto out;
/* Split data into separate packets */
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
* for older hardware revisions
*/
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
wl->rx_counter);
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
ret = wlcore_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
wl->rx_counter);
if (ret < 0)
goto out;
}
wl12xx_rearm_rx_streaming(wl, active_hlids);
out:
return ret;
}
#ifdef CONFIG_PM
@ -306,14 +318,19 @@ int wl1271_rx_filter_enable(struct wl1271 *wl,
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++) {
if (!wl->rx_filter_enabled[i])
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 */

View File

@ -143,11 +143,11 @@ struct wl1271_rx_descriptor {
u8 reserved;
} __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);
int wl1271_rx_filter_enable(struct wl1271 *wl,
int index, bool enable,
struct wl12xx_rx_filter *filter);
void wl1271_rx_filter_clear_all(struct wl1271 *wl);
int wl1271_rx_filter_clear_all(struct wl1271 *wl);
#endif

View File

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

View File

@ -193,8 +193,8 @@ static int wl12xx_spi_read_busy(struct device *child)
return -ETIMEDOUT;
}
static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
size_t len, bool fixed)
static int __must_check wl12xx_spi_raw_read(struct device *child, int addr,
void *buf, size_t len, bool fixed)
{
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
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) &&
wl12xx_spi_read_busy(child)) {
memset(buf, 0, chunk_len);
return;
return 0;
}
spi_message_init(&m);
@ -256,10 +256,12 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
buf += chunk_len;
len -= chunk_len;
}
return 0;
}
static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf,
size_t len, bool fixed)
static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
void *buf, size_t len, bool fixed)
{
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
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);
return 0;
}
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_gem = false;
if (!skb)
if (!skb) {
wl1271_error("discarding null skb");
return -EINVAL;
}
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 sk_buff *skb;
@ -670,10 +682,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
u32 buf_offset = 0, last_len = 0;
bool sent_packets = false;
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))
return;
return 0;
while ((skb = wl1271_skb_dequeue(wl))) {
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,
last_len);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true);
bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA,
wl->aggr_buf, buf_offset, true);
if (bus_ret < 0)
goto out;
sent_packets = true;
buf_offset = 0;
continue;
@ -731,8 +747,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
out_ack:
if (buf_offset) {
buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len);
wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true);
bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
buf_offset, true);
if (bus_ret < 0)
goto out;
sent_packets = true;
}
if (sent_packets) {
@ -740,13 +759,19 @@ out_ack:
* Interrupt the firmware with the new packets. This is only
* required for older hardware revisions
*/
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
wl1271_write32(wl, WL12XX_HOST_WR_ACCESS,
wl->tx_packets_count);
if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS,
wl->tx_packets_count);
if (bus_ret < 0)
goto out;
}
wl1271_handle_tx_low_watermark(wl);
}
wl12xx_rearm_rx_streaming(wl, active_hlids);
out:
return bus_ret;
}
void wl1271_tx_work(struct work_struct *work)
@ -759,7 +784,11 @@ void wl1271_tx_work(struct work_struct *work)
if (ret < 0)
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);
out:
@ -881,22 +910,28 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
}
/* 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 *)wl->target_mem_map;
u32 count, fw_counter;
u32 i;
int ret;
/* read the tx results from the chipset */
wl1271_read(wl, le32_to_cpu(memmap->tx_result),
wl->tx_res_if, sizeof(*wl->tx_res_if), false);
ret = wlcore_read(wl, le32_to_cpu(memmap->tx_result),
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);
/* write host counter to chipset (to ack) */
wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
offsetof(struct wl1271_tx_hw_res_if,
tx_result_host_counter), fw_counter);
ret = wlcore_write32(wl, le32_to_cpu(memmap->tx_result) +
offsetof(struct wl1271_tx_hw_res_if,
tx_result_host_counter), fw_counter);
if (ret < 0)
goto out;
count = fw_counter - wl->tx_results_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++;
}
out:
return ret;
}
EXPORT_SYMBOL(wl1271_tx_complete);
EXPORT_SYMBOL(wlcore_tx_complete);
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_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl);
int wlcore_tx_work_locked(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(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 (*boot)(struct wl1271 *wl);
int (*plt_init)(struct wl1271 *wl);
void (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
void *buf, size_t len);
void (*ack_event)(struct wl1271 *wl);
int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
void *buf, size_t len);
int (*ack_event)(struct wl1271 *wl);
u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks);
void (*set_tx_desc_blocks)(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc,
@ -53,17 +53,17 @@ struct wlcore_ops {
struct sk_buff *skb);
enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl,
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 data_len);
void (*tx_delayed_compl)(struct wl1271 *wl);
int (*tx_delayed_compl)(struct wl1271 *wl);
void (*tx_immediate_compl)(struct wl1271 *wl);
int (*hw_init)(struct wl1271 *wl);
int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl,
struct wl12xx_vif *wlvif);
s8 (*get_pg_ver)(struct wl1271 *wl);
void (*get_mac)(struct wl1271 *wl);
int (*get_pg_ver)(struct wl1271 *wl, s8 *ver);
int (*get_mac)(struct wl1271 *wl);
void (*set_tx_desc_csum)(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc,
struct sk_buff *skb);

View File

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