mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
commit
e4d680c706
67 changed files with 3270 additions and 1374 deletions
|
@ -65,7 +65,7 @@ void bcma_core_set_clockmode(struct bcma_device *core,
|
|||
switch (clkmode) {
|
||||
case BCMA_CLKMODE_FAST:
|
||||
bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
|
||||
udelay(64);
|
||||
usleep_range(64, 300);
|
||||
for (i = 0; i < 1500; i++) {
|
||||
if (bcma_read32(core, BCMA_CLKCTLST) &
|
||||
BCMA_CLKCTLST_HAVEHT) {
|
||||
|
|
|
@ -76,7 +76,10 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
|
|||
if (max_msk)
|
||||
bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
|
||||
|
||||
/* Add some delay; allow resources to come up and settle. */
|
||||
/*
|
||||
* Add some delay; allow resources to come up and settle.
|
||||
* Delay is required for SoC (early init).
|
||||
*/
|
||||
mdelay(2);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
|
|||
v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
|
||||
if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
|
||||
break;
|
||||
msleep(1);
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
|
|||
ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA);
|
||||
break;
|
||||
}
|
||||
msleep(1);
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
|
||||
return ret;
|
||||
|
@ -132,7 +132,7 @@ static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
|
|||
v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
|
||||
if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
|
||||
break;
|
||||
msleep(1);
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
|
||||
}
|
||||
|
|
|
@ -425,9 +425,9 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
|
|||
pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
|
||||
|
||||
/* Reset RC */
|
||||
udelay(3000);
|
||||
usleep_range(3000, 5000);
|
||||
pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
|
||||
udelay(1000);
|
||||
usleep_range(1000, 2000);
|
||||
pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
|
||||
BCMA_CORE_PCI_CTL_RST_OE);
|
||||
|
||||
|
@ -481,7 +481,7 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
|
|||
* before issuing configuration requests to PCI Express
|
||||
* devices.
|
||||
*/
|
||||
udelay(100000);
|
||||
msleep(100);
|
||||
|
||||
bcma_core_pci_enable_crs(pc);
|
||||
|
||||
|
@ -501,7 +501,7 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
|
|||
set_io_port_base(pc_host->pci_controller.io_map_base);
|
||||
/* Give some time to the PCI controller to configure itself with the new
|
||||
* values. Not waiting at this point causes crashes of the machine. */
|
||||
mdelay(10);
|
||||
usleep_range(10000, 15000);
|
||||
register_pci_controller(&pc_host->pci_controller);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -182,6 +182,7 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
|
|||
struct ath9k_hw_capabilities *pCap = &ah->caps;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u32 sync_cause = 0, async_cause, async_mask = AR_INTR_MAC_IRQ;
|
||||
bool fatal_int;
|
||||
|
||||
if (ath9k_hw_mci_is_enabled(ah))
|
||||
async_mask |= AR_INTR_ASYNC_MASK_MCI;
|
||||
|
@ -310,6 +311,22 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
|
|||
|
||||
if (sync_cause) {
|
||||
ath9k_debug_sync_cause(common, sync_cause);
|
||||
fatal_int =
|
||||
(sync_cause &
|
||||
(AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
|
||||
? true : false;
|
||||
|
||||
if (fatal_int) {
|
||||
if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
|
||||
ath_dbg(common, ANY,
|
||||
"received PCI FATAL interrupt\n");
|
||||
}
|
||||
if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
|
||||
ath_dbg(common, ANY,
|
||||
"received PCI PERR interrupt\n");
|
||||
}
|
||||
*masked |= ATH9K_INT_FATAL;
|
||||
}
|
||||
|
||||
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
|
||||
REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
|
||||
|
|
|
@ -813,8 +813,8 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)
|
|||
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
|
||||
}
|
||||
|
||||
void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
|
||||
bool is_full_sleep)
|
||||
int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
|
||||
bool is_full_sleep)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
|
@ -824,14 +824,13 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
|
|||
is_full_sleep, is_2g);
|
||||
|
||||
if (!mci->gpm_addr && !mci->sched_addr) {
|
||||
ath_dbg(common, MCI,
|
||||
"MCI GPM and schedule buffers are not allocated\n");
|
||||
return;
|
||||
ath_err(common, "MCI GPM and schedule buffers are not allocated\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) {
|
||||
ath_dbg(common, MCI, "BTCOEX control register is dead\n");
|
||||
return;
|
||||
ath_err(common, "BTCOEX control register is dead\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Program MCI DMA related registers */
|
||||
|
@ -913,6 +912,8 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
|
|||
|
||||
if (en_int)
|
||||
ar9003_mci_enable_interrupt(ah);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
|
||||
|
@ -1144,8 +1145,8 @@ void ar9003_mci_init_cal_done(struct ath_hw *ah)
|
|||
ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
|
||||
}
|
||||
|
||||
void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
|
||||
u16 len, u32 sched_addr)
|
||||
int ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
|
||||
u16 len, u32 sched_addr)
|
||||
{
|
||||
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
|
||||
|
||||
|
@ -1154,7 +1155,7 @@ void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
|
|||
mci->gpm_len = len;
|
||||
mci->sched_addr = sched_addr;
|
||||
|
||||
ar9003_mci_reset(ah, true, true, true);
|
||||
return ar9003_mci_reset(ah, true, true, true);
|
||||
}
|
||||
EXPORT_SYMBOL(ar9003_mci_setup);
|
||||
|
||||
|
|
|
@ -249,8 +249,8 @@ bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
|
|||
u32 *payload, u8 len, bool wait_done,
|
||||
bool check_bt);
|
||||
u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type);
|
||||
void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
|
||||
u16 len, u32 sched_addr);
|
||||
int ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
|
||||
u16 len, u32 sched_addr);
|
||||
void ar9003_mci_cleanup(struct ath_hw *ah);
|
||||
void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
|
||||
u32 *rx_msg_intr);
|
||||
|
@ -272,8 +272,8 @@ void ar9003_mci_check_bt(struct ath_hw *ah);
|
|||
bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||
int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||
struct ath9k_hw_cal_data *caldata);
|
||||
void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
|
||||
bool is_full_sleep);
|
||||
int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
|
||||
bool is_full_sleep);
|
||||
void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
|
||||
void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
|
||||
void ar9003_mci_set_power_awake(struct ath_hw *ah);
|
||||
|
|
|
@ -1360,7 +1360,7 @@ static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah,
|
|||
if (enable) {
|
||||
REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL,
|
||||
(1 << AR_PHY_ANT_SW_RX_PROT_S));
|
||||
if (IS_CHAN_2GHZ(ah->curchan))
|
||||
if (ah->curchan && IS_CHAN_2GHZ(ah->curchan))
|
||||
REG_SET_BIT(ah, AR_PHY_RESTART,
|
||||
AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
|
||||
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,
|
||||
|
|
|
@ -173,6 +173,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
|
||||
#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
|
||||
|
||||
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
|
||||
|
||||
#define ATH_TX_COMPLETE_POLL_INT 1000
|
||||
|
||||
enum ATH_AGGR_STATUS {
|
||||
|
|
|
@ -43,8 +43,8 @@ static const u32 ar9003_wlan_weights[ATH_BTCOEX_STOMP_MAX]
|
|||
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* STOMP_NONE */
|
||||
};
|
||||
|
||||
static const u32 ar9462_wlan_weights[ATH_BTCOEX_STOMP_MAX]
|
||||
[AR9300_NUM_WLAN_WEIGHTS] = {
|
||||
static const u32 mci_wlan_weights[ATH_BTCOEX_STOMP_MAX]
|
||||
[AR9300_NUM_WLAN_WEIGHTS] = {
|
||||
{ 0x01017d01, 0x41414101, 0x41414101, 0x41414141 }, /* STOMP_ALL */
|
||||
{ 0x01017d01, 0x3b3b3b01, 0x3b3b3b01, 0x3b3b3b3b }, /* STOMP_LOW */
|
||||
{ 0x01017d01, 0x01010101, 0x01010101, 0x01010101 }, /* STOMP_NONE */
|
||||
|
@ -208,14 +208,37 @@ static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
|
|||
AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* For AR9002, bt_weight/wlan_weight are used.
|
||||
* For AR9003 and above, stomp_type is used.
|
||||
*/
|
||||
void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
|
||||
u32 bt_weight,
|
||||
u32 wlan_weight)
|
||||
u32 wlan_weight,
|
||||
enum ath_stomp_type stomp_type)
|
||||
{
|
||||
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
|
||||
|
||||
btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
|
||||
SM(wlan_weight, AR_BTCOEX_WL_WGHT);
|
||||
if (AR_SREV_9300_20_OR_LATER(ah)) {
|
||||
const u32 *weight = ar9003_wlan_weights[stomp_type];
|
||||
int i;
|
||||
|
||||
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
|
||||
if ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
|
||||
btcoex_hw->mci.stomp_ftp)
|
||||
stomp_type = ATH_BTCOEX_STOMP_LOW_FTP;
|
||||
weight = mci_wlan_weights[stomp_type];
|
||||
}
|
||||
|
||||
for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
|
||||
btcoex_hw->bt_weight[i] = AR9300_BT_WGHT;
|
||||
btcoex_hw->wlan_weight[i] = weight[i];
|
||||
}
|
||||
} else {
|
||||
btcoex_hw->bt_coex_weights =
|
||||
SM(bt_weight, AR_BTCOEX_BT_WGHT) |
|
||||
SM(wlan_weight, AR_BTCOEX_WL_WGHT);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
|
||||
|
||||
|
@ -282,7 +305,7 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah)
|
|||
ath9k_hw_btcoex_enable_2wire(ah);
|
||||
break;
|
||||
case ATH_BTCOEX_CFG_3WIRE:
|
||||
if (AR_SREV_9462(ah)) {
|
||||
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
|
||||
ath9k_hw_btcoex_enable_mci(ah);
|
||||
return;
|
||||
}
|
||||
|
@ -304,7 +327,7 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah)
|
|||
int i;
|
||||
|
||||
btcoex_hw->enabled = false;
|
||||
if (AR_SREV_9462(ah)) {
|
||||
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
|
||||
ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
|
||||
for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
|
||||
REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i),
|
||||
|
@ -332,26 +355,6 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah)
|
|||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_btcoex_disable);
|
||||
|
||||
static void ar9003_btcoex_bt_stomp(struct ath_hw *ah,
|
||||
enum ath_stomp_type stomp_type)
|
||||
{
|
||||
struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
|
||||
const u32 *weight = ar9003_wlan_weights[stomp_type];
|
||||
int i;
|
||||
|
||||
if (AR_SREV_9462(ah)) {
|
||||
if ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
|
||||
btcoex->mci.stomp_ftp)
|
||||
stomp_type = ATH_BTCOEX_STOMP_LOW_FTP;
|
||||
weight = ar9462_wlan_weights[stomp_type];
|
||||
}
|
||||
|
||||
for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
|
||||
btcoex->bt_weight[i] = AR9300_BT_WGHT;
|
||||
btcoex->wlan_weight[i] = weight[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures appropriate weight based on stomp type.
|
||||
*/
|
||||
|
@ -359,22 +362,22 @@ void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
|
|||
enum ath_stomp_type stomp_type)
|
||||
{
|
||||
if (AR_SREV_9300_20_OR_LATER(ah)) {
|
||||
ar9003_btcoex_bt_stomp(ah, stomp_type);
|
||||
ath9k_hw_btcoex_set_weight(ah, 0, 0, stomp_type);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (stomp_type) {
|
||||
case ATH_BTCOEX_STOMP_ALL:
|
||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||
AR_STOMP_ALL_WLAN_WGHT);
|
||||
AR_STOMP_ALL_WLAN_WGHT, 0);
|
||||
break;
|
||||
case ATH_BTCOEX_STOMP_LOW:
|
||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||
AR_STOMP_LOW_WLAN_WGHT);
|
||||
AR_STOMP_LOW_WLAN_WGHT, 0);
|
||||
break;
|
||||
case ATH_BTCOEX_STOMP_NONE:
|
||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||
AR_STOMP_NONE_WLAN_WGHT);
|
||||
AR_STOMP_NONE_WLAN_WGHT, 0);
|
||||
break;
|
||||
default:
|
||||
ath_dbg(ath9k_hw_common(ah), BTCOEX, "Invalid Stomptype\n");
|
||||
|
|
|
@ -107,7 +107,8 @@ void ath9k_hw_btcoex_init_mci(struct ath_hw *ah);
|
|||
void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum);
|
||||
void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
|
||||
u32 bt_weight,
|
||||
u32 wlan_weight);
|
||||
u32 wlan_weight,
|
||||
enum ath_stomp_type stomp_type);
|
||||
void ath9k_hw_btcoex_disable(struct ath_hw *ah);
|
||||
void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
|
||||
enum ath_stomp_type stomp_type);
|
||||
|
|
|
@ -222,6 +222,57 @@ static const struct file_operations fops_disable_ani = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t read_file_ant_diversity(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
char buf[32];
|
||||
unsigned int len;
|
||||
|
||||
len = sprintf(buf, "%d\n", common->antenna_diversity);
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t write_file_ant_diversity(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
unsigned long antenna_diversity;
|
||||
char buf[32];
|
||||
ssize_t len;
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, len))
|
||||
return -EFAULT;
|
||||
|
||||
if (!AR_SREV_9565(sc->sc_ah))
|
||||
goto exit;
|
||||
|
||||
buf[len] = '\0';
|
||||
if (strict_strtoul(buf, 0, &antenna_diversity))
|
||||
return -EINVAL;
|
||||
|
||||
common->antenna_diversity = !!antenna_diversity;
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath_ant_comb_update(sc);
|
||||
ath_dbg(common, CONFIG, "Antenna diversity: %d\n",
|
||||
common->antenna_diversity);
|
||||
ath9k_ps_restore(sc);
|
||||
exit:
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_ant_diversity = {
|
||||
.read = read_file_ant_diversity,
|
||||
.write = write_file_ant_diversity,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t read_file_dma(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -1601,12 +1652,12 @@ int ath9k_init_debug(struct ath_hw *ah)
|
|||
debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
|
||||
&fops_samps);
|
||||
#endif
|
||||
|
||||
debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
|
||||
sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
|
||||
|
||||
debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
|
||||
sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
|
||||
debugfs_create_file("diversity", S_IRUSR | S_IWUSR,
|
||||
sc->debug.debugfs_phy, sc, &fops_ant_diversity);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -395,7 +395,10 @@ void ath9k_start_btcoex(struct ath_softc *sc)
|
|||
!ah->btcoex_hw.enabled) {
|
||||
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
|
||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||
AR_STOMP_LOW_WLAN_WGHT);
|
||||
AR_STOMP_LOW_WLAN_WGHT, 0);
|
||||
else
|
||||
ath9k_hw_btcoex_set_weight(ah, 0, 0,
|
||||
ATH_BTCOEX_STOMP_NONE);
|
||||
ath9k_hw_btcoex_enable(ah);
|
||||
|
||||
if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
|
||||
|
@ -412,7 +415,7 @@ void ath9k_stop_btcoex(struct ath_softc *sc)
|
|||
if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
|
||||
ath9k_btcoex_timer_pause(sc);
|
||||
ath9k_hw_btcoex_disable(ah);
|
||||
if (AR_SREV_9462(ah))
|
||||
if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
|
||||
ath_mci_flush_profile(&sc->btcoex.mci);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv)
|
|||
|
||||
if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) {
|
||||
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
|
||||
AR_STOMP_LOW_WLAN_WGHT);
|
||||
AR_STOMP_LOW_WLAN_WGHT, 0);
|
||||
ath9k_hw_btcoex_enable(ah);
|
||||
ath_htc_resume_btcoex_work(priv);
|
||||
}
|
||||
|
|
|
@ -392,6 +392,7 @@ int ath_mci_setup(struct ath_softc *sc)
|
|||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_mci_coex *mci = &sc->mci_coex;
|
||||
struct ath_mci_buf *buf = &mci->sched_buf;
|
||||
int ret;
|
||||
|
||||
buf->bf_addr = dma_alloc_coherent(sc->dev,
|
||||
ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
|
||||
|
@ -411,9 +412,13 @@ int ath_mci_setup(struct ath_softc *sc)
|
|||
mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr + mci->sched_buf.bf_len;
|
||||
mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len;
|
||||
|
||||
ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr,
|
||||
mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
|
||||
mci->sched_buf.bf_paddr);
|
||||
ret = ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr,
|
||||
mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
|
||||
mci->sched_buf.bf_paddr);
|
||||
if (ret) {
|
||||
ath_err(common, "Failed to initialize MCI\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
INIT_WORK(&sc->mci_work, ath9k_mci_work);
|
||||
ath_dbg(common, MCI, "MCI Initialized\n");
|
||||
|
|
|
@ -424,8 +424,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
|||
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
|
||||
|
||||
if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
|
||||
/* The following may also be needed for other older chips */
|
||||
if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
|
||||
/* This is needed for older chips */
|
||||
if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160)
|
||||
rfilt |= ATH9K_RX_FILTER_PROM;
|
||||
rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
|
||||
}
|
||||
|
|
|
@ -497,7 +497,7 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
|
|||
|
||||
REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
|
||||
|
||||
if (AR_SREV_9462(ah)) {
|
||||
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
|
||||
/*
|
||||
* this is needed to prevent the chip waking up
|
||||
* the host within 3-4 seconds with certain
|
||||
|
|
|
@ -1820,10 +1820,14 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
|
|||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath9k_channel *curchan = ah->curchan;
|
||||
|
||||
if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) &&
|
||||
(curchan->channelFlags & CHANNEL_5GHZ) &&
|
||||
(chainmask == 0x7) && (rate < 0x90))
|
||||
return 0x3;
|
||||
else if (AR_SREV_9462(ah) && ath9k_hw_btcoex_is_enabled(ah) &&
|
||||
IS_CCK_RATE(rate))
|
||||
return 0x2;
|
||||
else
|
||||
return chainmask;
|
||||
}
|
||||
|
|
|
@ -3895,6 +3895,8 @@ static void b43legacy_remove(struct ssb_device *dev)
|
|||
cancel_work_sync(&wl->firmware_load);
|
||||
|
||||
B43legacy_WARN_ON(!wl);
|
||||
if (!wldev->fw.ucode)
|
||||
return; /* NULL if fw never loaded */
|
||||
if (wl->current_dev == wldev)
|
||||
ieee80211_unregister_hw(wl->hw);
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* IO codes that are interpreted by dongle firmware
|
||||
******************************************************************************/
|
||||
#define BRCMF_C_UP 2
|
||||
#define BRCMF_C_DOWN 3
|
||||
#define BRCMF_C_SET_PROMISC 10
|
||||
#define BRCMF_C_GET_RATE 12
|
||||
#define BRCMF_C_GET_INFRA 19
|
||||
|
@ -50,7 +51,10 @@
|
|||
#define BRCMF_C_REASSOC 53
|
||||
#define BRCMF_C_SET_ROAM_TRIGGER 55
|
||||
#define BRCMF_C_SET_ROAM_DELTA 57
|
||||
#define BRCMF_C_GET_BCNPRD 75
|
||||
#define BRCMF_C_SET_BCNPRD 76
|
||||
#define BRCMF_C_GET_DTIMPRD 77
|
||||
#define BRCMF_C_SET_DTIMPRD 78
|
||||
#define BRCMF_C_SET_COUNTRY 84
|
||||
#define BRCMF_C_GET_PM 85
|
||||
#define BRCMF_C_SET_PM 86
|
||||
|
@ -134,6 +138,9 @@
|
|||
|
||||
#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
|
||||
|
||||
#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
|
||||
#define BRCMF_STA_ASSOC 0x10 /* Associated */
|
||||
|
||||
struct brcmf_event_msg {
|
||||
__be16 version;
|
||||
__be16 flags;
|
||||
|
@ -566,6 +573,28 @@ struct brcmf_channel_info_le {
|
|||
__le32 scan_channel;
|
||||
};
|
||||
|
||||
struct brcmf_sta_info_le {
|
||||
__le16 ver; /* version of this struct */
|
||||
__le16 len; /* length in bytes of this structure */
|
||||
__le16 cap; /* sta's advertised capabilities */
|
||||
__le32 flags; /* flags defined below */
|
||||
__le32 idle; /* time since data pkt rx'd from sta */
|
||||
u8 ea[ETH_ALEN]; /* Station address */
|
||||
__le32 count; /* # rates in this set */
|
||||
u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */
|
||||
/* w/hi bit set if basic */
|
||||
__le32 in; /* seconds elapsed since associated */
|
||||
__le32 listen_interval_inms; /* Min Listen interval in ms for STA */
|
||||
__le32 tx_pkts; /* # of packets transmitted */
|
||||
__le32 tx_failures; /* # of packets failed */
|
||||
__le32 rx_ucast_pkts; /* # of unicast packets received */
|
||||
__le32 rx_mcast_pkts; /* # of multicast packets received */
|
||||
__le32 tx_rate; /* Rate of last successful tx frame */
|
||||
__le32 rx_rate; /* Rate of last successful rx frame */
|
||||
__le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */
|
||||
__le32 rx_decrypt_failures; /* # of packet decrypted failed */
|
||||
};
|
||||
|
||||
/* Bus independent dongle command */
|
||||
struct brcmf_dcmd {
|
||||
uint cmd; /* common dongle cmd definition */
|
||||
|
@ -585,7 +614,7 @@ struct brcmf_pub {
|
|||
/* Linkage ponters */
|
||||
struct brcmf_bus *bus_if;
|
||||
struct brcmf_proto *prot;
|
||||
struct brcmf_cfg80211_dev *config;
|
||||
struct brcmf_cfg80211_info *config;
|
||||
struct device *dev; /* fullmac dongle device pointer */
|
||||
|
||||
/* Internal brcmf items */
|
||||
|
@ -658,6 +687,8 @@ extern const struct bcmevent_name bcmevent_names[];
|
|||
|
||||
extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
|
||||
char *buf, uint len);
|
||||
extern uint brcmf_c_mkiovar_bsscfg(char *name, char *data, uint datalen,
|
||||
char *buf, uint buflen, s32 bssidx);
|
||||
|
||||
extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
|
||||
|
||||
|
|
|
@ -88,6 +88,52 @@ brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
|
|||
return len;
|
||||
}
|
||||
|
||||
uint
|
||||
brcmf_c_mkiovar_bsscfg(char *name, char *data, uint datalen,
|
||||
char *buf, uint buflen, s32 bssidx)
|
||||
{
|
||||
const s8 *prefix = "bsscfg:";
|
||||
s8 *p;
|
||||
u32 prefixlen;
|
||||
u32 namelen;
|
||||
u32 iolen;
|
||||
__le32 bssidx_le;
|
||||
|
||||
if (bssidx == 0)
|
||||
return brcmf_c_mkiovar(name, data, datalen, buf, buflen);
|
||||
|
||||
prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */
|
||||
namelen = (u32) strlen(name) + 1; /* lengh of iovar name + null */
|
||||
iolen = prefixlen + namelen + sizeof(bssidx_le) + datalen;
|
||||
|
||||
if (buflen < 0 || iolen > (u32)buflen) {
|
||||
brcmf_dbg(ERROR, "buffer is too short\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
/* copy prefix, no null */
|
||||
memcpy(p, prefix, prefixlen);
|
||||
p += prefixlen;
|
||||
|
||||
/* copy iovar name including null */
|
||||
memcpy(p, name, namelen);
|
||||
p += namelen;
|
||||
|
||||
/* bss config index as first data */
|
||||
bssidx_le = cpu_to_le32(bssidx);
|
||||
memcpy(p, &bssidx_le, sizeof(bssidx_le));
|
||||
p += sizeof(bssidx_le);
|
||||
|
||||
/* parameter buffer follows */
|
||||
if (datalen)
|
||||
memcpy(p, data, datalen);
|
||||
|
||||
return iolen;
|
||||
|
||||
}
|
||||
|
||||
bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
|
||||
struct sk_buff *pkt, int prec)
|
||||
{
|
||||
|
|
|
@ -160,40 +160,17 @@ static struct brcmf_usbdev_info *brcmf_usb_get_businfo(struct device *dev)
|
|||
return brcmf_usb_get_buspub(dev)->devinfo;
|
||||
}
|
||||
|
||||
static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo,
|
||||
uint *condition, bool *pending)
|
||||
static int brcmf_usb_ioctl_resp_wait(struct brcmf_usbdev_info *devinfo)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int timeout = IOCTL_RESP_TIMEOUT;
|
||||
|
||||
/* Convert timeout in millsecond to jiffies */
|
||||
timeout = msecs_to_jiffies(timeout);
|
||||
/* Wait until control frame is available */
|
||||
add_wait_queue(&devinfo->ioctl_resp_wait, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
smp_mb();
|
||||
while (!(*condition) && (!signal_pending(current) && timeout)) {
|
||||
timeout = schedule_timeout(timeout);
|
||||
/* Wait until control frame is available */
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
if (signal_pending(current))
|
||||
*pending = true;
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&devinfo->ioctl_resp_wait, &wait);
|
||||
|
||||
return timeout;
|
||||
return wait_event_timeout(devinfo->ioctl_resp_wait,
|
||||
devinfo->ctl_completed,
|
||||
msecs_to_jiffies(IOCTL_RESP_TIMEOUT));
|
||||
}
|
||||
|
||||
static int brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)
|
||||
static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)
|
||||
{
|
||||
if (waitqueue_active(&devinfo->ioctl_resp_wait))
|
||||
wake_up_interruptible(&devinfo->ioctl_resp_wait);
|
||||
|
||||
return 0;
|
||||
wake_up(&devinfo->ioctl_resp_wait);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -322,7 +299,6 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
|
|||
{
|
||||
int err = 0;
|
||||
int timeout = 0;
|
||||
bool pending;
|
||||
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
|
||||
|
||||
if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
|
||||
|
@ -340,9 +316,7 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
|
|||
clear_bit(0, &devinfo->ctl_op);
|
||||
return err;
|
||||
}
|
||||
|
||||
timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed,
|
||||
&pending);
|
||||
timeout = brcmf_usb_ioctl_resp_wait(devinfo);
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
if (!timeout) {
|
||||
brcmf_dbg(ERROR, "Txctl wait timed out\n");
|
||||
|
@ -355,7 +329,6 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
|
|||
{
|
||||
int err = 0;
|
||||
int timeout = 0;
|
||||
bool pending;
|
||||
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
|
||||
|
||||
if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
|
||||
|
@ -365,15 +338,14 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
|
|||
if (test_and_set_bit(0, &devinfo->ctl_op))
|
||||
return -EIO;
|
||||
|
||||
devinfo->ctl_completed = false;
|
||||
err = brcmf_usb_recv_ctl(devinfo, buf, len);
|
||||
if (err) {
|
||||
brcmf_dbg(ERROR, "fail %d bytes: %d\n", err, len);
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
return err;
|
||||
}
|
||||
devinfo->ctl_completed = false;
|
||||
timeout = brcmf_usb_ioctl_resp_wait(devinfo, &devinfo->ctl_completed,
|
||||
&pending);
|
||||
timeout = brcmf_usb_ioctl_resp_wait(devinfo);
|
||||
err = devinfo->ctl_urb_status;
|
||||
clear_bit(0, &devinfo->ctl_op);
|
||||
if (!timeout) {
|
||||
|
@ -493,6 +465,8 @@ static void brcmf_usb_tx_complete(struct urb *urb)
|
|||
else
|
||||
devinfo->bus_pub.bus->dstats.tx_errors++;
|
||||
|
||||
brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
|
||||
|
||||
brcmu_pkt_buf_free_skb(req->skb);
|
||||
req->skb = NULL;
|
||||
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,12 +17,6 @@
|
|||
#ifndef _wl_cfg80211_h_
|
||||
#define _wl_cfg80211_h_
|
||||
|
||||
struct brcmf_cfg80211_conf;
|
||||
struct brcmf_cfg80211_iface;
|
||||
struct brcmf_cfg80211_priv;
|
||||
struct brcmf_cfg80211_security;
|
||||
struct brcmf_cfg80211_ibss;
|
||||
|
||||
#define WL_DBG_NONE 0
|
||||
#define WL_DBG_CONN (1 << 5)
|
||||
#define WL_DBG_SCAN (1 << 4)
|
||||
|
@ -130,13 +124,18 @@ do { \
|
|||
#define WL_ESCAN_ACTION_CONTINUE 2
|
||||
#define WL_ESCAN_ACTION_ABORT 3
|
||||
|
||||
#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */
|
||||
#define IE_MAX_LEN 512
|
||||
|
||||
/* dongle status */
|
||||
enum wl_status {
|
||||
WL_STATUS_READY,
|
||||
WL_STATUS_SCANNING,
|
||||
WL_STATUS_SCAN_ABORTING,
|
||||
WL_STATUS_CONNECTING,
|
||||
WL_STATUS_CONNECTED
|
||||
WL_STATUS_CONNECTED,
|
||||
WL_STATUS_AP_CREATING,
|
||||
WL_STATUS_AP_CREATED
|
||||
};
|
||||
|
||||
/* wi-fi mode */
|
||||
|
@ -176,23 +175,17 @@ struct brcmf_cfg80211_conf {
|
|||
struct ieee80211_channel channel;
|
||||
};
|
||||
|
||||
/* forward declaration */
|
||||
struct brcmf_cfg80211_info;
|
||||
|
||||
/* cfg80211 main event loop */
|
||||
struct brcmf_cfg80211_event_loop {
|
||||
s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_priv *cfg_priv,
|
||||
s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_info *cfg,
|
||||
struct net_device *ndev,
|
||||
const struct brcmf_event_msg *e,
|
||||
void *data);
|
||||
};
|
||||
|
||||
/* representing interface of cfg80211 plane */
|
||||
struct brcmf_cfg80211_iface {
|
||||
struct brcmf_cfg80211_priv *cfg_priv;
|
||||
};
|
||||
|
||||
struct brcmf_cfg80211_dev {
|
||||
void *driver_data; /* to store cfg80211 object information */
|
||||
};
|
||||
|
||||
/* basic structure of scan request */
|
||||
struct brcmf_cfg80211_scan_req {
|
||||
struct brcmf_ssid_le ssid_le;
|
||||
|
@ -245,7 +238,7 @@ struct brcmf_cfg80211_profile {
|
|||
/* dongle iscan event loop */
|
||||
struct brcmf_cfg80211_iscan_eloop {
|
||||
s32 (*handler[WL_SCAN_ERSULTS_LAST])
|
||||
(struct brcmf_cfg80211_priv *cfg_priv);
|
||||
(struct brcmf_cfg80211_info *cfg);
|
||||
};
|
||||
|
||||
/* dongle iscan controller */
|
||||
|
@ -295,6 +288,17 @@ struct escan_info {
|
|||
struct net_device *ndev;
|
||||
};
|
||||
|
||||
/* Structure to hold WPS, WPA IEs for a AP */
|
||||
struct ap_info {
|
||||
u8 probe_res_ie[IE_MAX_LEN];
|
||||
u8 beacon_ie[IE_MAX_LEN];
|
||||
u32 probe_res_ie_len;
|
||||
u32 beacon_ie_len;
|
||||
u8 *wpa_ie;
|
||||
u8 *rsn_ie;
|
||||
bool security_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_pno_param_le - PNO scan configuration parameters
|
||||
*
|
||||
|
@ -377,7 +381,7 @@ struct brcmf_pno_scanresults_le {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_cfg80211_priv - dongle private data of cfg80211 interface
|
||||
* struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
|
||||
*
|
||||
* @wdev: representing wl cfg80211 device.
|
||||
* @conf: dongle configuration.
|
||||
|
@ -417,9 +421,10 @@ struct brcmf_pno_scanresults_le {
|
|||
* @escan_timeout: Timer for catch scan timeout.
|
||||
* @escan_timeout_work: scan timeout worker.
|
||||
* @escan_ioctl_buf: dongle command buffer for escan commands.
|
||||
* @ap_info: host ap information.
|
||||
* @ci: used to link this structure to netdev private data.
|
||||
*/
|
||||
struct brcmf_cfg80211_priv {
|
||||
struct brcmf_cfg80211_info {
|
||||
struct wireless_dev *wdev;
|
||||
struct brcmf_cfg80211_conf *conf;
|
||||
struct cfg80211_scan_request *scan_request;
|
||||
|
@ -458,52 +463,52 @@ struct brcmf_cfg80211_priv {
|
|||
struct timer_list escan_timeout;
|
||||
struct work_struct escan_timeout_work;
|
||||
u8 *escan_ioctl_buf;
|
||||
u8 ci[0] __aligned(NETDEV_ALIGN);
|
||||
struct ap_info *ap_info;
|
||||
};
|
||||
|
||||
static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_priv *w)
|
||||
static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *w)
|
||||
{
|
||||
return w->wdev->wiphy;
|
||||
}
|
||||
|
||||
static inline struct brcmf_cfg80211_priv *wiphy_to_cfg(struct wiphy *w)
|
||||
static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w)
|
||||
{
|
||||
return (struct brcmf_cfg80211_priv *)(wiphy_priv(w));
|
||||
return (struct brcmf_cfg80211_info *)(wiphy_priv(w));
|
||||
}
|
||||
|
||||
static inline struct brcmf_cfg80211_priv *wdev_to_cfg(struct wireless_dev *wd)
|
||||
static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd)
|
||||
{
|
||||
return (struct brcmf_cfg80211_priv *)(wdev_priv(wd));
|
||||
return (struct brcmf_cfg80211_info *)(wdev_priv(wd));
|
||||
}
|
||||
|
||||
static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_priv *cfg)
|
||||
static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg)
|
||||
{
|
||||
return cfg->wdev->netdev;
|
||||
}
|
||||
|
||||
static inline struct brcmf_cfg80211_priv *ndev_to_cfg(struct net_device *ndev)
|
||||
static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev)
|
||||
{
|
||||
return wdev_to_cfg(ndev->ieee80211_ptr);
|
||||
}
|
||||
|
||||
#define iscan_to_cfg(i) ((struct brcmf_cfg80211_priv *)(i->data))
|
||||
#define iscan_to_cfg(i) ((struct brcmf_cfg80211_info *)(i->data))
|
||||
#define cfg_to_iscan(w) (w->iscan)
|
||||
|
||||
static inline struct
|
||||
brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg)
|
||||
brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
|
||||
{
|
||||
return &cfg->conn_info;
|
||||
}
|
||||
|
||||
extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
|
||||
struct device *busdev,
|
||||
struct brcmf_pub *drvr);
|
||||
extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg);
|
||||
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct net_device *ndev,
|
||||
struct device *busdev,
|
||||
struct brcmf_pub *drvr);
|
||||
void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
|
||||
|
||||
/* event handler from dongle */
|
||||
extern void brcmf_cfg80211_event(struct net_device *ndev,
|
||||
const struct brcmf_event_msg *e, void *data);
|
||||
extern s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev);
|
||||
extern s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev);
|
||||
void brcmf_cfg80211_event(struct net_device *ndev,
|
||||
const struct brcmf_event_msg *e, void *data);
|
||||
s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg);
|
||||
s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg);
|
||||
|
||||
#endif /* _wl_cfg80211_h_ */
|
||||
|
|
|
@ -302,6 +302,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
|
|||
new_node->start_win = last_seq + 1;
|
||||
|
||||
new_node->win_size = win_size;
|
||||
new_node->flags = 0;
|
||||
|
||||
new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
|
||||
GFP_KERNEL);
|
||||
|
@ -457,13 +458,20 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
|
|||
* If seq_num is less then starting win then ignore and drop the
|
||||
* packet
|
||||
*/
|
||||
if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */
|
||||
if (seq_num >= ((start_win + TWOPOW11) &
|
||||
(MAX_TID_VALUE - 1)) && (seq_num < start_win))
|
||||
if (tbl->flags & RXREOR_FORCE_NO_DROP) {
|
||||
dev_dbg(priv->adapter->dev,
|
||||
"RXREOR_FORCE_NO_DROP when HS is activated\n");
|
||||
tbl->flags &= ~RXREOR_FORCE_NO_DROP;
|
||||
} else {
|
||||
if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
|
||||
if (seq_num >= ((start_win + TWOPOW11) &
|
||||
(MAX_TID_VALUE - 1)) &&
|
||||
seq_num < start_win)
|
||||
return -1;
|
||||
} else if ((seq_num < start_win) ||
|
||||
(seq_num > (start_win + TWOPOW11))) {
|
||||
return -1;
|
||||
} else if ((seq_num < start_win) ||
|
||||
(seq_num > (start_win + TWOPOW11))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -474,8 +482,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
|
|||
seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
|
||||
|
||||
if (((end_win < start_win) &&
|
||||
(seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) &&
|
||||
(seq_num > end_win)) ||
|
||||
(seq_num < start_win) && (seq_num > end_win)) ||
|
||||
((end_win > start_win) && ((seq_num > end_win) ||
|
||||
(seq_num < start_win)))) {
|
||||
end_win = seq_num;
|
||||
|
@ -637,3 +644,29 @@ void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
|
|||
INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
|
||||
mwifiex_reset_11n_rx_seq_num(priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function updates all rx_reorder_tbl's flags.
|
||||
*/
|
||||
void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags)
|
||||
{
|
||||
struct mwifiex_private *priv;
|
||||
struct mwifiex_rx_reorder_tbl *tbl;
|
||||
unsigned long lock_flags;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adapter->priv_num; i++) {
|
||||
priv = adapter->priv[i];
|
||||
if (!priv)
|
||||
continue;
|
||||
if (list_empty(&priv->rx_reorder_tbl_ptr))
|
||||
continue;
|
||||
|
||||
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, lock_flags);
|
||||
list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list)
|
||||
tbl->flags = flags;
|
||||
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, lock_flags);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
#define BA_SETUP_MAX_PACKET_THRESHOLD 16
|
||||
#define BA_SETUP_PACKET_OFFSET 16
|
||||
|
||||
enum mwifiex_rxreor_flags {
|
||||
RXREOR_FORCE_NO_DROP = 1<<0,
|
||||
};
|
||||
|
||||
static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
|
||||
{
|
||||
memset(priv->rx_seq, 0xff, sizeof(priv->rx_seq));
|
||||
|
@ -73,5 +77,6 @@ struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
|
|||
struct mwifiex_rx_reorder_tbl *
|
||||
mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta);
|
||||
void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta);
|
||||
void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags);
|
||||
|
||||
#endif /* _MWIFIEX_11N_RXREORDER_H_ */
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = {
|
||||
{
|
||||
.max = 1, .types = BIT(NL80211_IFTYPE_STATION),
|
||||
.max = 2, .types = BIT(NL80211_IFTYPE_STATION),
|
||||
},
|
||||
{
|
||||
.max = 1, .types = BIT(NL80211_IFTYPE_AP),
|
||||
|
@ -77,8 +77,7 @@ static const struct ieee80211_regdomain mwifiex_world_regdom_custom = {
|
|||
* NL80211_CHAN_HT40MINUS -> IEEE80211_HT_PARAM_CHA_SEC_BELOW
|
||||
* Others -> IEEE80211_HT_PARAM_CHA_SEC_NONE
|
||||
*/
|
||||
static u8
|
||||
mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type)
|
||||
u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type)
|
||||
{
|
||||
switch (chan_type) {
|
||||
case NL80211_CHAN_NO_HT:
|
||||
|
@ -138,6 +137,188 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function forms an skb for management frame.
|
||||
*/
|
||||
static int
|
||||
mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
|
||||
{
|
||||
u8 addr[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
u16 pkt_len;
|
||||
u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT;
|
||||
struct timeval tv;
|
||||
|
||||
pkt_len = len + ETH_ALEN;
|
||||
|
||||
skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN +
|
||||
MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
|
||||
memcpy(skb_push(skb, sizeof(pkt_len)), &pkt_len, sizeof(pkt_len));
|
||||
|
||||
memcpy(skb_push(skb, sizeof(tx_control)),
|
||||
&tx_control, sizeof(tx_control));
|
||||
|
||||
memcpy(skb_push(skb, sizeof(pkt_type)), &pkt_type, sizeof(pkt_type));
|
||||
|
||||
/* Add packet data and address4 */
|
||||
memcpy(skb_put(skb, sizeof(struct ieee80211_hdr_3addr)), buf,
|
||||
sizeof(struct ieee80211_hdr_3addr));
|
||||
memcpy(skb_put(skb, ETH_ALEN), addr, ETH_ALEN);
|
||||
memcpy(skb_put(skb, len - sizeof(struct ieee80211_hdr_3addr)),
|
||||
buf + sizeof(struct ieee80211_hdr_3addr),
|
||||
len - sizeof(struct ieee80211_hdr_3addr));
|
||||
|
||||
skb->priority = LOW_PRIO_TID;
|
||||
do_gettimeofday(&tv);
|
||||
skb->tstamp = timeval_to_ktime(tv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CFG802.11 operation handler to transmit a management frame.
|
||||
*/
|
||||
static int
|
||||
mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan, bool offchan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
bool channel_type_valid, unsigned int wait,
|
||||
const u8 *buf, size_t len, bool no_cck,
|
||||
bool dont_wait_for_ack, u64 *cookie)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u16 pkt_len;
|
||||
const struct ieee80211_mgmt *mgmt;
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
|
||||
|
||||
if (!buf || !len) {
|
||||
wiphy_err(wiphy, "invalid buffer and length\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
mgmt = (const struct ieee80211_mgmt *)buf;
|
||||
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA &&
|
||||
ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
/* Since we support offload probe resp, we need to skip probe
|
||||
* resp in AP or GO mode */
|
||||
wiphy_dbg(wiphy,
|
||||
"info: skip to send probe resp in AP or GO mode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pkt_len = len + ETH_ALEN;
|
||||
skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN +
|
||||
MWIFIEX_MGMT_FRAME_HEADER_SIZE +
|
||||
pkt_len + sizeof(pkt_len));
|
||||
|
||||
if (!skb) {
|
||||
wiphy_err(wiphy, "allocate skb failed for management frame\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mwifiex_form_mgmt_frame(skb, buf, len);
|
||||
mwifiex_queue_tx_pkt(priv, skb);
|
||||
|
||||
*cookie = random32() | 1;
|
||||
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, GFP_ATOMIC);
|
||||
|
||||
wiphy_dbg(wiphy, "info: management frame transmitted\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CFG802.11 operation handler to register a mgmt frame.
|
||||
*/
|
||||
static void
|
||||
mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
|
||||
|
||||
if (reg)
|
||||
priv->mgmt_frame_mask |= BIT(frame_type >> 4);
|
||||
else
|
||||
priv->mgmt_frame_mask &= ~BIT(frame_type >> 4);
|
||||
|
||||
mwifiex_send_cmd_async(priv, HostCmd_CMD_MGMT_FRAME_REG,
|
||||
HostCmd_ACT_GEN_SET, 0, &priv->mgmt_frame_mask);
|
||||
|
||||
wiphy_dbg(wiphy, "info: mgmt frame registered\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* CFG802.11 operation handler to remain on channel.
|
||||
*/
|
||||
static int
|
||||
mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration, u64 *cookie)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
|
||||
int ret;
|
||||
|
||||
if (!chan || !cookie) {
|
||||
wiphy_err(wiphy, "Invalid parameter for ROC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (priv->roc_cfg.cookie) {
|
||||
wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llu\n",
|
||||
priv->roc_cfg.cookie);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET, chan,
|
||||
&channel_type, duration);
|
||||
|
||||
if (!ret) {
|
||||
*cookie = random32() | 1;
|
||||
priv->roc_cfg.cookie = *cookie;
|
||||
priv->roc_cfg.chan = *chan;
|
||||
priv->roc_cfg.chan_type = channel_type;
|
||||
|
||||
cfg80211_ready_on_channel(wdev, *cookie, chan, channel_type,
|
||||
duration, GFP_ATOMIC);
|
||||
|
||||
wiphy_dbg(wiphy, "info: ROC, cookie = 0x%llx\n", *cookie);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* CFG802.11 operation handler to cancel remain on channel.
|
||||
*/
|
||||
static int
|
||||
mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev, u64 cookie)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
|
||||
int ret;
|
||||
|
||||
if (cookie != priv->roc_cfg.cookie)
|
||||
return -ENOENT;
|
||||
|
||||
ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_REMOVE,
|
||||
&priv->roc_cfg.chan,
|
||||
&priv->roc_cfg.chan_type, 0);
|
||||
|
||||
if (!ret) {
|
||||
cfg80211_remain_on_channel_expired(wdev, cookie,
|
||||
&priv->roc_cfg.chan,
|
||||
priv->roc_cfg.chan_type,
|
||||
GFP_ATOMIC);
|
||||
|
||||
memset(&priv->roc_cfg, 0, sizeof(struct mwifiex_roc_cfg));
|
||||
|
||||
wiphy_dbg(wiphy, "info: cancel ROC, cookie = 0x%llx\n", cookie);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* CFG802.11 operation handler to set Tx power.
|
||||
*/
|
||||
|
@ -493,6 +674,76 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv)
|
||||
{
|
||||
u16 mode = P2P_MODE_DISABLE;
|
||||
|
||||
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA)
|
||||
mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA);
|
||||
|
||||
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
|
||||
HostCmd_ACT_GEN_SET, 0, &mode))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initializes the functionalities for P2P client.
|
||||
* The P2P client initialization sequence is:
|
||||
* disable -> device -> client
|
||||
*/
|
||||
static int
|
||||
mwifiex_cfg80211_init_p2p_client(struct mwifiex_private *priv)
|
||||
{
|
||||
u16 mode;
|
||||
|
||||
if (mwifiex_cfg80211_deinit_p2p(priv))
|
||||
return -1;
|
||||
|
||||
mode = P2P_MODE_DEVICE;
|
||||
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
|
||||
HostCmd_ACT_GEN_SET, 0, &mode))
|
||||
return -1;
|
||||
|
||||
mode = P2P_MODE_CLIENT;
|
||||
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
|
||||
HostCmd_ACT_GEN_SET, 0, &mode))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initializes the functionalities for P2P GO.
|
||||
* The P2P GO initialization sequence is:
|
||||
* disable -> device -> GO
|
||||
*/
|
||||
static int
|
||||
mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv)
|
||||
{
|
||||
u16 mode;
|
||||
|
||||
if (mwifiex_cfg80211_deinit_p2p(priv))
|
||||
return -1;
|
||||
|
||||
mode = P2P_MODE_DEVICE;
|
||||
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
|
||||
HostCmd_ACT_GEN_SET, 0, &mode))
|
||||
return -1;
|
||||
|
||||
mode = P2P_MODE_GO;
|
||||
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG,
|
||||
HostCmd_ACT_GEN_SET, 0, &mode))
|
||||
return -1;
|
||||
|
||||
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
|
||||
mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_UAP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CFG802.11 operation handler to change interface type.
|
||||
*/
|
||||
|
@ -525,6 +776,16 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
|
|||
switch (type) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (mwifiex_cfg80211_init_p2p_client(priv))
|
||||
return -EFAULT;
|
||||
dev->ieee80211_ptr->iftype = type;
|
||||
return 0;
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
if (mwifiex_cfg80211_init_p2p_go(priv))
|
||||
return -EFAULT;
|
||||
dev->ieee80211_ptr->iftype = type;
|
||||
return 0;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name);
|
||||
case NL80211_IFTYPE_STATION: /* This shouldn't happen */
|
||||
|
@ -550,6 +811,18 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (mwifiex_cfg80211_deinit_p2p(priv))
|
||||
return -EFAULT;
|
||||
dev->ieee80211_ptr->iftype = type;
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wiphy_err(wiphy, "%s: unknown iftype: %d\n",
|
||||
dev->name, dev->ieee80211_ptr->iftype);
|
||||
|
@ -688,7 +961,6 @@ mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
|
|||
}
|
||||
|
||||
/* Supported rates to be advertised to the cfg80211 */
|
||||
|
||||
static struct ieee80211_rate mwifiex_rates[] = {
|
||||
{.bitrate = 10, .hw_value = 2, },
|
||||
{.bitrate = 20, .hw_value = 4, },
|
||||
|
@ -705,7 +977,6 @@ static struct ieee80211_rate mwifiex_rates[] = {
|
|||
};
|
||||
|
||||
/* Channel definitions to be advertised to cfg80211 */
|
||||
|
||||
static struct ieee80211_channel mwifiex_channels_2ghz[] = {
|
||||
{.center_freq = 2412, .hw_value = 1, },
|
||||
{.center_freq = 2417, .hw_value = 2, },
|
||||
|
@ -773,7 +1044,6 @@ static struct ieee80211_supported_band mwifiex_band_5ghz = {
|
|||
|
||||
|
||||
/* Supported crypto cipher suits to be advertised to cfg80211 */
|
||||
|
||||
static const u32 mwifiex_cipher_suites[] = {
|
||||
WLAN_CIPHER_SUITE_WEP40,
|
||||
WLAN_CIPHER_SUITE_WEP104,
|
||||
|
@ -782,6 +1052,35 @@ static const u32 mwifiex_cipher_suites[] = {
|
|||
WLAN_CIPHER_SUITE_AES_CMAC,
|
||||
};
|
||||
|
||||
/* Supported mgmt frame types to be advertised to cfg80211 */
|
||||
static const struct ieee80211_txrx_stypes
|
||||
mwifiex_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
[NL80211_IFTYPE_STATION] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
|
||||
},
|
||||
[NL80211_IFTYPE_AP] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
|
||||
},
|
||||
[NL80211_IFTYPE_P2P_CLIENT] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
|
||||
},
|
||||
[NL80211_IFTYPE_P2P_GO] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* CFG802.11 operation handler for setting bit rates.
|
||||
*
|
||||
|
@ -874,7 +1173,7 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
|
|||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
|
||||
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
|
||||
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) {
|
||||
wiphy_err(wiphy, "%s: bss_type mismatched\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -962,7 +1261,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
u8 config_bands = 0;
|
||||
|
||||
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP)
|
||||
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
|
||||
return -1;
|
||||
if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon))
|
||||
return -1;
|
||||
|
@ -1032,6 +1331,12 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
|
|||
|
||||
mwifiex_set_ht_params(priv, bss_cfg, params);
|
||||
|
||||
if (params->inactivity_timeout > 0) {
|
||||
/* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */
|
||||
bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout;
|
||||
bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout;
|
||||
}
|
||||
|
||||
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
|
||||
HostCmd_ACT_GEN_SET, 0, NULL)) {
|
||||
wiphy_err(wiphy, "Failed to stop the BSS\n");
|
||||
|
@ -1497,8 +1802,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
|
|||
{
|
||||
struct net_device *dev = request->wdev->netdev;
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
int i;
|
||||
int i, offset;
|
||||
struct ieee80211_channel *chan;
|
||||
struct ieee_types_header *ie;
|
||||
|
||||
wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
|
||||
|
||||
|
@ -1521,13 +1827,17 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
|
|||
priv->user_scan_cfg->ssid_list = request->ssids;
|
||||
|
||||
if (request->ie && request->ie_len) {
|
||||
offset = 0;
|
||||
for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
|
||||
if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR)
|
||||
continue;
|
||||
priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_SCAN;
|
||||
memcpy(&priv->vs_ie[i].ie, request->ie,
|
||||
request->ie_len);
|
||||
break;
|
||||
ie = (struct ieee_types_header *)(request->ie + offset);
|
||||
memcpy(&priv->vs_ie[i].ie, ie, sizeof(*ie) + ie->len);
|
||||
offset += sizeof(*ie) + ie->len;
|
||||
|
||||
if (offset >= request->ie_len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1705,6 +2015,41 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
|||
priv->bss_num = 0;
|
||||
priv->bss_mode = type;
|
||||
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
priv = adapter->priv[MWIFIEX_BSS_TYPE_P2P];
|
||||
|
||||
if (priv->bss_mode) {
|
||||
wiphy_err(wiphy, "Can't create multiple P2P ifaces");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
|
||||
if (!wdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
priv->wdev = wdev;
|
||||
wdev->wiphy = wiphy;
|
||||
|
||||
/* At start-up, wpa_supplicant tries to change the interface
|
||||
* to NL80211_IFTYPE_STATION if it is not managed mode.
|
||||
* So, we initialize it to STA mode.
|
||||
*/
|
||||
wdev->iftype = NL80211_IFTYPE_STATION;
|
||||
priv->bss_mode = NL80211_IFTYPE_STATION;
|
||||
|
||||
/* Setting bss_type to P2P tells firmware that this interface
|
||||
* is receiving P2P peers found during find phase and doing
|
||||
* action frame handshake.
|
||||
*/
|
||||
priv->bss_type = MWIFIEX_BSS_TYPE_P2P;
|
||||
|
||||
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
|
||||
priv->bss_priority = MWIFIEX_BSS_ROLE_STA;
|
||||
priv->bss_role = MWIFIEX_BSS_ROLE_STA;
|
||||
priv->bss_started = 0;
|
||||
priv->bss_num = 0;
|
||||
|
||||
break;
|
||||
default:
|
||||
wiphy_err(wiphy, "type not supported\n");
|
||||
|
@ -1813,6 +2158,10 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
|
|||
.leave_ibss = mwifiex_cfg80211_leave_ibss,
|
||||
.add_key = mwifiex_cfg80211_add_key,
|
||||
.del_key = mwifiex_cfg80211_del_key,
|
||||
.mgmt_tx = mwifiex_cfg80211_mgmt_tx,
|
||||
.mgmt_frame_register = mwifiex_cfg80211_mgmt_frame_register,
|
||||
.remain_on_channel = mwifiex_cfg80211_remain_on_channel,
|
||||
.cancel_remain_on_channel = mwifiex_cfg80211_cancel_remain_on_channel,
|
||||
.set_default_key = mwifiex_cfg80211_set_default_key,
|
||||
.set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
|
||||
.set_tx_power = mwifiex_cfg80211_set_tx_power,
|
||||
|
@ -1849,8 +2198,12 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
|||
}
|
||||
wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
|
||||
wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
|
||||
wiphy->mgmt_stypes = mwifiex_mgmt_stypes;
|
||||
wiphy->max_remain_on_channel_duration = 5000;
|
||||
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
|
||||
|
@ -1870,17 +2223,20 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
|||
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
|
||||
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
|
||||
WIPHY_FLAG_CUSTOM_REGULATORY;
|
||||
WIPHY_FLAG_CUSTOM_REGULATORY |
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||
|
||||
wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
|
||||
|
||||
wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2;
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
|
||||
|
||||
wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1;
|
||||
wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1;
|
||||
|
||||
wiphy->features = NL80211_FEATURE_HT_IBSS;
|
||||
wiphy->features = NL80211_FEATURE_HT_IBSS |
|
||||
NL80211_FEATURE_INACTIVITY_TIMER;
|
||||
|
||||
/* Reserve space for mwifiex specific private data for BSS */
|
||||
wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
|
||||
|
|
|
@ -1088,6 +1088,8 @@ mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated)
|
|||
if (activated) {
|
||||
if (priv->adapter->is_hs_configured) {
|
||||
priv->adapter->hs_activated = true;
|
||||
mwifiex_update_rxreor_flags(priv->adapter,
|
||||
RXREOR_FORCE_NO_DROP);
|
||||
dev_dbg(priv->adapter->dev, "event: hs_activated\n");
|
||||
priv->adapter->hs_activate_wait_q_woken = true;
|
||||
wake_up_interruptible(
|
||||
|
|
|
@ -28,11 +28,14 @@
|
|||
#include <linux/ieee80211.h>
|
||||
|
||||
|
||||
#define MWIFIEX_MAX_BSS_NUM (2)
|
||||
#define MWIFIEX_MAX_BSS_NUM (3)
|
||||
|
||||
#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd)
|
||||
* + 4 byte alignment
|
||||
*/
|
||||
#define MWIFIEX_MGMT_FRAME_HEADER_SIZE 8 /* sizeof(pkt_type)
|
||||
* + sizeof(tx_control)
|
||||
*/
|
||||
|
||||
#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2
|
||||
#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16
|
||||
|
@ -67,6 +70,7 @@
|
|||
enum mwifiex_bss_type {
|
||||
MWIFIEX_BSS_TYPE_STA = 0,
|
||||
MWIFIEX_BSS_TYPE_UAP = 1,
|
||||
MWIFIEX_BSS_TYPE_P2P = 2,
|
||||
MWIFIEX_BSS_TYPE_ANY = 0xff,
|
||||
};
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
|
|||
};
|
||||
|
||||
#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF)))
|
||||
#define CAL_RSSI(SNR, NF) ((s16)((s16)(SNR)+(s16)(NF)))
|
||||
|
||||
#define UAP_BSS_PARAMS_I 0
|
||||
#define UAP_CUSTOM_IE_I 1
|
||||
|
@ -127,6 +128,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
|
|||
#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45)
|
||||
#define TLV_TYPE_UAP_BCAST_SSID (PROPRIETARY_TLV_BASE_ID + 48)
|
||||
#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51)
|
||||
#define TLV_TYPE_UAP_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 57)
|
||||
#define TLV_TYPE_UAP_WEP_KEY (PROPRIETARY_TLV_BASE_ID + 59)
|
||||
#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
|
||||
#define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64)
|
||||
|
@ -141,6 +143,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
|
|||
#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 105)
|
||||
#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113)
|
||||
#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114)
|
||||
#define TLV_TYPE_UAP_PS_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 123)
|
||||
#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145)
|
||||
#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146)
|
||||
|
||||
|
@ -260,9 +263,12 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
|
|||
#define HostCmd_CMD_TX_RATE_CFG 0x00d6
|
||||
#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4
|
||||
#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
|
||||
#define HostCmd_CMD_P2P_MODE_CFG 0x00eb
|
||||
#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
|
||||
#define HostCmd_CMD_SET_BSS_MODE 0x00f7
|
||||
#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
|
||||
#define HostCmd_CMD_MGMT_FRAME_REG 0x010c
|
||||
#define HostCmd_CMD_REMAIN_ON_CHAN 0x010d
|
||||
|
||||
#define PROTOCOL_NO_SECURITY 0x01
|
||||
#define PROTOCOL_STATIC_WEP 0x02
|
||||
|
@ -288,9 +294,17 @@ enum ENH_PS_MODES {
|
|||
DIS_AUTO_PS = 0xfe,
|
||||
};
|
||||
|
||||
enum P2P_MODES {
|
||||
P2P_MODE_DISABLE = 0,
|
||||
P2P_MODE_DEVICE = 1,
|
||||
P2P_MODE_GO = 2,
|
||||
P2P_MODE_CLIENT = 3,
|
||||
};
|
||||
|
||||
#define HostCmd_RET_BIT 0x8000
|
||||
#define HostCmd_ACT_GEN_GET 0x0000
|
||||
#define HostCmd_ACT_GEN_SET 0x0001
|
||||
#define HostCmd_ACT_GEN_REMOVE 0x0004
|
||||
#define HostCmd_ACT_BITWISE_SET 0x0002
|
||||
#define HostCmd_ACT_BITWISE_CLR 0x0003
|
||||
#define HostCmd_RESULT_OK 0x0000
|
||||
|
@ -388,6 +402,7 @@ enum ENH_PS_MODES {
|
|||
#define EVENT_BW_CHANGE 0x00000048
|
||||
#define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c
|
||||
#define EVENT_HOSTWAKE_STAIE 0x0000004d
|
||||
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
|
||||
|
||||
#define EVENT_ID_MASK 0xffff
|
||||
#define BSS_NUM_MASK 0xf
|
||||
|
@ -1331,11 +1346,35 @@ struct host_cmd_tlv_channel_band {
|
|||
u8 channel;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_tlv_ageout_timer {
|
||||
struct host_cmd_tlv tlv;
|
||||
__le32 sta_ao_timer;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_version_ext {
|
||||
u8 version_str_sel;
|
||||
char version_str[128];
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_mgmt_frame_reg {
|
||||
__le16 action;
|
||||
__le32 mask;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_p2p_mode_cfg {
|
||||
__le16 action;
|
||||
__le16 mode;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_remain_on_chan {
|
||||
__le16 action;
|
||||
u8 status;
|
||||
u8 reserved;
|
||||
u8 band_cfg;
|
||||
u8 channel;
|
||||
__le32 duration;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_802_11_ibss_status {
|
||||
__le16 action;
|
||||
__le16 enable;
|
||||
|
@ -1347,6 +1386,7 @@ struct host_cmd_ds_802_11_ibss_status {
|
|||
|
||||
#define CONNECTION_TYPE_INFRA 0
|
||||
#define CONNECTION_TYPE_ADHOC 1
|
||||
#define CONNECTION_TYPE_AP 2
|
||||
|
||||
struct host_cmd_ds_set_bss_mode {
|
||||
u8 con_type;
|
||||
|
@ -1444,6 +1484,9 @@ struct host_cmd_ds_command {
|
|||
struct host_cmd_ds_wmm_get_status get_wmm_status;
|
||||
struct host_cmd_ds_802_11_key_material key_material;
|
||||
struct host_cmd_ds_version_ext verext;
|
||||
struct host_cmd_ds_mgmt_frame_reg reg_mask;
|
||||
struct host_cmd_ds_remain_on_chan roc_cfg;
|
||||
struct host_cmd_ds_p2p_mode_cfg mode_cfg;
|
||||
struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
|
||||
struct host_cmd_ds_mac_reg_access mac_reg;
|
||||
struct host_cmd_ds_bbp_reg_access bbp_reg;
|
||||
|
|
|
@ -114,9 +114,6 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
|
|||
cpu_to_le16(mask);
|
||||
|
||||
ie->ie_index = cpu_to_le16(index);
|
||||
ie->ie_length = priv->mgmt_ie[index].ie_length;
|
||||
memcpy(&ie->ie_buffer, &priv->mgmt_ie[index].ie_buffer,
|
||||
le16_to_cpu(priv->mgmt_ie[index].ie_length));
|
||||
} else {
|
||||
if (mask != MWIFIEX_DELETE_MASK)
|
||||
return -1;
|
||||
|
@ -214,30 +211,35 @@ mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* This function checks if WPS IE is present in passed buffer and copies it to
|
||||
* mwifiex_ie structure.
|
||||
/* This function checks if the vendor specified IE is present in passed buffer
|
||||
* and copies it to mwifiex_ie structure.
|
||||
* Function takes pointer to struct mwifiex_ie pointer as argument.
|
||||
* If WPS IE is present memory is allocated for mwifiex_ie pointer and filled
|
||||
* in with WPS IE. Caller should take care of freeing this memory.
|
||||
* If the vendor specified IE is present then memory is allocated for
|
||||
* mwifiex_ie pointer and filled in with IE. Caller should take care of freeing
|
||||
* this memory.
|
||||
*/
|
||||
static int mwifiex_update_wps_ie(const u8 *ies, int ies_len,
|
||||
struct mwifiex_ie **ie_ptr, u16 mask)
|
||||
static int mwifiex_update_vs_ie(const u8 *ies, int ies_len,
|
||||
struct mwifiex_ie **ie_ptr, u16 mask,
|
||||
unsigned int oui, u8 oui_type)
|
||||
{
|
||||
struct ieee_types_header *wps_ie;
|
||||
struct mwifiex_ie *ie = NULL;
|
||||
struct ieee_types_header *vs_ie;
|
||||
struct mwifiex_ie *ie = *ie_ptr;
|
||||
const u8 *vendor_ie;
|
||||
|
||||
vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
|
||||
WLAN_OUI_TYPE_MICROSOFT_WPS,
|
||||
ies, ies_len);
|
||||
vendor_ie = cfg80211_find_vendor_ie(oui, oui_type, ies, ies_len);
|
||||
if (vendor_ie) {
|
||||
ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
|
||||
if (!ie)
|
||||
return -ENOMEM;
|
||||
if (!*ie_ptr) {
|
||||
*ie_ptr = kzalloc(sizeof(struct mwifiex_ie),
|
||||
GFP_KERNEL);
|
||||
if (!*ie_ptr)
|
||||
return -ENOMEM;
|
||||
ie = *ie_ptr;
|
||||
}
|
||||
|
||||
wps_ie = (struct ieee_types_header *)vendor_ie;
|
||||
memcpy(ie->ie_buffer, wps_ie, wps_ie->len + 2);
|
||||
ie->ie_length = cpu_to_le16(wps_ie->len + 2);
|
||||
vs_ie = (struct ieee_types_header *)vendor_ie;
|
||||
memcpy(ie->ie_buffer + le16_to_cpu(ie->ie_length),
|
||||
vs_ie, vs_ie->len + 2);
|
||||
le16_add_cpu(&ie->ie_length, vs_ie->len + 2);
|
||||
ie->mgmt_subtype_mask = cpu_to_le16(mask);
|
||||
ie->ie_index = cpu_to_le16(MWIFIEX_AUTO_IDX_MASK);
|
||||
}
|
||||
|
@ -257,20 +259,40 @@ static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private *priv,
|
|||
u16 ar_idx = MWIFIEX_AUTO_IDX_MASK;
|
||||
int ret = 0;
|
||||
|
||||
if (data->beacon_ies && data->beacon_ies_len)
|
||||
mwifiex_update_wps_ie(data->beacon_ies, data->beacon_ies_len,
|
||||
&beacon_ie, MGMT_MASK_BEACON);
|
||||
if (data->beacon_ies && data->beacon_ies_len) {
|
||||
mwifiex_update_vs_ie(data->beacon_ies, data->beacon_ies_len,
|
||||
&beacon_ie, MGMT_MASK_BEACON,
|
||||
WLAN_OUI_MICROSOFT,
|
||||
WLAN_OUI_TYPE_MICROSOFT_WPS);
|
||||
mwifiex_update_vs_ie(data->beacon_ies, data->beacon_ies_len,
|
||||
&beacon_ie, MGMT_MASK_BEACON,
|
||||
WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P);
|
||||
}
|
||||
|
||||
if (data->proberesp_ies && data->proberesp_ies_len)
|
||||
mwifiex_update_wps_ie(data->proberesp_ies,
|
||||
data->proberesp_ies_len, &pr_ie,
|
||||
MGMT_MASK_PROBE_RESP);
|
||||
if (data->proberesp_ies && data->proberesp_ies_len) {
|
||||
mwifiex_update_vs_ie(data->proberesp_ies,
|
||||
data->proberesp_ies_len, &pr_ie,
|
||||
MGMT_MASK_PROBE_RESP, WLAN_OUI_MICROSOFT,
|
||||
WLAN_OUI_TYPE_MICROSOFT_WPS);
|
||||
mwifiex_update_vs_ie(data->proberesp_ies,
|
||||
data->proberesp_ies_len, &pr_ie,
|
||||
MGMT_MASK_PROBE_RESP,
|
||||
WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P);
|
||||
}
|
||||
|
||||
if (data->assocresp_ies && data->assocresp_ies_len)
|
||||
mwifiex_update_wps_ie(data->assocresp_ies,
|
||||
data->assocresp_ies_len, &ar_ie,
|
||||
MGMT_MASK_ASSOC_RESP |
|
||||
MGMT_MASK_REASSOC_RESP);
|
||||
if (data->assocresp_ies && data->assocresp_ies_len) {
|
||||
mwifiex_update_vs_ie(data->assocresp_ies,
|
||||
data->assocresp_ies_len, &ar_ie,
|
||||
MGMT_MASK_ASSOC_RESP |
|
||||
MGMT_MASK_REASSOC_RESP,
|
||||
WLAN_OUI_MICROSOFT,
|
||||
WLAN_OUI_TYPE_MICROSOFT_WPS);
|
||||
mwifiex_update_vs_ie(data->assocresp_ies,
|
||||
data->assocresp_ies_len, &ar_ie,
|
||||
MGMT_MASK_ASSOC_RESP |
|
||||
MGMT_MASK_REASSOC_RESP, WLAN_OUI_WFA,
|
||||
WLAN_OUI_TYPE_WFA_P2P);
|
||||
}
|
||||
|
||||
if (beacon_ie || pr_ie || ar_ie) {
|
||||
ret = mwifiex_update_uap_custom_ie(priv, beacon_ie,
|
||||
|
|
|
@ -144,7 +144,7 @@ static void scan_delay_timer_fn(unsigned long data)
|
|||
* Additionally, it also initializes all the locks and sets up all the
|
||||
* lists.
|
||||
*/
|
||||
static int mwifiex_init_priv(struct mwifiex_private *priv)
|
||||
int mwifiex_init_priv(struct mwifiex_private *priv)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
|
@ -214,6 +214,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
|
|||
priv->wps_ie = NULL;
|
||||
priv->wps_ie_len = 0;
|
||||
priv->ap_11n_enabled = 0;
|
||||
memset(&priv->roc_cfg, 0, sizeof(priv->roc_cfg));
|
||||
|
||||
priv->scan_block = false;
|
||||
|
||||
|
@ -647,6 +648,17 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function frees the private structure, including cleans
|
||||
* up the TX and RX queues and frees the BSS priority tables.
|
||||
*/
|
||||
void mwifiex_free_priv(struct mwifiex_private *priv)
|
||||
{
|
||||
mwifiex_clean_txrx(priv);
|
||||
mwifiex_delete_bss_prio_tbl(priv);
|
||||
mwifiex_free_curr_bcn(priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to shutdown the driver.
|
||||
*
|
||||
|
|
|
@ -105,6 +105,8 @@ struct mwifiex_uap_bss_param {
|
|||
struct wep_key wep_cfg[NUM_WEP_KEYS];
|
||||
struct ieee80211_ht_cap ht_cap;
|
||||
u8 rates[MWIFIEX_SUPPORTED_RATES];
|
||||
u32 sta_ao_timer;
|
||||
u32 ps_sta_ao_timer;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
@ -369,6 +369,13 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
|
|||
dev_err(adapter->dev, "cannot create default AP interface\n");
|
||||
goto err_add_intf;
|
||||
}
|
||||
|
||||
/* Create P2P interface by default */
|
||||
if (!mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d",
|
||||
NL80211_IFTYPE_P2P_CLIENT, NULL, NULL)) {
|
||||
dev_err(adapter->dev, "cannot create default P2P interface\n");
|
||||
goto err_add_intf;
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
|
||||
|
@ -468,6 +475,27 @@ mwifiex_close(struct net_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add buffer into wmm tx queue and queue work to transmit it.
|
||||
*/
|
||||
int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
|
||||
{
|
||||
mwifiex_wmm_add_buf_txqueue(priv, skb);
|
||||
atomic_inc(&priv->adapter->tx_pending);
|
||||
|
||||
if (priv->adapter->scan_delay_cnt)
|
||||
atomic_set(&priv->adapter->is_tx_received, true);
|
||||
|
||||
if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
|
||||
mwifiex_set_trans_start(priv->netdev);
|
||||
mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
|
||||
}
|
||||
|
||||
queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CFG802.11 network device handler for data transmission.
|
||||
*/
|
||||
|
@ -516,18 +544,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
tx_info->bss_type = priv->bss_type;
|
||||
mwifiex_fill_buffer(skb);
|
||||
|
||||
mwifiex_wmm_add_buf_txqueue(priv, skb);
|
||||
atomic_inc(&priv->adapter->tx_pending);
|
||||
|
||||
if (priv->adapter->scan_delay_cnt)
|
||||
atomic_set(&priv->adapter->is_tx_received, true);
|
||||
|
||||
if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
|
||||
mwifiex_set_trans_start(dev);
|
||||
mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
|
||||
}
|
||||
|
||||
queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
|
||||
mwifiex_queue_tx_pkt(priv, skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -98,6 +98,8 @@ enum {
|
|||
#define MWIFIEX_OUI_NOT_PRESENT 0
|
||||
#define MWIFIEX_OUI_PRESENT 1
|
||||
|
||||
#define PKT_TYPE_MGMT 0xE5
|
||||
|
||||
/*
|
||||
* Do not check for data_received for USB, as data_received
|
||||
* is handled in mwifiex_usb_recv for USB
|
||||
|
@ -368,6 +370,12 @@ struct wps {
|
|||
u8 session_enable;
|
||||
};
|
||||
|
||||
struct mwifiex_roc_cfg {
|
||||
u64 cookie;
|
||||
struct ieee80211_channel chan;
|
||||
enum nl80211_channel_type chan_type;
|
||||
};
|
||||
|
||||
struct mwifiex_adapter;
|
||||
struct mwifiex_private;
|
||||
|
||||
|
@ -494,6 +502,8 @@ struct mwifiex_private {
|
|||
u16 rsn_idx;
|
||||
struct timer_list scan_delay_timer;
|
||||
u8 ap_11n_enabled;
|
||||
u32 mgmt_frame_mask;
|
||||
struct mwifiex_roc_cfg roc_cfg;
|
||||
};
|
||||
|
||||
enum mwifiex_ba_status {
|
||||
|
@ -525,6 +535,7 @@ struct mwifiex_rx_reorder_tbl {
|
|||
int win_size;
|
||||
void **rx_reorder_ptr;
|
||||
struct reorder_tmr_cnxt timer_context;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
struct mwifiex_bss_prio_node {
|
||||
|
@ -726,6 +737,9 @@ void mwifiex_stop_net_dev_queue(struct net_device *netdev,
|
|||
void mwifiex_wake_up_net_dev_queue(struct net_device *netdev,
|
||||
struct mwifiex_adapter *adapter);
|
||||
|
||||
int mwifiex_init_priv(struct mwifiex_private *priv);
|
||||
void mwifiex_free_priv(struct mwifiex_private *priv);
|
||||
|
||||
int mwifiex_init_fw(struct mwifiex_adapter *adapter);
|
||||
|
||||
int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter);
|
||||
|
@ -738,6 +752,9 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *);
|
|||
|
||||
int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);
|
||||
|
||||
int mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter,
|
||||
struct sk_buff *skb);
|
||||
|
||||
int mwifiex_process_event(struct mwifiex_adapter *adapter);
|
||||
|
||||
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
|
||||
|
@ -960,6 +977,14 @@ mwifiex_netdev_get_priv(struct net_device *dev)
|
|||
return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks if a skb holds a management frame.
|
||||
*/
|
||||
static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb)
|
||||
{
|
||||
return (*(u32 *)skb->data == PKT_TYPE_MGMT);
|
||||
}
|
||||
|
||||
int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
|
||||
u32 func_init_shutdown);
|
||||
int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
|
||||
|
@ -992,6 +1017,13 @@ int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
|
|||
|
||||
int mwifiex_get_ver_ext(struct mwifiex_private *priv);
|
||||
|
||||
int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type *channel_type,
|
||||
unsigned int duration);
|
||||
|
||||
int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role);
|
||||
|
||||
int mwifiex_get_stats_info(struct mwifiex_private *priv,
|
||||
struct mwifiex_ds_get_stats *log);
|
||||
|
||||
|
@ -1022,6 +1054,8 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
|
|||
|
||||
int mwifiex_main_process(struct mwifiex_adapter *);
|
||||
|
||||
int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb);
|
||||
|
||||
int mwifiex_get_bss_info(struct mwifiex_private *,
|
||||
struct mwifiex_bss_info *);
|
||||
int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
|
||||
|
@ -1032,6 +1066,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
|
|||
int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
|
||||
struct mwifiex_bssdescriptor *bss_desc);
|
||||
|
||||
u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type);
|
||||
|
||||
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
const char *name,
|
||||
enum nl80211_iftype type,
|
||||
|
|
|
@ -614,9 +614,8 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
|
|||
|
||||
/* Increment the TLV header length by the size
|
||||
appended */
|
||||
chan_tlv_out->header.len =
|
||||
cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) +
|
||||
(sizeof(chan_tlv_out->chan_scan_param)));
|
||||
le16_add_cpu(&chan_tlv_out->header.len,
|
||||
sizeof(chan_tlv_out->chan_scan_param));
|
||||
|
||||
/*
|
||||
* The tlv buffer length is set to the number of bytes
|
||||
|
|
|
@ -1167,6 +1167,31 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
|
|||
S_DS_GEN);
|
||||
ret = 0;
|
||||
break;
|
||||
case HostCmd_CMD_MGMT_FRAME_REG:
|
||||
cmd_ptr->command = cpu_to_le16(cmd_no);
|
||||
cmd_ptr->params.reg_mask.action = cpu_to_le16(cmd_action);
|
||||
cmd_ptr->params.reg_mask.mask = cpu_to_le32(*(u32 *)data_buf);
|
||||
cmd_ptr->size =
|
||||
cpu_to_le16(sizeof(struct host_cmd_ds_mgmt_frame_reg) +
|
||||
S_DS_GEN);
|
||||
ret = 0;
|
||||
break;
|
||||
case HostCmd_CMD_REMAIN_ON_CHAN:
|
||||
cmd_ptr->command = cpu_to_le16(cmd_no);
|
||||
memcpy(&cmd_ptr->params, data_buf,
|
||||
sizeof(struct host_cmd_ds_remain_on_chan));
|
||||
cmd_ptr->size =
|
||||
cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) +
|
||||
S_DS_GEN);
|
||||
break;
|
||||
case HostCmd_CMD_P2P_MODE_CFG:
|
||||
cmd_ptr->command = cpu_to_le16(cmd_no);
|
||||
cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action);
|
||||
cmd_ptr->params.mode_cfg.mode = cpu_to_le16(*(u16 *)data_buf);
|
||||
cmd_ptr->size =
|
||||
cpu_to_le16(sizeof(struct host_cmd_ds_p2p_mode_cfg) +
|
||||
S_DS_GEN);
|
||||
break;
|
||||
case HostCmd_CMD_FUNC_INIT:
|
||||
if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET)
|
||||
priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY;
|
||||
|
@ -1236,6 +1261,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
|
|||
else if (priv->bss_mode == NL80211_IFTYPE_STATION)
|
||||
cmd_ptr->params.bss_mode.con_type =
|
||||
CONNECTION_TYPE_INFRA;
|
||||
else if (priv->bss_mode == NL80211_IFTYPE_AP)
|
||||
cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_AP;
|
||||
cmd_ptr->size = cpu_to_le16(sizeof(struct
|
||||
host_cmd_ds_set_bss_mode) + S_DS_GEN);
|
||||
ret = 0;
|
||||
|
@ -1285,35 +1312,35 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
|
|||
|
||||
if (first_sta) {
|
||||
if (priv->adapter->iface_type == MWIFIEX_PCIE) {
|
||||
ret = mwifiex_send_cmd_async(priv,
|
||||
ret = mwifiex_send_cmd_sync(priv,
|
||||
HostCmd_CMD_PCIE_DESC_DETAILS,
|
||||
HostCmd_ACT_GEN_SET, 0, NULL);
|
||||
if (ret)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT,
|
||||
HostCmd_ACT_GEN_SET, 0, NULL);
|
||||
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_FUNC_INIT,
|
||||
HostCmd_ACT_GEN_SET, 0, NULL);
|
||||
if (ret)
|
||||
return -1;
|
||||
/* Read MAC address from HW */
|
||||
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC,
|
||||
HostCmd_ACT_GEN_GET, 0, NULL);
|
||||
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_GET_HW_SPEC,
|
||||
HostCmd_ACT_GEN_GET, 0, NULL);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
/* Reconfigure tx buf size */
|
||||
ret = mwifiex_send_cmd_async(priv,
|
||||
HostCmd_CMD_RECONFIGURE_TX_BUFF,
|
||||
HostCmd_ACT_GEN_SET, 0,
|
||||
&priv->adapter->tx_buf_size);
|
||||
ret = mwifiex_send_cmd_sync(priv,
|
||||
HostCmd_CMD_RECONFIGURE_TX_BUFF,
|
||||
HostCmd_ACT_GEN_SET, 0,
|
||||
&priv->adapter->tx_buf_size);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
|
||||
/* Enable IEEE PS by default */
|
||||
priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
|
||||
ret = mwifiex_send_cmd_async(
|
||||
ret = mwifiex_send_cmd_sync(
|
||||
priv, HostCmd_CMD_802_11_PS_MODE_ENH,
|
||||
EN_AUTO_PS, BITMAP_STA_PS, NULL);
|
||||
if (ret)
|
||||
|
@ -1322,21 +1349,21 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
|
|||
}
|
||||
|
||||
/* get tx rate */
|
||||
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG,
|
||||
HostCmd_ACT_GEN_GET, 0, NULL);
|
||||
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
|
||||
HostCmd_ACT_GEN_GET, 0, NULL);
|
||||
if (ret)
|
||||
return -1;
|
||||
priv->data_rate = 0;
|
||||
|
||||
/* get tx power */
|
||||
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_RF_TX_PWR,
|
||||
HostCmd_ACT_GEN_GET, 0, NULL);
|
||||
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_TX_PWR,
|
||||
HostCmd_ACT_GEN_GET, 0, NULL);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
|
||||
/* set ibss coalescing_status */
|
||||
ret = mwifiex_send_cmd_async(
|
||||
ret = mwifiex_send_cmd_sync(
|
||||
priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
|
||||
HostCmd_ACT_GEN_SET, 0, &enable);
|
||||
if (ret)
|
||||
|
@ -1346,16 +1373,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
|
|||
memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
|
||||
amsdu_aggr_ctrl.enable = true;
|
||||
/* Send request to firmware */
|
||||
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
|
||||
HostCmd_ACT_GEN_SET, 0,
|
||||
&amsdu_aggr_ctrl);
|
||||
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
|
||||
HostCmd_ACT_GEN_SET, 0,
|
||||
&amsdu_aggr_ctrl);
|
||||
if (ret)
|
||||
return -1;
|
||||
/* MAC Control must be the last command in init_fw */
|
||||
/* set MAC Control */
|
||||
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
|
||||
HostCmd_ACT_GEN_SET, 0,
|
||||
&priv->curr_pkt_filter);
|
||||
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
|
||||
HostCmd_ACT_GEN_SET, 0,
|
||||
&priv->curr_pkt_filter);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
|
@ -1364,10 +1391,10 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
|
|||
/* Enable auto deep sleep */
|
||||
auto_ds.auto_ds = DEEP_SLEEP_ON;
|
||||
auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
|
||||
ret = mwifiex_send_cmd_async(priv,
|
||||
HostCmd_CMD_802_11_PS_MODE_ENH,
|
||||
EN_AUTO_PS, BITMAP_AUTO_DS,
|
||||
&auto_ds);
|
||||
ret = mwifiex_send_cmd_sync(priv,
|
||||
HostCmd_CMD_802_11_PS_MODE_ENH,
|
||||
EN_AUTO_PS, BITMAP_AUTO_DS,
|
||||
&auto_ds);
|
||||
if (ret)
|
||||
return -1;
|
||||
}
|
||||
|
@ -1375,23 +1402,24 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
|
|||
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
|
||||
/* Send cmd to FW to enable/disable 11D function */
|
||||
state_11d = ENABLE_11D;
|
||||
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
|
||||
HostCmd_ACT_GEN_SET, DOT11D_I,
|
||||
&state_11d);
|
||||
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
|
||||
HostCmd_ACT_GEN_SET, DOT11D_I,
|
||||
&state_11d);
|
||||
if (ret)
|
||||
dev_err(priv->adapter->dev,
|
||||
"11D: failed to enable 11D\n");
|
||||
}
|
||||
|
||||
/* set last_init_cmd before sending the command */
|
||||
priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG;
|
||||
|
||||
/* Send cmd to FW to configure 11n specific configuration
|
||||
* (Short GI, Channel BW, Green field support etc.) for transmit
|
||||
*/
|
||||
tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG;
|
||||
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_CFG,
|
||||
HostCmd_ACT_GEN_SET, 0, &tx_cfg);
|
||||
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_11N_CFG,
|
||||
HostCmd_ACT_GEN_SET, 0, &tx_cfg);
|
||||
|
||||
/* set last_init_cmd */
|
||||
priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG;
|
||||
ret = -EINPROGRESS;
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -653,6 +653,38 @@ static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the command response of remain on channel.
|
||||
*/
|
||||
static int
|
||||
mwifiex_ret_remain_on_chan(struct mwifiex_private *priv,
|
||||
struct host_cmd_ds_command *resp,
|
||||
struct host_cmd_ds_remain_on_chan *roc_cfg)
|
||||
{
|
||||
struct host_cmd_ds_remain_on_chan *resp_cfg = &resp->params.roc_cfg;
|
||||
|
||||
if (roc_cfg)
|
||||
memcpy(roc_cfg, resp_cfg, sizeof(*roc_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the command response of P2P mode cfg.
|
||||
*/
|
||||
static int
|
||||
mwifiex_ret_p2p_mode_cfg(struct mwifiex_private *priv,
|
||||
struct host_cmd_ds_command *resp,
|
||||
void *data_buf)
|
||||
{
|
||||
struct host_cmd_ds_p2p_mode_cfg *mode_cfg = &resp->params.mode_cfg;
|
||||
|
||||
if (data_buf)
|
||||
*((u16 *)data_buf) = le16_to_cpu(mode_cfg->mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the command response of register access.
|
||||
*
|
||||
|
@ -875,6 +907,13 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
|
|||
case HostCmd_CMD_VERSION_EXT:
|
||||
ret = mwifiex_ret_ver_ext(priv, resp, data_buf);
|
||||
break;
|
||||
case HostCmd_CMD_REMAIN_ON_CHAN:
|
||||
ret = mwifiex_ret_remain_on_chan(priv, resp, data_buf);
|
||||
break;
|
||||
case HostCmd_CMD_P2P_MODE_CFG:
|
||||
ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf);
|
||||
break;
|
||||
case HostCmd_CMD_MGMT_FRAME_REG:
|
||||
case HostCmd_CMD_FUNC_INIT:
|
||||
case HostCmd_CMD_FUNC_SHUTDOWN:
|
||||
break;
|
||||
|
|
|
@ -410,6 +410,18 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
|
|||
dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
|
||||
break;
|
||||
|
||||
case EVENT_REMAIN_ON_CHAN_EXPIRED:
|
||||
dev_dbg(adapter->dev, "event: Remain on channel expired\n");
|
||||
cfg80211_remain_on_channel_expired(priv->wdev,
|
||||
priv->roc_cfg.cookie,
|
||||
&priv->roc_cfg.chan,
|
||||
priv->roc_cfg.chan_type,
|
||||
GFP_ATOMIC);
|
||||
|
||||
memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
|
||||
eventcause);
|
||||
|
|
|
@ -1043,6 +1043,65 @@ mwifiex_get_ver_ext(struct mwifiex_private *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type *ct,
|
||||
unsigned int duration)
|
||||
{
|
||||
struct host_cmd_ds_remain_on_chan roc_cfg;
|
||||
u8 sc;
|
||||
|
||||
memset(&roc_cfg, 0, sizeof(roc_cfg));
|
||||
roc_cfg.action = cpu_to_le16(action);
|
||||
if (action == HostCmd_ACT_GEN_SET) {
|
||||
roc_cfg.band_cfg = chan->band;
|
||||
sc = mwifiex_chan_type_to_sec_chan_offset(*ct);
|
||||
roc_cfg.band_cfg |= (sc << 2);
|
||||
|
||||
roc_cfg.channel =
|
||||
ieee80211_frequency_to_channel(chan->center_freq);
|
||||
roc_cfg.duration = cpu_to_le32(duration);
|
||||
}
|
||||
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_REMAIN_ON_CHAN,
|
||||
action, 0, &roc_cfg)) {
|
||||
dev_err(priv->adapter->dev, "failed to remain on channel\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return roc_cfg.status;
|
||||
}
|
||||
|
||||
int
|
||||
mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role)
|
||||
{
|
||||
if (GET_BSS_ROLE(priv) == bss_role) {
|
||||
dev_dbg(priv->adapter->dev,
|
||||
"info: already in the desired role.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mwifiex_free_priv(priv);
|
||||
mwifiex_init_priv(priv);
|
||||
|
||||
priv->bss_role = bss_role;
|
||||
switch (bss_role) {
|
||||
case MWIFIEX_BSS_ROLE_UAP:
|
||||
priv->bss_mode = NL80211_IFTYPE_AP;
|
||||
break;
|
||||
case MWIFIEX_BSS_ROLE_STA:
|
||||
case MWIFIEX_BSS_ROLE_ANY:
|
||||
default:
|
||||
priv->bss_mode = NL80211_IFTYPE_STATION;
|
||||
break;
|
||||
}
|
||||
|
||||
mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE,
|
||||
HostCmd_ACT_GEN_SET, 0, NULL);
|
||||
|
||||
return mwifiex_sta_init_cmd(priv, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends IOCTL request to get statistics information.
|
||||
*
|
||||
|
|
|
@ -174,6 +174,12 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
|
|||
dev_err(adapter->dev, "Rx of A-MSDU failed");
|
||||
}
|
||||
return 0;
|
||||
} else if (rx_pkt_type == PKT_TYPE_MGMT) {
|
||||
ret = mwifiex_process_mgmt_packet(adapter, skb);
|
||||
if (ret)
|
||||
dev_err(adapter->dev, "Rx of mgmt packet failed");
|
||||
dev_kfree_skb_any(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -48,6 +48,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
|
|||
struct txpd *local_tx_pd;
|
||||
struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
u8 pad;
|
||||
u16 pkt_type, pkt_offset;
|
||||
|
||||
if (!skb->len) {
|
||||
dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len);
|
||||
|
@ -55,6 +56,8 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
|
|||
return skb->data;
|
||||
}
|
||||
|
||||
pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
|
||||
|
||||
/* If skb->data is not aligned; add padding */
|
||||
pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4;
|
||||
|
||||
|
@ -93,7 +96,14 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
|
|||
}
|
||||
|
||||
/* Offset of actual data */
|
||||
local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) + pad);
|
||||
pkt_offset = sizeof(struct txpd) + pad;
|
||||
if (pkt_type == PKT_TYPE_MGMT) {
|
||||
/* Set the packet type and add header for management frame */
|
||||
local_tx_pd->tx_pkt_type = cpu_to_le16(pkt_type);
|
||||
pkt_offset += MWIFIEX_MGMT_FRAME_HEADER_SIZE;
|
||||
}
|
||||
|
||||
local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset);
|
||||
|
||||
/* make space for INTF_HEADER_LEN */
|
||||
skb_push(skb, INTF_HEADER_LEN);
|
||||
|
|
|
@ -343,6 +343,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
|
|||
struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
|
||||
struct host_cmd_tlv_auth_type *auth_type;
|
||||
struct host_cmd_tlv_rates *tlv_rates;
|
||||
struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
|
||||
struct mwifiex_ie_types_htcap *htcap;
|
||||
struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
|
||||
int i;
|
||||
|
@ -497,6 +498,27 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
|
|||
tlv += sizeof(struct mwifiex_ie_types_htcap);
|
||||
}
|
||||
|
||||
if (bss_cfg->sta_ao_timer) {
|
||||
ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
|
||||
ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
|
||||
ao_timer->tlv.len = cpu_to_le16(sizeof(*ao_timer) -
|
||||
sizeof(struct host_cmd_tlv));
|
||||
ao_timer->sta_ao_timer = cpu_to_le32(bss_cfg->sta_ao_timer);
|
||||
cmd_size += sizeof(*ao_timer);
|
||||
tlv += sizeof(*ao_timer);
|
||||
}
|
||||
|
||||
if (bss_cfg->ps_sta_ao_timer) {
|
||||
ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
|
||||
ps_ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER);
|
||||
ps_ao_timer->tlv.len = cpu_to_le16(sizeof(*ps_ao_timer) -
|
||||
sizeof(struct host_cmd_tlv));
|
||||
ps_ao_timer->sta_ao_timer =
|
||||
cpu_to_le32(bss_cfg->ps_sta_ao_timer);
|
||||
cmd_size += sizeof(*ps_ao_timer);
|
||||
tlv += sizeof(*ps_ao_timer);
|
||||
}
|
||||
|
||||
*param_size = cmd_size;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -217,6 +217,12 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
|
|||
}
|
||||
|
||||
return 0;
|
||||
} else if (rx_pkt_type == PKT_TYPE_MGMT) {
|
||||
ret = mwifiex_process_mgmt_packet(adapter, skb);
|
||||
if (ret)
|
||||
dev_err(adapter->dev, "Rx of mgmt packet failed");
|
||||
dev_kfree_skb_any(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
|
||||
|
@ -278,6 +284,7 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
|
|||
struct uap_txpd *txpd;
|
||||
struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
int pad, len;
|
||||
u16 pkt_type;
|
||||
|
||||
if (!skb->len) {
|
||||
dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len);
|
||||
|
@ -285,6 +292,8 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
|
|||
return skb->data;
|
||||
}
|
||||
|
||||
pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
|
||||
|
||||
/* If skb->data is not aligned, add padding */
|
||||
pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4;
|
||||
|
||||
|
@ -312,6 +321,12 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
|
|||
cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[txpd->priority]);
|
||||
|
||||
/* Offset of actual data */
|
||||
if (pkt_type == PKT_TYPE_MGMT) {
|
||||
/* Set the packet type and add header for management frame */
|
||||
txpd->tx_pkt_type = cpu_to_le16(pkt_type);
|
||||
len += MWIFIEX_MGMT_FRAME_HEADER_SIZE;
|
||||
}
|
||||
|
||||
txpd->tx_pkt_offset = cpu_to_le16(len);
|
||||
|
||||
/* make space for INTF_HEADER_LEN */
|
||||
|
|
|
@ -141,6 +141,46 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function processes the received management packet and send it
|
||||
* to the kernel.
|
||||
*/
|
||||
int
|
||||
mwifiex_process_mgmt_packet(struct mwifiex_adapter *adapter,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct rxpd *rx_pd;
|
||||
struct mwifiex_private *priv;
|
||||
u16 pkt_len;
|
||||
|
||||
if (!skb)
|
||||
return -1;
|
||||
|
||||
rx_pd = (struct rxpd *)skb->data;
|
||||
priv = mwifiex_get_priv_by_id(adapter, rx_pd->bss_num, rx_pd->bss_type);
|
||||
if (!priv)
|
||||
return -1;
|
||||
|
||||
skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset));
|
||||
skb_pull(skb, sizeof(pkt_len));
|
||||
|
||||
pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);
|
||||
|
||||
/* Remove address4 */
|
||||
memmove(skb->data + sizeof(struct ieee80211_hdr_3addr),
|
||||
skb->data + sizeof(struct ieee80211_hdr),
|
||||
pkt_len - sizeof(struct ieee80211_hdr));
|
||||
|
||||
pkt_len -= ETH_ALEN + sizeof(pkt_len);
|
||||
rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);
|
||||
|
||||
cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq,
|
||||
CAL_RSSI(rx_pd->snr, rx_pd->nf),
|
||||
skb->data, pkt_len, GFP_ATOMIC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function processes the received packet before sending it to the
|
||||
* kernel.
|
||||
|
|
|
@ -462,7 +462,7 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
|
|||
for (i = 0; i < adapter->priv_num; ++i) {
|
||||
priv = adapter->priv[i];
|
||||
if (priv && atomic_read(&priv->wmm.tx_pkts_queued))
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -648,7 +648,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
|
|||
u8 ra[ETH_ALEN], tid_down;
|
||||
unsigned long flags;
|
||||
|
||||
if (!priv->media_connected) {
|
||||
if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) {
|
||||
dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
|
||||
mwifiex_write_data_complete(adapter, skb, -1);
|
||||
return;
|
||||
|
@ -663,7 +663,8 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
|
|||
/* In case of infra as we have already created the list during
|
||||
association we just don't have to call get_queue_raptr, we will
|
||||
have only 1 raptr for a tid in case of infra */
|
||||
if (!mwifiex_queuing_ra_based(priv)) {
|
||||
if (!mwifiex_queuing_ra_based(priv) &&
|
||||
!mwifiex_is_skb_mgmt_frame(skb)) {
|
||||
if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list))
|
||||
ra_list = list_first_entry(
|
||||
&priv->wmm.tid_tbl_ptr[tid_down].ra_list,
|
||||
|
@ -672,7 +673,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
|
|||
ra_list = NULL;
|
||||
} else {
|
||||
memcpy(ra, skb->data, ETH_ALEN);
|
||||
if (ra[0] & 0x01)
|
||||
if (ra[0] & 0x01 || mwifiex_is_skb_mgmt_frame(skb))
|
||||
memset(ra, 0xff, ETH_ALEN);
|
||||
ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "../wlcore/acx.h"
|
||||
#include "../wlcore/tx.h"
|
||||
#include "../wlcore/rx.h"
|
||||
#include "../wlcore/io.h"
|
||||
#include "../wlcore/boot.h"
|
||||
|
||||
#include "wl12xx.h"
|
||||
|
@ -1185,9 +1184,16 @@ static int wl12xx_enable_interrupts(struct wl1271 *wl)
|
|||
ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
|
||||
WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto disable_interrupts;
|
||||
|
||||
ret = wlcore_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
|
||||
if (ret < 0)
|
||||
goto disable_interrupts;
|
||||
|
||||
return ret;
|
||||
|
||||
disable_interrupts:
|
||||
wlcore_disable_interrupts(wl);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
@ -1583,7 +1589,10 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|||
return wlcore_set_key(wl, cmd, vif, sta, key_conf);
|
||||
}
|
||||
|
||||
static int wl12xx_setup(struct wl1271 *wl);
|
||||
|
||||
static struct wlcore_ops wl12xx_ops = {
|
||||
.setup = wl12xx_setup,
|
||||
.identify_chip = wl12xx_identify_chip,
|
||||
.identify_fw = wl12xx_identify_fw,
|
||||
.boot = wl12xx_boot,
|
||||
|
@ -1624,26 +1633,15 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __devinit wl12xx_probe(struct platform_device *pdev)
|
||||
static int wl12xx_setup(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct wl1271 *wl;
|
||||
struct ieee80211_hw *hw;
|
||||
struct wl12xx_priv *priv;
|
||||
struct wl12xx_priv *priv = wl->priv;
|
||||
struct wl12xx_platform_data *pdata = wl->pdev->dev.platform_data;
|
||||
|
||||
hw = wlcore_alloc_hw(sizeof(*priv));
|
||||
if (IS_ERR(hw)) {
|
||||
wl1271_error("can't allocate hw");
|
||||
return PTR_ERR(hw);
|
||||
}
|
||||
|
||||
wl = hw->priv;
|
||||
priv = wl->priv;
|
||||
wl->ops = &wl12xx_ops;
|
||||
wl->ptable = wl12xx_ptable;
|
||||
wl->rtable = wl12xx_rtable;
|
||||
wl->num_tx_desc = 16;
|
||||
wl->num_rx_desc = 8;
|
||||
wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS;
|
||||
wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS;
|
||||
wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES;
|
||||
wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
|
||||
wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
|
||||
wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
|
||||
|
@ -1695,7 +1693,36 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
|
|||
wl1271_error("Invalid tcxo parameter %s", tcxo_param);
|
||||
}
|
||||
|
||||
return wlcore_probe(wl, pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit wl12xx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wl1271 *wl;
|
||||
struct ieee80211_hw *hw;
|
||||
int ret;
|
||||
|
||||
hw = wlcore_alloc_hw(sizeof(struct wl12xx_priv),
|
||||
WL12XX_AGGR_BUFFER_SIZE);
|
||||
if (IS_ERR(hw)) {
|
||||
wl1271_error("can't allocate hw");
|
||||
ret = PTR_ERR(hw);
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl = hw->priv;
|
||||
wl->ops = &wl12xx_ops;
|
||||
wl->ptable = wl12xx_ptable;
|
||||
ret = wlcore_probe(wl, pdev);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
return ret;
|
||||
|
||||
out_free:
|
||||
wlcore_free_hw(wl);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
|
||||
|
@ -1714,17 +1741,7 @@ static struct platform_driver wl12xx_driver = {
|
|||
}
|
||||
};
|
||||
|
||||
static int __init wl12xx_init(void)
|
||||
{
|
||||
return platform_driver_register(&wl12xx_driver);
|
||||
}
|
||||
module_init(wl12xx_init);
|
||||
|
||||
static void __exit wl12xx_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&wl12xx_driver);
|
||||
}
|
||||
module_exit(wl12xx_exit);
|
||||
module_platform_driver(wl12xx_driver);
|
||||
|
||||
module_param_named(fref, fref_param, charp, 0);
|
||||
MODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52");
|
||||
|
|
|
@ -38,6 +38,13 @@
|
|||
#define WL128X_SUBTYPE_VER 2
|
||||
#define WL128X_MINOR_VER 115
|
||||
|
||||
#define WL12XX_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
|
||||
|
||||
#define WL12XX_NUM_TX_DESCRIPTORS 16
|
||||
#define WL12XX_NUM_RX_DESCRIPTORS 8
|
||||
|
||||
#define WL12XX_NUM_MAC_ADDRESSES 2
|
||||
|
||||
struct wl127x_rx_mem_pool_addr {
|
||||
u32 addr;
|
||||
u32 addr_extra;
|
||||
|
|
|
@ -220,7 +220,7 @@ static ssize_t clear_fw_stats_write(struct file *file,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl18xx_acx_clear_statistics(wl);
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
static char *ht_mode_param = NULL;
|
||||
static char *board_type_param = NULL;
|
||||
static bool checksum_param = false;
|
||||
static bool enable_11a_param = true;
|
||||
static int num_rx_desc_param = -1;
|
||||
|
||||
/* phy paramters */
|
||||
|
@ -415,7 +414,7 @@ static struct wlcore_conf wl18xx_conf = {
|
|||
.snr_threshold = 0,
|
||||
},
|
||||
.ht = {
|
||||
.rx_ba_win_size = 10,
|
||||
.rx_ba_win_size = 32,
|
||||
.tx_ba_win_size = 64,
|
||||
.inactivity_timeout = 10000,
|
||||
.tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
|
||||
|
@ -505,8 +504,8 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
|
|||
.rdl = 0x01,
|
||||
.auto_detect = 0x00,
|
||||
.dedicated_fem = FEM_NONE,
|
||||
.low_band_component = COMPONENT_2_WAY_SWITCH,
|
||||
.low_band_component_type = 0x06,
|
||||
.low_band_component = COMPONENT_3_WAY_SWITCH,
|
||||
.low_band_component_type = 0x04,
|
||||
.high_band_component = COMPONENT_2_WAY_SWITCH,
|
||||
.high_band_component_type = 0x09,
|
||||
.tcxo_ldo_voltage = 0x00,
|
||||
|
@ -812,6 +811,13 @@ static int wl18xx_enable_interrupts(struct wl1271 *wl)
|
|||
|
||||
ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
|
||||
WL1271_ACX_INTR_ALL & ~intr_mask);
|
||||
if (ret < 0)
|
||||
goto disable_interrupts;
|
||||
|
||||
return ret;
|
||||
|
||||
disable_interrupts:
|
||||
wlcore_disable_interrupts(wl);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
@ -1202,6 +1208,12 @@ static int wl18xx_handle_static_data(struct wl1271 *wl,
|
|||
struct wl18xx_static_data_priv *static_data_priv =
|
||||
(struct wl18xx_static_data_priv *) static_data->priv;
|
||||
|
||||
strncpy(wl->chip.phy_fw_ver_str, static_data_priv->phy_version,
|
||||
sizeof(wl->chip.phy_fw_ver_str));
|
||||
|
||||
/* make sure the string is NULL-terminated */
|
||||
wl->chip.phy_fw_ver_str[sizeof(wl->chip.phy_fw_ver_str) - 1] = '\0';
|
||||
|
||||
wl1271_info("PHY firmware version: %s", static_data_priv->phy_version);
|
||||
|
||||
return 0;
|
||||
|
@ -1240,13 +1252,6 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|||
if (!change_spare)
|
||||
return wlcore_set_key(wl, cmd, vif, sta, key_conf);
|
||||
|
||||
/*
|
||||
* stop the queues and flush to ensure the next packets are
|
||||
* in sync with FW spare block accounting
|
||||
*/
|
||||
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
|
||||
wl1271_tx_flush(wl);
|
||||
|
||||
ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -1269,7 +1274,6 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|||
}
|
||||
|
||||
out:
|
||||
wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1292,7 +1296,10 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
|
|||
return buf_offset;
|
||||
}
|
||||
|
||||
static int wl18xx_setup(struct wl1271 *wl);
|
||||
|
||||
static struct wlcore_ops wl18xx_ops = {
|
||||
.setup = wl18xx_setup,
|
||||
.identify_chip = wl18xx_identify_chip,
|
||||
.boot = wl18xx_boot,
|
||||
.plt_init = wl18xx_plt_init,
|
||||
|
@ -1373,27 +1380,15 @@ static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __devinit wl18xx_probe(struct platform_device *pdev)
|
||||
static int wl18xx_setup(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271 *wl;
|
||||
struct ieee80211_hw *hw;
|
||||
struct wl18xx_priv *priv;
|
||||
struct wl18xx_priv *priv = wl->priv;
|
||||
int ret;
|
||||
|
||||
hw = wlcore_alloc_hw(sizeof(*priv));
|
||||
if (IS_ERR(hw)) {
|
||||
wl1271_error("can't allocate hw");
|
||||
ret = PTR_ERR(hw);
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl = hw->priv;
|
||||
priv = wl->priv;
|
||||
wl->ops = &wl18xx_ops;
|
||||
wl->ptable = wl18xx_ptable;
|
||||
wl->rtable = wl18xx_rtable;
|
||||
wl->num_tx_desc = 32;
|
||||
wl->num_rx_desc = 32;
|
||||
wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
|
||||
wl->num_rx_desc = WL18XX_NUM_TX_DESCRIPTORS;
|
||||
wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
|
||||
wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
|
||||
wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
|
||||
wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
|
||||
|
@ -1404,9 +1399,9 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
|
|||
if (num_rx_desc_param != -1)
|
||||
wl->num_rx_desc = num_rx_desc_param;
|
||||
|
||||
ret = wl18xx_conf_init(wl, &pdev->dev);
|
||||
ret = wl18xx_conf_init(wl, wl->dev);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
return ret;
|
||||
|
||||
/* If the module param is set, update it in conf */
|
||||
if (board_type_param) {
|
||||
|
@ -1423,27 +1418,14 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
|
|||
} else {
|
||||
wl1271_error("invalid board type '%s'",
|
||||
board_type_param);
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* HACK! Just for now we hardcode COM8 and HDK to 0x06 */
|
||||
switch (priv->conf.phy.board_type) {
|
||||
case BOARD_TYPE_HDK_18XX:
|
||||
case BOARD_TYPE_COM8_18XX:
|
||||
priv->conf.phy.low_band_component_type = 0x06;
|
||||
break;
|
||||
case BOARD_TYPE_FPGA_18XX:
|
||||
case BOARD_TYPE_DVP_18XX:
|
||||
case BOARD_TYPE_EVB_18XX:
|
||||
priv->conf.phy.low_band_component_type = 0x05;
|
||||
break;
|
||||
default:
|
||||
if (priv->conf.phy.board_type >= NUM_BOARD_TYPES) {
|
||||
wl1271_error("invalid board type '%d'",
|
||||
priv->conf.phy.board_type);
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (low_band_component_param != -1)
|
||||
|
@ -1475,22 +1457,21 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
|
|||
priv->conf.ht.mode = HT_MODE_SISO20;
|
||||
else {
|
||||
wl1271_error("invalid ht_mode '%s'", ht_mode_param);
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->conf.ht.mode == HT_MODE_DEFAULT) {
|
||||
/*
|
||||
* Only support mimo with multiple antennas. Fall back to
|
||||
* siso20.
|
||||
* siso40.
|
||||
*/
|
||||
if (wl18xx_is_mimo_supported(wl))
|
||||
wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
|
||||
&wl18xx_mimo_ht_cap_2ghz);
|
||||
else
|
||||
wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
|
||||
&wl18xx_siso20_ht_cap);
|
||||
&wl18xx_siso40_ht_cap_2ghz);
|
||||
|
||||
/* 5Ghz is always wide */
|
||||
wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
|
||||
|
@ -1512,9 +1493,34 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
|
|||
wl18xx_ops.init_vif = NULL;
|
||||
}
|
||||
|
||||
wl->enable_11a = enable_11a_param;
|
||||
/* Enable 11a Band only if we have 5G antennas */
|
||||
wl->enable_11a = (priv->conf.phy.number_of_assembled_ant5 != 0);
|
||||
|
||||
return wlcore_probe(wl, pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit wl18xx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wl1271 *wl;
|
||||
struct ieee80211_hw *hw;
|
||||
int ret;
|
||||
|
||||
hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv),
|
||||
WL18XX_AGGR_BUFFER_SIZE);
|
||||
if (IS_ERR(hw)) {
|
||||
wl1271_error("can't allocate hw");
|
||||
ret = PTR_ERR(hw);
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl = hw->priv;
|
||||
wl->ops = &wl18xx_ops;
|
||||
wl->ptable = wl18xx_ptable;
|
||||
ret = wlcore_probe(wl, pdev);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
return ret;
|
||||
|
||||
out_free:
|
||||
wlcore_free_hw(wl);
|
||||
|
@ -1538,18 +1544,7 @@ static struct platform_driver wl18xx_driver = {
|
|||
}
|
||||
};
|
||||
|
||||
static int __init wl18xx_init(void)
|
||||
{
|
||||
return platform_driver_register(&wl18xx_driver);
|
||||
}
|
||||
module_init(wl18xx_init);
|
||||
|
||||
static void __exit wl18xx_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&wl18xx_driver);
|
||||
}
|
||||
module_exit(wl18xx_exit);
|
||||
|
||||
module_platform_driver(wl18xx_driver);
|
||||
module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR);
|
||||
MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20");
|
||||
|
||||
|
@ -1560,9 +1555,6 @@ MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or "
|
|||
module_param_named(checksum, checksum_param, bool, S_IRUSR);
|
||||
MODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)");
|
||||
|
||||
module_param_named(enable_11a, enable_11a_param, bool, S_IRUSR);
|
||||
MODULE_PARM_DESC(enable_11a, "Enable 11a (5GHz): boolean (defaults to true)");
|
||||
|
||||
module_param_named(dc2dc, dc2dc_param, int, S_IRUSR);
|
||||
MODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)");
|
||||
|
||||
|
|
|
@ -33,6 +33,13 @@
|
|||
|
||||
#define WL18XX_CMD_MAX_SIZE 740
|
||||
|
||||
#define WL18XX_AGGR_BUFFER_SIZE (13 * PAGE_SIZE)
|
||||
|
||||
#define WL18XX_NUM_TX_DESCRIPTORS 32
|
||||
#define WL18XX_NUM_RX_DESCRIPTORS 32
|
||||
|
||||
#define WL18XX_NUM_MAC_ADDRESSES 3
|
||||
|
||||
struct wl18xx_priv {
|
||||
/* buffer for sending commands to FW */
|
||||
u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
|
||||
|
|
|
@ -59,6 +59,9 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
|
|||
u16 status;
|
||||
u16 poll_count = 0;
|
||||
|
||||
if (WARN_ON(unlikely(wl->state == WLCORE_STATE_RESTARTING)))
|
||||
return -EIO;
|
||||
|
||||
cmd = buf;
|
||||
cmd->id = cpu_to_le16(id);
|
||||
cmd->status = 0;
|
||||
|
@ -990,7 +993,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
|
|||
|
||||
ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV,
|
||||
skb->data, skb->len,
|
||||
CMD_TEMPL_KLV_IDX_NULL_DATA,
|
||||
wlvif->sta.klv_template_id,
|
||||
wlvif->basic_rate);
|
||||
|
||||
out:
|
||||
|
@ -1785,10 +1788,17 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
|||
wlvif->bss_type == BSS_TYPE_IBSS)))
|
||||
return -EINVAL;
|
||||
|
||||
ret = wl12xx_cmd_role_start_dev(wl, wlvif);
|
||||
ret = wl12xx_cmd_role_enable(wl,
|
||||
wl12xx_wlvif_to_vif(wlvif)->addr,
|
||||
WL1271_ROLE_DEVICE,
|
||||
&wlvif->dev_role_id);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl12xx_cmd_role_start_dev(wl, wlvif);
|
||||
if (ret < 0)
|
||||
goto out_disable;
|
||||
|
||||
ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
|
||||
if (ret < 0)
|
||||
goto out_stop;
|
||||
|
@ -1797,6 +1807,8 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
|||
|
||||
out_stop:
|
||||
wl12xx_cmd_role_stop_dev(wl, wlvif);
|
||||
out_disable:
|
||||
wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -1824,6 +1836,11 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
|||
ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -157,11 +157,6 @@ enum wl1271_commands {
|
|||
|
||||
#define MAX_CMD_PARAMS 572
|
||||
|
||||
enum {
|
||||
CMD_TEMPL_KLV_IDX_NULL_DATA = 0,
|
||||
CMD_TEMPL_KLV_IDX_MAX = 4
|
||||
};
|
||||
|
||||
enum cmd_templ {
|
||||
CMD_TEMPL_NULL_DATA = 0,
|
||||
CMD_TEMPL_BEACON,
|
||||
|
|
|
@ -412,8 +412,7 @@ struct conf_rx_settings {
|
|||
#define CONF_TX_RATE_RETRY_LIMIT 10
|
||||
|
||||
/* basic rates for p2p operations (probe req/resp, etc.) */
|
||||
#define CONF_TX_RATE_MASK_BASIC_P2P (CONF_HW_BIT_RATE_6MBPS | \
|
||||
CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS)
|
||||
#define CONF_TX_RATE_MASK_BASIC_P2P CONF_HW_BIT_RATE_6MBPS
|
||||
|
||||
/*
|
||||
* Rates supported for data packets when operating as AP. Note the absence
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#define DRIVER_NAME "wl12xx"
|
||||
#define DRIVER_NAME "wlcore"
|
||||
#define DRIVER_PREFIX DRIVER_NAME ": "
|
||||
|
||||
enum {
|
||||
|
@ -73,11 +73,21 @@ extern u32 wl12xx_debug_level;
|
|||
#define wl1271_info(fmt, arg...) \
|
||||
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
|
||||
|
||||
/* define the debug macro differently if dynamic debug is supported */
|
||||
#if defined(CONFIG_DYNAMIC_DEBUG)
|
||||
#define wl1271_debug(level, fmt, arg...) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \
|
||||
if (unlikely(level & wl12xx_debug_level)) \
|
||||
dynamic_pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \
|
||||
} while (0)
|
||||
#else
|
||||
#define wl1271_debug(level, fmt, arg...) \
|
||||
do { \
|
||||
if (unlikely(level & wl12xx_debug_level)) \
|
||||
printk(KERN_DEBUG pr_fmt(DRIVER_PREFIX fmt "\n"), \
|
||||
##arg); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* TODO: use pr_debug_hex_dump when it becomes available */
|
||||
#define wl1271_dump(level, prefix, buf, len) \
|
||||
|
|
|
@ -62,11 +62,14 @@ void wl1271_debugfs_update_stats(struct wl1271 *wl)
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (wl->state == WL1271_STATE_ON && !wl->plt &&
|
||||
if (!wl->plt &&
|
||||
time_after(jiffies, wl->stats.fw_stats_update +
|
||||
msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
|
||||
wl1271_acx_statistics(wl, wl->stats.fw_stats);
|
||||
|
@ -286,7 +289,7 @@ static ssize_t dynamic_ps_timeout_write(struct file *file,
|
|||
|
||||
wl->conf.conn.dynamic_ps_timeout = value;
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -353,7 +356,7 @@ static ssize_t forced_ps_write(struct file *file,
|
|||
|
||||
wl->conf.conn.forced_ps = value;
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -486,6 +489,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
|
|||
DRIVER_STATE_PRINT_HEX(platform_quirks);
|
||||
DRIVER_STATE_PRINT_HEX(chip.id);
|
||||
DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
|
||||
DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str);
|
||||
DRIVER_STATE_PRINT_INT(sched_scanning);
|
||||
|
||||
#undef DRIVER_STATE_PRINT_INT
|
||||
|
@ -999,7 +1003,7 @@ static ssize_t sleep_auth_write(struct file *file,
|
|||
|
||||
wl->conf.conn.sta_sleep_auth = value;
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
/* this will show up on "read" in case we are off */
|
||||
wl->sleep_auth = value;
|
||||
goto out;
|
||||
|
@ -1060,14 +1064,16 @@ static ssize_t dev_mem_read(struct file *file,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
if (unlikely(wl->state == WLCORE_STATE_OFF)) {
|
||||
ret = -EFAULT;
|
||||
goto skip_read;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto skip_read;
|
||||
/*
|
||||
* Don't fail if elp_wakeup returns an error, so the device's memory
|
||||
* could be read even if the FW crashed
|
||||
*/
|
||||
wl1271_ps_elp_wakeup(wl);
|
||||
|
||||
/* store current partition and switch partition */
|
||||
memcpy(&old_part, &wl->curr_part, sizeof(old_part));
|
||||
|
@ -1145,14 +1151,16 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
if (unlikely(wl->state == WLCORE_STATE_OFF)) {
|
||||
ret = -EFAULT;
|
||||
goto skip_write;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto skip_write;
|
||||
/*
|
||||
* Don't fail if elp_wakeup returns an error, so the device's memory
|
||||
* could be read even if the FW crashed
|
||||
*/
|
||||
wl1271_ps_elp_wakeup(wl);
|
||||
|
||||
/* store current partition and switch partition */
|
||||
memcpy(&old_part, &wl->curr_part, sizeof(old_part));
|
||||
|
|
|
@ -141,7 +141,7 @@ int wl1271_init_templates_config(struct wl1271 *wl)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
|
||||
for (i = 0; i < WLCORE_MAX_KLV_TEMPLATES; i++) {
|
||||
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
|
||||
CMD_TEMPL_KLV, NULL,
|
||||
sizeof(struct ieee80211_qos_hdr),
|
||||
|
@ -371,15 +371,7 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl,
|
|||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret, i;
|
||||
|
||||
/* disable all keep-alive templates */
|
||||
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
|
||||
ret = wl1271_acx_keep_alive_config(wl, wlvif, i,
|
||||
ACX_KEEP_ALIVE_TPL_INVALID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
int ret;
|
||||
|
||||
/* disable the keep-alive feature */
|
||||
ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
|
||||
|
|
|
@ -64,7 +64,7 @@ static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr,
|
|||
return -EIO;
|
||||
|
||||
ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed);
|
||||
if (ret && wl->state != WL1271_STATE_OFF)
|
||||
if (ret && wl->state != WLCORE_STATE_OFF)
|
||||
set_bit(WL1271_FLAG_IO_FAILED, &wl->flags);
|
||||
|
||||
return ret;
|
||||
|
@ -80,7 +80,7 @@ static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr,
|
|||
return -EIO;
|
||||
|
||||
ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed);
|
||||
if (ret && wl->state != WL1271_STATE_OFF)
|
||||
if (ret && wl->state != WLCORE_STATE_OFF)
|
||||
set_bit(WL1271_FLAG_IO_FAILED, &wl->flags);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -248,7 +248,7 @@ static void wl12xx_tx_watchdog_work(struct work_struct *work)
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
/* Tx went out in the meantime - everything is ok */
|
||||
|
@ -512,7 +512,7 @@ static int wlcore_irq_locked(struct wl1271 *wl)
|
|||
|
||||
wl1271_debug(DEBUG_IRQ, "IRQ work");
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -696,7 +696,7 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
|
|||
* we can't call wl12xx_get_vif_count() here because
|
||||
* wl->mutex is taken, so use the cached last_vif_count value
|
||||
*/
|
||||
if (wl->last_vif_count > 1) {
|
||||
if (wl->last_vif_count > 1 && wl->mr_fw_name) {
|
||||
fw_type = WL12XX_FW_TYPE_MULTI;
|
||||
fw_name = wl->mr_fw_name;
|
||||
} else {
|
||||
|
@ -744,38 +744,14 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
|
||||
ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
|
||||
|
||||
if (ret < 0) {
|
||||
wl1271_debug(DEBUG_BOOT, "could not get nvs file %s: %d",
|
||||
WL12XX_NVS_NAME, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
|
||||
if (!wl->nvs) {
|
||||
wl1271_error("could not allocate memory for the nvs file");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->nvs_len = fw->size;
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
}
|
||||
|
||||
void wl12xx_queue_recovery_work(struct wl1271 *wl)
|
||||
{
|
||||
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)) {
|
||||
if (wl->state == WLCORE_STATE_ON) {
|
||||
wl->state = WLCORE_STATE_RESTARTING;
|
||||
set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
|
||||
wlcore_disable_interrupts_nosync(wl);
|
||||
ieee80211_queue_work(wl->hw, &wl->recovery_work);
|
||||
}
|
||||
|
@ -913,7 +889,7 @@ static void wl1271_recovery_work(struct work_struct *work)
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state != WL1271_STATE_ON || wl->plt)
|
||||
if (wl->state == WLCORE_STATE_OFF || wl->plt)
|
||||
goto out_unlock;
|
||||
|
||||
if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) {
|
||||
|
@ -1081,7 +1057,7 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
|
|||
|
||||
wl1271_notice("power up");
|
||||
|
||||
if (wl->state != WL1271_STATE_OFF) {
|
||||
if (wl->state != WLCORE_STATE_OFF) {
|
||||
wl1271_error("cannot go into PLT state because not "
|
||||
"in off state: %d", wl->state);
|
||||
ret = -EBUSY;
|
||||
|
@ -1102,7 +1078,7 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
|
|||
if (ret < 0)
|
||||
goto power_off;
|
||||
|
||||
wl->state = WL1271_STATE_ON;
|
||||
wl->state = WLCORE_STATE_ON;
|
||||
wl1271_notice("firmware booted in PLT mode %s (%s)",
|
||||
PLT_MODE[plt_mode],
|
||||
wl->chip.fw_ver_str);
|
||||
|
@ -1171,7 +1147,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
|
|||
wl1271_power_off(wl);
|
||||
wl->flags = 0;
|
||||
wl->sleep_auth = WL1271_PSM_ILLEGAL;
|
||||
wl->state = WL1271_STATE_OFF;
|
||||
wl->state = WLCORE_STATE_OFF;
|
||||
wl->plt = false;
|
||||
wl->plt_mode = PLT_OFF;
|
||||
wl->rx_counter = 0;
|
||||
|
@ -1602,12 +1578,6 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
|
|||
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
|
||||
goto out;
|
||||
|
||||
if ((wl->conf.conn.suspend_wake_up_event ==
|
||||
wl->conf.conn.wake_up_event) &&
|
||||
(wl->conf.conn.suspend_listen_interval ==
|
||||
wl->conf.conn.listen_interval))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -1616,6 +1586,12 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
|
|||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
if ((wl->conf.conn.suspend_wake_up_event ==
|
||||
wl->conf.conn.wake_up_event) &&
|
||||
(wl->conf.conn.suspend_listen_interval ==
|
||||
wl->conf.conn.listen_interval))
|
||||
goto out_sleep;
|
||||
|
||||
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
|
||||
wl->conf.conn.suspend_wake_up_event,
|
||||
wl->conf.conn.suspend_listen_interval);
|
||||
|
@ -1671,11 +1647,7 @@ static void wl1271_configure_resume(struct wl1271 *wl,
|
|||
if ((!is_ap) && (!is_sta))
|
||||
return;
|
||||
|
||||
if (is_sta &&
|
||||
((wl->conf.conn.suspend_wake_up_event ==
|
||||
wl->conf.conn.wake_up_event) &&
|
||||
(wl->conf.conn.suspend_listen_interval ==
|
||||
wl->conf.conn.listen_interval)))
|
||||
if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
|
||||
return;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -1685,6 +1657,12 @@ static void wl1271_configure_resume(struct wl1271 *wl,
|
|||
if (is_sta) {
|
||||
wl1271_configure_wowlan(wl, NULL);
|
||||
|
||||
if ((wl->conf.conn.suspend_wake_up_event ==
|
||||
wl->conf.conn.wake_up_event) &&
|
||||
(wl->conf.conn.suspend_listen_interval ==
|
||||
wl->conf.conn.listen_interval))
|
||||
goto out_sleep;
|
||||
|
||||
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
|
||||
wl->conf.conn.wake_up_event,
|
||||
wl->conf.conn.listen_interval);
|
||||
|
@ -1697,6 +1675,7 @@ static void wl1271_configure_resume(struct wl1271 *wl,
|
|||
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
|
||||
}
|
||||
|
||||
out_sleep:
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
}
|
||||
|
||||
|
@ -1833,7 +1812,7 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
if (wl->state == WLCORE_STATE_OFF) {
|
||||
if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
|
||||
&wl->flags))
|
||||
wlcore_enable_interrupts(wl);
|
||||
|
@ -1845,7 +1824,7 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
|
|||
* this must be before the cancel_work calls below, so that the work
|
||||
* functions don't perform further work.
|
||||
*/
|
||||
wl->state = WL1271_STATE_OFF;
|
||||
wl->state = WLCORE_STATE_OFF;
|
||||
|
||||
/*
|
||||
* Use the nosync variant to disable interrupts, so the mutex could be
|
||||
|
@ -1856,6 +1835,8 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
|
|||
mutex_unlock(&wl->mutex);
|
||||
|
||||
wlcore_synchronize_interrupts(wl);
|
||||
if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
|
||||
cancel_work_sync(&wl->recovery_work);
|
||||
wl1271_flush_deferred_work(wl);
|
||||
cancel_delayed_work_sync(&wl->scan_complete_work);
|
||||
cancel_work_sync(&wl->netstack_work);
|
||||
|
@ -1958,6 +1939,27 @@ static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
|
|||
*idx = WL12XX_MAX_RATE_POLICIES;
|
||||
}
|
||||
|
||||
static int wlcore_allocate_klv_template(struct wl1271 *wl, u8 *idx)
|
||||
{
|
||||
u8 policy = find_first_zero_bit(wl->klv_templates_map,
|
||||
WLCORE_MAX_KLV_TEMPLATES);
|
||||
if (policy >= WLCORE_MAX_KLV_TEMPLATES)
|
||||
return -EBUSY;
|
||||
|
||||
__set_bit(policy, wl->klv_templates_map);
|
||||
*idx = policy;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wlcore_free_klv_template(struct wl1271 *wl, u8 *idx)
|
||||
{
|
||||
if (WARN_ON(*idx >= WLCORE_MAX_KLV_TEMPLATES))
|
||||
return;
|
||||
|
||||
__clear_bit(*idx, wl->klv_templates_map);
|
||||
*idx = WLCORE_MAX_KLV_TEMPLATES;
|
||||
}
|
||||
|
||||
static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
switch (wlvif->bss_type) {
|
||||
|
@ -2022,6 +2024,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
|
|||
wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
|
||||
wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
|
||||
wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
|
||||
wlcore_allocate_klv_template(wl, &wlvif->sta.klv_template_id);
|
||||
wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
|
||||
wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
|
||||
|
@ -2098,7 +2101,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
|
|||
/* Unlocking the mutex in the middle of handling is
|
||||
inherently unsafe. In this case we deem it safe to do,
|
||||
because we need to let any possibly pending IRQ out of
|
||||
the system (and while we are WL1271_STATE_OFF the IRQ
|
||||
the system (and while we are WLCORE_STATE_OFF the IRQ
|
||||
work function will not do anything.) Also, any other
|
||||
possible concurrent operations will fail due to the
|
||||
current state, hence the wl1271 struct should be safe. */
|
||||
|
@ -2133,7 +2136,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
|
|||
wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
|
||||
wl->enable_11a ? "" : "not ");
|
||||
|
||||
wl->state = WL1271_STATE_ON;
|
||||
wl->state = WLCORE_STATE_ON;
|
||||
out:
|
||||
return booted;
|
||||
}
|
||||
|
@ -2167,7 +2170,11 @@ static bool wl12xx_need_fw_change(struct wl1271 *wl,
|
|||
wl->last_vif_count = vif_count;
|
||||
|
||||
/* no need for fw change if the device is OFF */
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
if (wl->state == WLCORE_STATE_OFF)
|
||||
return false;
|
||||
|
||||
/* no need for fw change if a single fw is used */
|
||||
if (!wl->mr_fw_name)
|
||||
return false;
|
||||
|
||||
if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
|
||||
|
@ -2249,7 +2256,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
|
|||
* TODO: after the nvs issue will be solved, move this block
|
||||
* to start(), and make sure here the driver is ON.
|
||||
*/
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
if (wl->state == WLCORE_STATE_OFF) {
|
||||
/*
|
||||
* we still need this in order to configure the fw
|
||||
* while uploading the nvs
|
||||
|
@ -2263,21 +2270,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
|
||||
wlvif->bss_type == BSS_TYPE_IBSS) {
|
||||
/*
|
||||
* The device role is a special role used for
|
||||
* rx and tx frames prior to association (as
|
||||
* the STA role can get packets only from
|
||||
* its associated bssid)
|
||||
*/
|
||||
ret = wl12xx_cmd_role_enable(wl, vif->addr,
|
||||
WL1271_ROLE_DEVICE,
|
||||
&wlvif->dev_role_id);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl12xx_cmd_role_enable(wl, vif->addr,
|
||||
role_type, &wlvif->role_id);
|
||||
if (ret < 0)
|
||||
|
@ -2316,7 +2308,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
|
|||
return;
|
||||
|
||||
/* because of hardware recovery, we may get here twice */
|
||||
if (wl->state != WL1271_STATE_ON)
|
||||
if (wl->state == WLCORE_STATE_OFF)
|
||||
return;
|
||||
|
||||
wl1271_info("down");
|
||||
|
@ -2346,10 +2338,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
|
|||
wlvif->bss_type == BSS_TYPE_IBSS) {
|
||||
if (wl12xx_dev_role_started(wlvif))
|
||||
wl12xx_stop_dev(wl, wlvif);
|
||||
|
||||
ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
|
||||
if (ret < 0)
|
||||
goto deinit;
|
||||
}
|
||||
|
||||
ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
|
||||
|
@ -2368,6 +2356,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
|
|||
wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
|
||||
wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
|
||||
wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
|
||||
wlcore_free_klv_template(wl, &wlvif->sta.klv_template_id);
|
||||
} else {
|
||||
wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
|
||||
wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
|
||||
|
@ -2432,12 +2421,11 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
|
|||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct wl12xx_vif *iter;
|
||||
struct vif_counter_data vif_count;
|
||||
bool cancel_recovery = true;
|
||||
|
||||
wl12xx_get_vif_count(hw, vif, &vif_count);
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF ||
|
||||
if (wl->state == WLCORE_STATE_OFF ||
|
||||
!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
|
||||
goto out;
|
||||
|
||||
|
@ -2457,12 +2445,9 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
|
|||
wl12xx_force_active_psm(wl);
|
||||
set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
|
||||
wl12xx_queue_recovery_work(wl);
|
||||
cancel_recovery = false;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
if (cancel_recovery)
|
||||
cancel_work_sync(&wl->recovery_work);
|
||||
}
|
||||
|
||||
static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
|
||||
|
@ -2536,7 +2521,7 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
|||
goto out;
|
||||
|
||||
ret = wl1271_acx_keep_alive_config(wl, wlvif,
|
||||
CMD_TEMPL_KLV_IDX_NULL_DATA,
|
||||
wlvif->sta.klv_template_id,
|
||||
ACX_KEEP_ALIVE_TPL_VALID);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -2556,6 +2541,11 @@ static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
|||
ieee80211_chswitch_done(vif, false);
|
||||
}
|
||||
|
||||
/* invalidate keep-alive template */
|
||||
wl1271_acx_keep_alive_config(wl, wlvif,
|
||||
wlvif->sta.klv_template_id,
|
||||
ACX_KEEP_ALIVE_TPL_INVALID);
|
||||
|
||||
/* to stop listening to a channel, we disconnect */
|
||||
ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
|
||||
if (ret < 0)
|
||||
|
@ -2594,11 +2584,6 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
|||
wlvif->rate_set =
|
||||
wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
ret = wl1271_acx_sta_rate_policies(wl, wlvif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = wl1271_acx_keep_alive_config(
|
||||
wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
|
||||
ACX_KEEP_ALIVE_TPL_INVALID);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
|
||||
|
@ -2772,7 +2757,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||
if (changed & IEEE80211_CONF_CHANGE_POWER)
|
||||
wl->power_level = conf->power_level;
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -2806,10 +2791,6 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct wl1271_filter_params *fp;
|
||||
struct netdev_hw_addr *ha;
|
||||
struct wl1271 *wl = hw->priv;
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
return 0;
|
||||
|
||||
fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
|
||||
if (!fp) {
|
||||
|
@ -2858,7 +2839,7 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
|
|||
*total &= WL1271_SUPPORTED_FILTERS;
|
||||
changed &= WL1271_SUPPORTED_FILTERS;
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -3082,8 +3063,45 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
int ret;
|
||||
bool might_change_spare =
|
||||
key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
|
||||
key_conf->cipher == WLAN_CIPHER_SUITE_TKIP;
|
||||
|
||||
return wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
|
||||
if (might_change_spare) {
|
||||
/*
|
||||
* stop the queues and flush to ensure the next packets are
|
||||
* in sync with FW spare block accounting
|
||||
*/
|
||||
mutex_lock(&wl->mutex);
|
||||
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
wl1271_tx_flush(wl);
|
||||
}
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
ret = -EAGAIN;
|
||||
goto out_wake_queues;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out_wake_queues;
|
||||
|
||||
ret = wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
|
||||
out_wake_queues:
|
||||
if (might_change_spare)
|
||||
wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
|
||||
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
|
@ -3105,17 +3123,6 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|||
key_conf->keylen, key_conf->flags);
|
||||
wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF)) {
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
|
||||
switch (key_conf->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
|
@ -3145,8 +3152,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|||
default:
|
||||
wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
|
||||
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out_sleep;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
|
@ -3157,7 +3163,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|||
tx_seq_32, tx_seq_16, sta);
|
||||
if (ret < 0) {
|
||||
wl1271_error("Could not add or replace key");
|
||||
goto out_sleep;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3171,7 +3177,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|||
ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("build arp rsp failed: %d", ret);
|
||||
goto out_sleep;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -3183,22 +3189,15 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|||
0, 0, sta);
|
||||
if (ret < 0) {
|
||||
wl1271_error("Could not remove key");
|
||||
goto out_sleep;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wl1271_error("Unsupported key cmd 0x%x", cmd);
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
out_sleep:
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wlcore_set_key);
|
||||
|
@ -3221,7 +3220,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
/*
|
||||
* We cannot return -EBUSY here because cfg80211 will expect
|
||||
* a call to ieee80211_scan_completed if we do - in this case
|
||||
|
@ -3261,7 +3260,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
|
||||
|
@ -3310,7 +3309,7 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
@ -3347,7 +3346,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -3368,7 +3367,7 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF)) {
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
@ -3397,7 +3396,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF)) {
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
@ -4173,7 +4172,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
|
||||
|
@ -4257,7 +4256,7 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -4456,7 +4455,7 @@ static int wl12xx_op_sta_state(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF)) {
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
@ -4495,7 +4494,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF)) {
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
@ -4613,7 +4612,7 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
|
|||
mask->control[i].legacy,
|
||||
i);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
|
||||
|
@ -4649,12 +4648,14 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF)) {
|
||||
if (unlikely(wl->state == WLCORE_STATE_OFF)) {
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
ieee80211_chswitch_done(vif, false);
|
||||
}
|
||||
goto out;
|
||||
} else if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -4689,7 +4690,7 @@ static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
/* packets are considered pending if in the TX queue or the FW */
|
||||
|
@ -4938,7 +4939,7 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
|
|||
|
||||
wl->sg_enabled = res;
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
|
@ -5056,7 +5057,7 @@ static void wl1271_connection_loss_work(struct work_struct *work)
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
/* Call mac80211 connection loss */
|
||||
|
@ -5070,18 +5071,17 @@ static void wl1271_connection_loss_work(struct work_struct *work)
|
|||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
|
||||
u32 oui, u32 nic, int n)
|
||||
static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic)
|
||||
{
|
||||
int i;
|
||||
|
||||
wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
|
||||
oui, nic, n);
|
||||
wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x",
|
||||
oui, nic);
|
||||
|
||||
if (nic + n - 1 > 0xffffff)
|
||||
if (nic + WLCORE_NUM_MAC_ADDRESSES - wl->num_mac_addr > 0xffffff)
|
||||
wl1271_warning("NIC part of the MAC address wraps around!");
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (i = 0; i < wl->num_mac_addr; i++) {
|
||||
wl->addresses[i].addr[0] = (u8)(oui >> 16);
|
||||
wl->addresses[i].addr[1] = (u8)(oui >> 8);
|
||||
wl->addresses[i].addr[2] = (u8) oui;
|
||||
|
@ -5091,7 +5091,22 @@ static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
|
|||
nic++;
|
||||
}
|
||||
|
||||
wl->hw->wiphy->n_addresses = n;
|
||||
/* we may be one address short at the most */
|
||||
WARN_ON(wl->num_mac_addr + 1 < WLCORE_NUM_MAC_ADDRESSES);
|
||||
|
||||
/*
|
||||
* turn on the LAA bit in the first address and use it as
|
||||
* the last address.
|
||||
*/
|
||||
if (wl->num_mac_addr < WLCORE_NUM_MAC_ADDRESSES) {
|
||||
int idx = WLCORE_NUM_MAC_ADDRESSES - 1;
|
||||
memcpy(&wl->addresses[idx], &wl->addresses[0],
|
||||
sizeof(wl->addresses[0]));
|
||||
/* LAA bit */
|
||||
wl->addresses[idx].addr[2] |= BIT(1);
|
||||
}
|
||||
|
||||
wl->hw->wiphy->n_addresses = WLCORE_NUM_MAC_ADDRESSES;
|
||||
wl->hw->wiphy->addresses = wl->addresses;
|
||||
}
|
||||
|
||||
|
@ -5130,8 +5145,7 @@ static int wl1271_register_hw(struct wl1271 *wl)
|
|||
if (wl->mac80211_registered)
|
||||
return 0;
|
||||
|
||||
wl1271_fetch_nvs(wl);
|
||||
if (wl->nvs != NULL) {
|
||||
if (wl->nvs_len >= 12) {
|
||||
/* NOTE: The wl->nvs->nvs element must be first, in
|
||||
* order to simplify the casting, we assume it is at
|
||||
* the beginning of the wl->nvs structure.
|
||||
|
@ -5151,7 +5165,7 @@ static int wl1271_register_hw(struct wl1271 *wl)
|
|||
nic_addr = wl->fuse_nic_addr + 1;
|
||||
}
|
||||
|
||||
wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
|
||||
wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr);
|
||||
|
||||
ret = ieee80211_register_hw(wl->hw);
|
||||
if (ret < 0) {
|
||||
|
@ -5181,7 +5195,7 @@ static void wl1271_unregister_hw(struct wl1271 *wl)
|
|||
|
||||
static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
|
||||
{
|
||||
.max = 2,
|
||||
.max = 3,
|
||||
.types = BIT(NL80211_IFTYPE_STATION),
|
||||
},
|
||||
{
|
||||
|
@ -5196,7 +5210,7 @@ static const struct ieee80211_iface_combination
|
|||
wlcore_iface_combinations[] = {
|
||||
{
|
||||
.num_different_channels = 1,
|
||||
.max_interfaces = 2,
|
||||
.max_interfaces = 3,
|
||||
.limits = wlcore_iface_limits,
|
||||
.n_limits = ARRAY_SIZE(wlcore_iface_limits),
|
||||
},
|
||||
|
@ -5312,7 +5326,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
|||
|
||||
#define WL1271_DEFAULT_CHANNEL 0
|
||||
|
||||
struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
|
||||
struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size)
|
||||
{
|
||||
struct ieee80211_hw *hw;
|
||||
struct wl1271 *wl;
|
||||
|
@ -5392,17 +5406,19 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
|
|||
|
||||
spin_lock_init(&wl->wl_lock);
|
||||
|
||||
wl->state = WL1271_STATE_OFF;
|
||||
wl->state = WLCORE_STATE_OFF;
|
||||
wl->fw_type = WL12XX_FW_TYPE_NONE;
|
||||
mutex_init(&wl->mutex);
|
||||
mutex_init(&wl->flush_mutex);
|
||||
init_completion(&wl->nvs_loading_complete);
|
||||
|
||||
order = get_order(WL1271_AGGR_BUFFER_SIZE);
|
||||
order = get_order(aggr_buf_size);
|
||||
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
|
||||
if (!wl->aggr_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_wq;
|
||||
}
|
||||
wl->aggr_buf_size = aggr_buf_size;
|
||||
|
||||
wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
|
||||
if (!wl->dummy_packet) {
|
||||
|
@ -5465,8 +5481,7 @@ int wlcore_free_hw(struct wl1271 *wl)
|
|||
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
|
||||
free_page((unsigned long)wl->fwlog);
|
||||
dev_kfree_skb(wl->dummy_packet);
|
||||
free_pages((unsigned long)wl->aggr_buf,
|
||||
get_order(WL1271_AGGR_BUFFER_SIZE));
|
||||
free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size));
|
||||
|
||||
wl1271_debugfs_exit(wl);
|
||||
|
||||
|
@ -5516,17 +5531,32 @@ static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
|
|||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
||||
static void wlcore_nvs_cb(const struct firmware *fw, void *context)
|
||||
{
|
||||
struct wl1271 *wl = context;
|
||||
struct platform_device *pdev = wl->pdev;
|
||||
struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
|
||||
unsigned long irqflags;
|
||||
int ret;
|
||||
|
||||
if (!wl->ops || !wl->ptable) {
|
||||
ret = -EINVAL;
|
||||
goto out_free_hw;
|
||||
if (fw) {
|
||||
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
if (!wl->nvs) {
|
||||
wl1271_error("Could not allocate nvs data");
|
||||
goto out;
|
||||
}
|
||||
wl->nvs_len = fw->size;
|
||||
} else {
|
||||
wl1271_debug(DEBUG_BOOT, "Could not get nvs file %s",
|
||||
WL12XX_NVS_NAME);
|
||||
wl->nvs = NULL;
|
||||
wl->nvs_len = 0;
|
||||
}
|
||||
|
||||
ret = wl->ops->setup(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_nvs;
|
||||
|
||||
BUG_ON(wl->num_tx_desc > WLCORE_MAX_TX_DESCRIPTORS);
|
||||
|
||||
/* adjust some runtime configuration parameters */
|
||||
|
@ -5535,11 +5565,8 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
|||
wl->irq = platform_get_irq(pdev, 0);
|
||||
wl->platform_quirks = pdata->platform_quirks;
|
||||
wl->set_power = pdata->set_power;
|
||||
wl->dev = &pdev->dev;
|
||||
wl->if_ops = pdata->ops;
|
||||
|
||||
platform_set_drvdata(pdev, wl);
|
||||
|
||||
if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
|
||||
irqflags = IRQF_TRIGGER_RISING;
|
||||
else
|
||||
|
@ -5550,7 +5577,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
|||
pdev->name, wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("request_irq() failed: %d", ret);
|
||||
goto out_free_hw;
|
||||
goto out_free_nvs;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
@ -5609,6 +5636,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
|||
goto out_hw_pg_ver;
|
||||
}
|
||||
|
||||
wl->initialized = true;
|
||||
goto out;
|
||||
|
||||
out_hw_pg_ver:
|
||||
|
@ -5623,10 +5651,33 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
|||
out_irq:
|
||||
free_irq(wl->irq, wl);
|
||||
|
||||
out_free_hw:
|
||||
wlcore_free_hw(wl);
|
||||
out_free_nvs:
|
||||
kfree(wl->nvs);
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
complete_all(&wl->nvs_loading_complete);
|
||||
}
|
||||
|
||||
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!wl->ops || !wl->ptable)
|
||||
return -EINVAL;
|
||||
|
||||
wl->dev = &pdev->dev;
|
||||
wl->pdev = pdev;
|
||||
platform_set_drvdata(pdev, wl);
|
||||
|
||||
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
|
||||
WL12XX_NVS_NAME, &pdev->dev, GFP_KERNEL,
|
||||
wl, wlcore_nvs_cb);
|
||||
if (ret < 0) {
|
||||
wl1271_error("request_firmware_nowait failed: %d", ret);
|
||||
complete_all(&wl->nvs_loading_complete);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wlcore_probe);
|
||||
|
@ -5635,6 +5686,10 @@ int __devexit wlcore_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct wl1271 *wl = platform_get_drvdata(pdev);
|
||||
|
||||
wait_for_completion(&wl->nvs_loading_complete);
|
||||
if (!wl->initialized)
|
||||
return 0;
|
||||
|
||||
if (wl->irq_wake_enabled) {
|
||||
device_init_wakeup(wl->dev, 0);
|
||||
disable_irq_wake(wl->irq);
|
||||
|
@ -5665,3 +5720,4 @@ MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
|
|||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
||||
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
|
||||
MODULE_FIRMWARE(WL12XX_NVS_NAME);
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
#define WL1271_WAKEUP_TIMEOUT 500
|
||||
|
||||
#define ELP_ENTRY_DELAY 5
|
||||
#define ELP_ENTRY_DELAY 30
|
||||
|
||||
void wl1271_elp_work(struct work_struct *work)
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ void wl1271_elp_work(struct work_struct *work)
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
/* our work might have been already cancelled */
|
||||
|
@ -98,11 +98,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
|||
return;
|
||||
}
|
||||
|
||||
if (wl->conf.conn.forced_ps)
|
||||
timeout = ELP_ENTRY_DELAY;
|
||||
else
|
||||
timeout = wl->conf.conn.dynamic_ps_timeout;
|
||||
|
||||
timeout = ELP_ENTRY_DELAY;
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
|
||||
msecs_to_jiffies(timeout));
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
|
|||
pkt_len = wlcore_rx_get_buf_size(wl, des);
|
||||
align_pkt_len = wlcore_rx_get_align_buf_size(wl,
|
||||
pkt_len);
|
||||
if (buf_size + align_pkt_len > WL1271_AGGR_BUFFER_SIZE)
|
||||
if (buf_size + align_pkt_len > wl->aggr_buf_size)
|
||||
break;
|
||||
buf_size += align_pkt_len;
|
||||
rx_counter++;
|
||||
|
|
|
@ -46,7 +46,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF)
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
|
||||
|
@ -184,11 +184,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
|
|||
if (passive)
|
||||
scan_options |= WL1271_SCAN_OPT_PASSIVE;
|
||||
|
||||
if (wlvif->bss_type == BSS_TYPE_AP_BSS ||
|
||||
test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
|
||||
cmd->params.role_id = wlvif->role_id;
|
||||
else
|
||||
cmd->params.role_id = wlvif->dev_role_id;
|
||||
cmd->params.role_id = wlvif->role_id;
|
||||
|
||||
if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
|
||||
ret = -EINVAL;
|
||||
|
@ -593,7 +589,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
|
|||
goto out;
|
||||
}
|
||||
|
||||
cmd->role_id = wlvif->dev_role_id;
|
||||
cmd->role_id = wlvif->role_id;
|
||||
if (!n_match_ssids) {
|
||||
/* No filter, with ssids */
|
||||
type = SCAN_SSID_FILTER_DISABLED;
|
||||
|
@ -683,7 +679,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
|||
if (!cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
cfg->role_id = wlvif->dev_role_id;
|
||||
cfg->role_id = wlvif->role_id;
|
||||
cfg->rssi_threshold = c->rssi_threshold;
|
||||
cfg->snr_threshold = c->snr_threshold;
|
||||
cfg->n_probe_reqs = c->num_probe_reqs;
|
||||
|
@ -718,7 +714,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
|||
if (!force_passive && cfg->active[0]) {
|
||||
u8 band = IEEE80211_BAND_2GHZ;
|
||||
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
|
||||
wlvif->dev_role_id, band,
|
||||
wlvif->role_id, band,
|
||||
req->ssids[0].ssid,
|
||||
req->ssids[0].ssid_len,
|
||||
ies->ie[band],
|
||||
|
@ -732,7 +728,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
|||
if (!force_passive && cfg->active[1]) {
|
||||
u8 band = IEEE80211_BAND_5GHZ;
|
||||
ret = wl12xx_cmd_build_probe_req(wl, wlvif,
|
||||
wlvif->dev_role_id, band,
|
||||
wlvif->role_id, band,
|
||||
req->ssids[0].ssid,
|
||||
req->ssids[0].ssid_len,
|
||||
ies->ie[band],
|
||||
|
@ -774,7 +770,7 @@ int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
|||
if (!start)
|
||||
return -ENOMEM;
|
||||
|
||||
start->role_id = wlvif->dev_role_id;
|
||||
start->role_id = wlvif->role_id;
|
||||
start->tag = WL1271_SCAN_DEFAULT_TAG;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
|
||||
|
@ -810,7 +806,7 @@ void wl1271_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
|||
return;
|
||||
}
|
||||
|
||||
stop->role_id = wlvif->dev_role_id;
|
||||
stop->role_id = wlvif->role_id;
|
||||
stop->tag = WL1271_SCAN_DEFAULT_TAG;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
|
||||
|
|
|
@ -66,7 +66,13 @@
|
|||
/* HW limitation: maximum possible chunk size is 4095 bytes */
|
||||
#define WSPI_MAX_CHUNK_SIZE 4092
|
||||
|
||||
#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
|
||||
/*
|
||||
* only support SPI for 12xx - this code should be reworked when 18xx
|
||||
* support is introduced
|
||||
*/
|
||||
#define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
|
||||
|
||||
#define WSPI_MAX_NUM_OF_CHUNKS (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
|
||||
|
||||
struct wl12xx_spi_glue {
|
||||
struct device *dev;
|
||||
|
@ -271,7 +277,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
|
|||
u32 chunk_len;
|
||||
int i;
|
||||
|
||||
WARN_ON(len > WL1271_AGGR_BUFFER_SIZE);
|
||||
WARN_ON(len > SPI_AGGR_BUFFER_SIZE);
|
||||
|
||||
spi_message_init(&m);
|
||||
memset(t, 0, sizeof(t));
|
||||
|
|
|
@ -92,7 +92,7 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
|
|||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
|||
int id, ret = -EBUSY, ac;
|
||||
u32 spare_blocks;
|
||||
|
||||
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
|
||||
if (buf_offset + total_len > wl->aggr_buf_size)
|
||||
return -EAGAIN;
|
||||
|
||||
spare_blocks = wlcore_hw_get_spare_blocks(wl, is_gem);
|
||||
|
@ -319,8 +319,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
|||
if (hlid == wlvif->ap.global_hlid)
|
||||
rate_idx = wlvif->ap.mgmt_rate_idx;
|
||||
else if (hlid == wlvif->ap.bcast_hlid ||
|
||||
skb->protocol == cpu_to_be16(ETH_P_PAE))
|
||||
/* send AP bcast and EAPOLs using the min basic rate */
|
||||
skb->protocol == cpu_to_be16(ETH_P_PAE) ||
|
||||
!ieee80211_is_data(frame_control))
|
||||
/*
|
||||
* send non-data, bcast and EAPOLs using the
|
||||
* min basic rate
|
||||
*/
|
||||
rate_idx = wlvif->ap.bcast_rate_idx;
|
||||
else
|
||||
rate_idx = wlvif->ap.ucast_rate_idx[ac];
|
||||
|
@ -687,7 +691,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl)
|
|||
int bus_ret = 0;
|
||||
u8 hlid;
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
return 0;
|
||||
|
||||
while ((skb = wl1271_skb_dequeue(wl, &hlid))) {
|
||||
|
@ -1072,39 +1076,54 @@ void wl12xx_tx_reset(struct wl1271 *wl)
|
|||
/* caller must *NOT* hold wl->mutex */
|
||||
void wl1271_tx_flush(struct wl1271 *wl)
|
||||
{
|
||||
unsigned long timeout;
|
||||
unsigned long timeout, start_time;
|
||||
int i;
|
||||
timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
|
||||
start_time = jiffies;
|
||||
timeout = start_time + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
|
||||
|
||||
/* only one flush should be in progress, for consistent queue state */
|
||||
mutex_lock(&wl->flush_mutex);
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
if (wl->tx_frames_cnt == 0 && wl1271_tx_total_queue_count(wl) == 0) {
|
||||
mutex_unlock(&wl->mutex);
|
||||
goto out;
|
||||
}
|
||||
|
||||
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
|
||||
|
||||
while (!time_after(jiffies, timeout)) {
|
||||
mutex_lock(&wl->mutex);
|
||||
wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
|
||||
wl1271_debug(DEBUG_MAC80211, "flushing tx buffer: %d %d",
|
||||
wl->tx_frames_cnt,
|
||||
wl1271_tx_total_queue_count(wl));
|
||||
|
||||
/* force Tx and give the driver some time to flush data */
|
||||
mutex_unlock(&wl->mutex);
|
||||
if (wl1271_tx_total_queue_count(wl))
|
||||
wl1271_tx_work(&wl->tx_work);
|
||||
msleep(20);
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if ((wl->tx_frames_cnt == 0) &&
|
||||
(wl1271_tx_total_queue_count(wl) == 0)) {
|
||||
mutex_unlock(&wl->mutex);
|
||||
goto out;
|
||||
wl1271_debug(DEBUG_MAC80211, "tx flush took %d ms",
|
||||
jiffies_to_msecs(jiffies - start_time));
|
||||
goto out_wake;
|
||||
}
|
||||
mutex_unlock(&wl->mutex);
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
wl1271_warning("Unable to flush all TX buffers, timed out.");
|
||||
wl1271_warning("Unable to flush all TX buffers, "
|
||||
"timed out (timeout %d ms",
|
||||
WL1271_TX_FLUSH_TIMEOUT / 1000);
|
||||
|
||||
/* forcibly flush all Tx buffers on our queues */
|
||||
mutex_lock(&wl->mutex);
|
||||
for (i = 0; i < WL12XX_MAX_LINKS; i++)
|
||||
wl1271_tx_reset_link_queues(wl, i);
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
out:
|
||||
out_wake:
|
||||
wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
|
||||
mutex_unlock(&wl->mutex);
|
||||
out:
|
||||
mutex_unlock(&wl->flush_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wl1271_tx_flush);
|
||||
|
|
|
@ -31,12 +31,19 @@
|
|||
/* The maximum number of Tx descriptors in all chip families */
|
||||
#define WLCORE_MAX_TX_DESCRIPTORS 32
|
||||
|
||||
/*
|
||||
* We always allocate this number of mac addresses. If we don't
|
||||
* have enough allocated addresses, the LAA bit is used
|
||||
*/
|
||||
#define WLCORE_NUM_MAC_ADDRESSES 3
|
||||
|
||||
/* forward declaration */
|
||||
struct wl1271_tx_hw_descr;
|
||||
enum wl_rx_buf_align;
|
||||
struct wl1271_rx_descriptor;
|
||||
|
||||
struct wlcore_ops {
|
||||
int (*setup)(struct wl1271 *wl);
|
||||
int (*identify_chip)(struct wl1271 *wl);
|
||||
int (*identify_fw)(struct wl1271 *wl);
|
||||
int (*boot)(struct wl1271 *wl);
|
||||
|
@ -139,10 +146,12 @@ struct wl1271_stats {
|
|||
};
|
||||
|
||||
struct wl1271 {
|
||||
bool initialized;
|
||||
struct ieee80211_hw *hw;
|
||||
bool mac80211_registered;
|
||||
|
||||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
|
||||
void *if_priv;
|
||||
|
||||
|
@ -153,7 +162,7 @@ struct wl1271 {
|
|||
|
||||
spinlock_t wl_lock;
|
||||
|
||||
enum wl1271_state state;
|
||||
enum wlcore_state state;
|
||||
enum wl12xx_fw_type fw_type;
|
||||
bool plt;
|
||||
enum plt_mode plt_mode;
|
||||
|
@ -181,7 +190,7 @@ struct wl1271 {
|
|||
u32 fuse_nic_addr;
|
||||
|
||||
/* we have up to 2 MAC addresses */
|
||||
struct mac_address addresses[2];
|
||||
struct mac_address addresses[WLCORE_NUM_MAC_ADDRESSES];
|
||||
int channel;
|
||||
u8 system_hlid;
|
||||
|
||||
|
@ -190,6 +199,8 @@ struct wl1271 {
|
|||
unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
|
||||
unsigned long rate_policies_map[
|
||||
BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)];
|
||||
unsigned long klv_templates_map[
|
||||
BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)];
|
||||
|
||||
struct list_head wlvif_list;
|
||||
|
||||
|
@ -237,6 +248,7 @@ struct wl1271 {
|
|||
|
||||
/* Intermediate buffer, used for packet aggregation */
|
||||
u8 *aggr_buf;
|
||||
u32 aggr_buf_size;
|
||||
|
||||
/* Reusable dummy packet template */
|
||||
struct sk_buff *dummy_packet;
|
||||
|
@ -393,13 +405,18 @@ struct wl1271 {
|
|||
/* sleep auth value currently configured to FW */
|
||||
int sleep_auth;
|
||||
|
||||
/* the number of allocated MAC addresses in this chip */
|
||||
int num_mac_addr;
|
||||
|
||||
/* the minimum FW version required for the driver to work */
|
||||
unsigned int min_fw_ver[NUM_FW_VER];
|
||||
|
||||
struct completion nvs_loading_complete;
|
||||
};
|
||||
|
||||
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
|
||||
int __devexit wlcore_remove(struct platform_device *pdev);
|
||||
struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size);
|
||||
struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size);
|
||||
int wlcore_free_hw(struct wl1271 *wl);
|
||||
int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#define WLCORE_NUM_BANDS 2
|
||||
|
||||
#define WL12XX_MAX_RATE_POLICIES 16
|
||||
#define WLCORE_MAX_KLV_TEMPLATES 4
|
||||
|
||||
/* Defined by FW as 0. Will not be freed or allocated. */
|
||||
#define WL12XX_SYSTEM_HLID 0
|
||||
|
@ -83,11 +84,10 @@
|
|||
#define WL1271_AP_BSS_INDEX 0
|
||||
#define WL1271_AP_DEF_BEACON_EXP 20
|
||||
|
||||
#define WL1271_AGGR_BUFFER_SIZE (5 * PAGE_SIZE)
|
||||
|
||||
enum wl1271_state {
|
||||
WL1271_STATE_OFF,
|
||||
WL1271_STATE_ON,
|
||||
enum wlcore_state {
|
||||
WLCORE_STATE_OFF,
|
||||
WLCORE_STATE_RESTARTING,
|
||||
WLCORE_STATE_ON,
|
||||
};
|
||||
|
||||
enum wl12xx_fw_type {
|
||||
|
@ -124,6 +124,7 @@ struct wl1271_chip {
|
|||
u32 id;
|
||||
char fw_ver_str[ETHTOOL_BUSINFO_LEN];
|
||||
unsigned int fw_ver[NUM_FW_VER];
|
||||
char phy_fw_ver_str[ETHTOOL_BUSINFO_LEN];
|
||||
};
|
||||
|
||||
#define NUM_TX_QUEUES 4
|
||||
|
@ -337,6 +338,8 @@ struct wl12xx_vif {
|
|||
u8 ap_rate_idx;
|
||||
u8 p2p_rate_idx;
|
||||
|
||||
u8 klv_template_id;
|
||||
|
||||
bool qos;
|
||||
} sta;
|
||||
struct {
|
||||
|
|
Loading…
Reference in a new issue