Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem

This commit is contained in:
John W. Linville 2012-10-01 07:39:36 -04:00
commit e4d680c706
67 changed files with 3270 additions and 1374 deletions

View file

@ -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) {

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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,

View file

@ -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 {

View file

@ -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");

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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");

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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)
{

View file

@ -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

View file

@ -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_ */

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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, &params->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);

View file

@ -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(

View file

@ -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,
};

View file

@ -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;

View file

@ -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,

View file

@ -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.
*

View file

@ -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 {

View file

@ -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;
}

View file

@ -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,

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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.
*

View file

@ -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;
}
/*

View file

@ -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);

View file

@ -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;

View file

@ -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 */

View file

@ -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.

View file

@ -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);
}

View file

@ -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");

View file

@ -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;

View file

@ -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);

View file

@ -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)");

View file

@ -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];

View file

@ -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;
}

View file

@ -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,

View file

@ -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

View file

@ -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) \

View file

@ -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));

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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));
}

View file

@ -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++;

View file

@ -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,

View file

@ -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));

View file

@ -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;
}

View file

@ -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);

View file

@ -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,

View file

@ -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 {