mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08:00
Merge branch 'wl12xx-next' into for-linville
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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(
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user