mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 22:21:42 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
commit
f2abba4921
@ -263,8 +263,7 @@ Who: Ravikiran Thirumalai <kiran@scalex86.org>
|
||||
|
||||
What: Code that is now under CONFIG_WIRELESS_EXT_SYSFS
|
||||
(in net/core/net-sysfs.c)
|
||||
When: After the only user (hal) has seen a release with the patches
|
||||
for enough time, probably some time in 2010.
|
||||
When: 3.5
|
||||
Why: Over 1K .text/.data size reduction, data is available in other
|
||||
ways (ioctls)
|
||||
Who: Johannes Berg <johannes@sipsolutions.net>
|
||||
|
@ -21,48 +21,58 @@ static void bcma_host_pci_switch_core(struct bcma_device *core)
|
||||
pr_debug("Switched to core: 0x%X\n", core->id.id);
|
||||
}
|
||||
|
||||
static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
|
||||
/* Provides access to the requested core. Returns base offset that has to be
|
||||
* used. It makes use of fixed windows when possible. */
|
||||
static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
|
||||
{
|
||||
switch (core->id.id) {
|
||||
case BCMA_CORE_CHIPCOMMON:
|
||||
return 3 * BCMA_CORE_SIZE;
|
||||
case BCMA_CORE_PCIE:
|
||||
return 2 * BCMA_CORE_SIZE;
|
||||
}
|
||||
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
offset += bcma_host_pci_provide_access_to_core(core);
|
||||
return ioread8(core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
offset += bcma_host_pci_provide_access_to_core(core);
|
||||
return ioread16(core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
offset += bcma_host_pci_provide_access_to_core(core);
|
||||
return ioread32(core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
|
||||
u8 value)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
offset += bcma_host_pci_provide_access_to_core(core);
|
||||
iowrite8(value, core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
|
||||
u16 value)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
offset += bcma_host_pci_provide_access_to_core(core);
|
||||
iowrite16(value, core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
|
||||
u32 value)
|
||||
{
|
||||
if (core->bus->mapped_core != core)
|
||||
bcma_host_pci_switch_core(core);
|
||||
offset += bcma_host_pci_provide_access_to_core(core);
|
||||
iowrite32(value, core->bus->mmio + offset);
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ config BT_MRVL
|
||||
The core driver to support Marvell Bluetooth devices.
|
||||
|
||||
This driver is required if you want to support
|
||||
Marvell Bluetooth devices, such as 8688/8787.
|
||||
Marvell Bluetooth devices, such as 8688/8787/8797.
|
||||
|
||||
Say Y here to compile Marvell Bluetooth driver
|
||||
into the kernel or say M to compile it as module.
|
||||
@ -201,8 +201,8 @@ config BT_MRVL_SDIO
|
||||
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
||||
|
||||
This driver is required if you want to use Marvell Bluetooth
|
||||
devices with SDIO interface. Currently SD8688/SD8787 chipsets are
|
||||
supported.
|
||||
devices with SDIO interface. Currently SD8688/SD8787/SD8797
|
||||
chipsets are supported.
|
||||
|
||||
Say Y here to compile support for Marvell BT-over-SDIO driver
|
||||
into the kernel or say M to compile it as module.
|
||||
|
@ -65,7 +65,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
|
||||
.io_port_1 = 0x01,
|
||||
.io_port_2 = 0x02,
|
||||
};
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = {
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
|
||||
.cfg = 0x00,
|
||||
.host_int_mask = 0x02,
|
||||
.host_intstatus = 0x03,
|
||||
@ -92,7 +92,14 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8787_uapsta.bin",
|
||||
.reg = &btmrvl_reg_8787,
|
||||
.reg = &btmrvl_reg_87xx,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8797_uapsta.bin",
|
||||
.reg = &btmrvl_reg_87xx,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
@ -103,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
||||
/* Marvell SD8787 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
|
||||
/* Marvell SD8797 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
@ -1076,3 +1086,4 @@ MODULE_LICENSE("GPL v2");
|
||||
MODULE_FIRMWARE("sd8688_helper.bin");
|
||||
MODULE_FIRMWARE("sd8688.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
|
||||
|
@ -785,9 +785,8 @@ skip_waking:
|
||||
usb_mark_last_busy(data->udev);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
|
||||
done:
|
||||
usb_free_urb(urb);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,8 @@
|
||||
|
||||
#define VERSION "1.3"
|
||||
|
||||
static bool amp;
|
||||
|
||||
struct vhci_data {
|
||||
struct hci_dev *hdev;
|
||||
|
||||
@ -239,6 +241,9 @@ static int vhci_open(struct inode *inode, struct file *file)
|
||||
hdev->bus = HCI_VIRTUAL;
|
||||
hdev->driver_data = data;
|
||||
|
||||
if (amp)
|
||||
hdev->dev_type = HCI_AMP;
|
||||
|
||||
hdev->open = vhci_open_dev;
|
||||
hdev->close = vhci_close_dev;
|
||||
hdev->flush = vhci_flush;
|
||||
@ -303,6 +308,9 @@ static void __exit vhci_exit(void)
|
||||
module_init(vhci_init);
|
||||
module_exit(vhci_exit);
|
||||
|
||||
module_param(amp, bool, 0644);
|
||||
MODULE_PARM_DESC(amp, "Create AMP controller device");
|
||||
|
||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||
MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
|
@ -203,7 +203,7 @@ static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
|
||||
i);
|
||||
|
||||
ath_dbg(common, ATH_DBG_CALIBRATE,
|
||||
"Orignal: Chn %diq_corr_meas = 0x%08x\n",
|
||||
"Original: Chn %d iq_corr_meas = 0x%08x\n",
|
||||
i, ah->totalIqCorrMeas[i]);
|
||||
|
||||
iqCorrNeg = 0;
|
||||
|
@ -226,7 +226,7 @@ static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
|
||||
i);
|
||||
|
||||
ath_dbg(common, ATH_DBG_CALIBRATE,
|
||||
"Orignal: Chn %diq_corr_meas = 0x%08x\n",
|
||||
"Original: Chn %d iq_corr_meas = 0x%08x\n",
|
||||
i, ah->totalIqCorrMeas[i]);
|
||||
|
||||
iqCorrNeg = 0;
|
||||
|
@ -41,24 +41,24 @@ static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = {
|
||||
|
||||
static const u32 ar9462_2p0_baseband_postamble[][5] = {
|
||||
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
|
||||
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
|
||||
{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
|
||||
{0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x5ac640de},
|
||||
{0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x0796be89},
|
||||
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d},
|
||||
{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a01ae},
|
||||
{0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x63c640da},
|
||||
{0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x09143e81},
|
||||
{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
|
||||
{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
|
||||
{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
|
||||
{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
|
||||
{0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
|
||||
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
|
||||
{0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x92c84d2e},
|
||||
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
|
||||
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8},
|
||||
{0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
|
||||
{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x33795d5e},
|
||||
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
|
||||
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
|
||||
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c782},
|
||||
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
|
||||
{0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
|
||||
{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
|
||||
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
|
||||
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
|
||||
{0x0000a204, 0x013187c0, 0x013187c4, 0x013187c4, 0x013187c0},
|
||||
@ -81,6 +81,15 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
|
||||
{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
|
||||
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
|
||||
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a3a4, 0x00000010, 0x00000010, 0x00000000, 0x00000000},
|
||||
{0x0000a3a8, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa},
|
||||
{0x0000a3ac, 0xaaaaaa00, 0xaaaaaa30, 0xaaaaaa00, 0xaaaaaa00},
|
||||
{0x0000a41c, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
|
||||
{0x0000a420, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce},
|
||||
{0x0000a424, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
|
||||
{0x0000a428, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce},
|
||||
{0x0000a42c, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
|
||||
{0x0000a430, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
|
||||
{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
|
||||
{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000},
|
||||
{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
@ -1107,11 +1116,11 @@ static const u32 ar9462_2p0_baseband_core[][2] = {
|
||||
{0x00009e30, 0x06336f77},
|
||||
{0x00009e34, 0x6af6532f},
|
||||
{0x00009e38, 0x0cc80c00},
|
||||
{0x00009e40, 0x0d261820},
|
||||
{0x00009e40, 0x15262820},
|
||||
{0x00009e4c, 0x00001004},
|
||||
{0x00009e50, 0x00ff03f1},
|
||||
{0x00009e54, 0xe4c355c7},
|
||||
{0x00009e58, 0xfd897735},
|
||||
{0x00009e54, 0xe4c555c2},
|
||||
{0x00009e58, 0xfd857722},
|
||||
{0x00009e5c, 0xe9198724},
|
||||
{0x00009fc0, 0x803e4788},
|
||||
{0x00009fc4, 0x0001efb5},
|
||||
@ -1142,9 +1151,6 @@ static const u32 ar9462_2p0_baseband_core[][2] = {
|
||||
{0x0000a398, 0x001f0e0f},
|
||||
{0x0000a39c, 0x0075393f},
|
||||
{0x0000a3a0, 0xb79f6427},
|
||||
{0x0000a3a4, 0x00000000},
|
||||
{0x0000a3a8, 0xaaaaaaaa},
|
||||
{0x0000a3ac, 0x3c466478},
|
||||
{0x0000a3c0, 0x20202020},
|
||||
{0x0000a3c4, 0x22222220},
|
||||
{0x0000a3c8, 0x20200020},
|
||||
@ -1167,12 +1173,6 @@ static const u32 ar9462_2p0_baseband_core[][2] = {
|
||||
{0x0000a40c, 0x00820820},
|
||||
{0x0000a414, 0x1ce739ce},
|
||||
{0x0000a418, 0x2d001dce},
|
||||
{0x0000a41c, 0x1ce739ce},
|
||||
{0x0000a420, 0x000001ce},
|
||||
{0x0000a424, 0x1ce739ce},
|
||||
{0x0000a428, 0x000001ce},
|
||||
{0x0000a42c, 0x1ce739ce},
|
||||
{0x0000a430, 0x1ce739ce},
|
||||
{0x0000a434, 0x00000000},
|
||||
{0x0000a438, 0x00001801},
|
||||
{0x0000a43c, 0x00100000},
|
||||
|
@ -808,7 +808,8 @@ void ath9k_htc_ani_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
/* Verify whether we must check ANI */
|
||||
if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
|
||||
if (ah->config.enable_ani &&
|
||||
(timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
|
||||
aniflag = true;
|
||||
common->ani.checkani_timer = timestamp;
|
||||
}
|
||||
@ -838,7 +839,7 @@ set_timer:
|
||||
* short calibration and long calibration.
|
||||
*/
|
||||
cal_interval = ATH_LONG_CALINTERVAL;
|
||||
if (priv->ah->config.enable_ani)
|
||||
if (ah->config.enable_ani)
|
||||
cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
|
||||
if (!common->ani.caldone)
|
||||
cal_interval = min(cal_interval, (u32)short_cal_interval);
|
||||
|
@ -504,7 +504,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
|
||||
return ecode;
|
||||
}
|
||||
|
||||
if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) {
|
||||
if (ah->config.enable_ani) {
|
||||
ath9k_hw_ani_setup(ah);
|
||||
ath9k_hw_ani_init(ah);
|
||||
}
|
||||
@ -610,6 +610,10 @@ static int __ath9k_hw_init(struct ath_hw *ah)
|
||||
if (!AR_SREV_9300_20_OR_LATER(ah))
|
||||
ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
|
||||
|
||||
/* disable ANI for 9340 */
|
||||
if (AR_SREV_9340(ah))
|
||||
ah->config.enable_ani = false;
|
||||
|
||||
ath9k_hw_init_mode_regs(ah);
|
||||
|
||||
if (!ah->is_pciexpress)
|
||||
|
@ -1110,7 +1110,6 @@ bool ath9k_hw_disable(struct ath_hw *ah);
|
||||
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test);
|
||||
void ath9k_hw_setopmode(struct ath_hw *ah);
|
||||
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
|
||||
void ath9k_hw_setbssidmask(struct ath_hw *ah);
|
||||
void ath9k_hw_write_associd(struct ath_hw *ah);
|
||||
u32 ath9k_hw_gettsf32(struct ath_hw *ah);
|
||||
u64 ath9k_hw_gettsf64(struct ath_hw *ah);
|
||||
|
@ -258,6 +258,8 @@ static void setup_ht_cap(struct ath_softc *sc,
|
||||
|
||||
if (AR_SREV_9330(ah) || AR_SREV_9485(ah))
|
||||
max_streams = 1;
|
||||
else if (AR_SREV_9462(ah))
|
||||
max_streams = 2;
|
||||
else if (AR_SREV_9300_20_OR_LATER(ah))
|
||||
max_streams = 3;
|
||||
else
|
||||
|
@ -118,7 +118,7 @@ void ath9k_ps_restore(struct ath_softc *sc)
|
||||
if (--sc->ps_usecount != 0)
|
||||
goto unlock;
|
||||
|
||||
if (sc->ps_idle)
|
||||
if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK))
|
||||
mode = ATH9K_PM_FULL_SLEEP;
|
||||
else if (sc->ps_enabled &&
|
||||
!(sc->ps_flags & (PS_WAIT_FOR_BEACON |
|
||||
@ -332,7 +332,8 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
|
||||
hchan = ah->curchan;
|
||||
}
|
||||
|
||||
if (fastcc && !ath9k_hw_check_alive(ah))
|
||||
if (fastcc && (ah->chip_fullsleep ||
|
||||
!ath9k_hw_check_alive(ah)))
|
||||
fastcc = false;
|
||||
|
||||
if (!ath_prepare_reset(sc, retry_tx, flush))
|
||||
@ -561,7 +562,6 @@ void ath_ani_calibrate(unsigned long data)
|
||||
/* Long calibration runs independently of short calibration. */
|
||||
if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
|
||||
longcal = true;
|
||||
ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
|
||||
common->ani.longcal_timer = timestamp;
|
||||
}
|
||||
|
||||
@ -569,8 +569,6 @@ void ath_ani_calibrate(unsigned long data)
|
||||
if (!common->ani.caldone) {
|
||||
if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
|
||||
shortcal = true;
|
||||
ath_dbg(common, ATH_DBG_ANI,
|
||||
"shortcal @%lu\n", jiffies);
|
||||
common->ani.shortcal_timer = timestamp;
|
||||
common->ani.resetcal_timer = timestamp;
|
||||
}
|
||||
@ -584,8 +582,9 @@ void ath_ani_calibrate(unsigned long data)
|
||||
}
|
||||
|
||||
/* Verify whether we must check ANI */
|
||||
if ((timestamp - common->ani.checkani_timer) >=
|
||||
ah->config.ani_poll_interval) {
|
||||
if (sc->sc_ah->config.enable_ani
|
||||
&& (timestamp - common->ani.checkani_timer) >=
|
||||
ah->config.ani_poll_interval) {
|
||||
aniflag = true;
|
||||
common->ani.checkani_timer = timestamp;
|
||||
}
|
||||
@ -605,6 +604,11 @@ void ath_ani_calibrate(unsigned long data)
|
||||
ah->rxchainmask, longcal);
|
||||
}
|
||||
|
||||
ath_dbg(common, ATH_DBG_ANI,
|
||||
"Calibration @%lu finished: %s %s %s, caldone: %s\n", jiffies,
|
||||
longcal ? "long" : "", shortcal ? "short" : "",
|
||||
aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
set_timer:
|
||||
@ -886,82 +890,6 @@ chip_reset:
|
||||
#undef SCHED_INTR
|
||||
}
|
||||
|
||||
static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_channel *channel = hw->conf.channel;
|
||||
int r;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
atomic_set(&ah->intr_ref_cnt, -1);
|
||||
|
||||
ath9k_hw_configpcipowersave(ah, false);
|
||||
|
||||
if (!ah->curchan)
|
||||
ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah);
|
||||
|
||||
r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
|
||||
if (r) {
|
||||
ath_err(common,
|
||||
"Unable to reset channel (%u MHz), reset status %d\n",
|
||||
channel->center_freq, r);
|
||||
}
|
||||
|
||||
ath_complete_reset(sc, true);
|
||||
|
||||
/* Enable LED */
|
||||
ath9k_hw_cfg_output(ah, ah->led_pin,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
|
||||
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ieee80211_channel *channel = hw->conf.channel;
|
||||
int r;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
||||
ath_cancel_work(sc);
|
||||
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
/*
|
||||
* Keep the LED on when the radio is disabled
|
||||
* during idle unassociated state.
|
||||
*/
|
||||
if (!sc->ps_idle) {
|
||||
ath9k_hw_set_gpio(ah, ah->led_pin, 1);
|
||||
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
|
||||
}
|
||||
|
||||
ath_prepare_reset(sc, false, true);
|
||||
|
||||
if (!ah->curchan)
|
||||
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
|
||||
|
||||
r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
|
||||
if (r) {
|
||||
ath_err(ath9k_hw_common(sc->sc_ah),
|
||||
"Unable to reset channel (%u MHz), reset status %d\n",
|
||||
channel->center_freq, r);
|
||||
}
|
||||
|
||||
ath9k_hw_phy_disable(ah);
|
||||
|
||||
ath9k_hw_configpcipowersave(ah, true);
|
||||
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
static int ath_reset(struct ath_softc *sc, bool retry_tx)
|
||||
{
|
||||
int r;
|
||||
@ -1097,6 +1025,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
||||
* and then setup of the interrupt mask.
|
||||
*/
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
atomic_set(&ah->intr_ref_cnt, -1);
|
||||
|
||||
r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
|
||||
if (r) {
|
||||
ath_err(common,
|
||||
@ -1138,6 +1069,18 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
||||
goto mutex_unlock;
|
||||
}
|
||||
|
||||
if (ah->led_pin >= 0) {
|
||||
ath9k_hw_cfg_output(ah, ah->led_pin,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset key cache to sane defaults (all entries cleared) instead of
|
||||
* semi-random values after suspend/resume.
|
||||
*/
|
||||
ath9k_cmn_init_crypto(sc->sc_ah);
|
||||
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
|
||||
@ -1183,6 +1126,13 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cannot tx while the hardware is in full sleep, it first needs a full
|
||||
* chip reset to recover from that
|
||||
*/
|
||||
if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP))
|
||||
goto exit;
|
||||
|
||||
if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) {
|
||||
/*
|
||||
* We are using PS-Poll and mac80211 can request TX while in
|
||||
@ -1229,6 +1179,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
bool prev_idle;
|
||||
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
@ -1259,21 +1210,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
* before setting the invalid flag. */
|
||||
ath9k_hw_disable_interrupts(ah);
|
||||
|
||||
if (!(sc->sc_flags & SC_OP_INVALID)) {
|
||||
ath_drain_all_txq(sc, false);
|
||||
ath_stoprecv(sc);
|
||||
ath9k_hw_phy_disable(ah);
|
||||
} else
|
||||
sc->rx.rxlink = NULL;
|
||||
|
||||
if (sc->rx.frag) {
|
||||
dev_kfree_skb_any(sc->rx.frag);
|
||||
sc->rx.frag = NULL;
|
||||
}
|
||||
|
||||
/* disable HAL and put h/w to sleep */
|
||||
ath9k_hw_disable(ah);
|
||||
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
/* we can now sync irq and kill any running tasklets, since we already
|
||||
@ -1282,12 +1218,37 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
||||
tasklet_kill(&sc->intr_tq);
|
||||
tasklet_kill(&sc->bcon_tasklet);
|
||||
|
||||
prev_idle = sc->ps_idle;
|
||||
sc->ps_idle = true;
|
||||
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
if (ah->led_pin >= 0) {
|
||||
ath9k_hw_set_gpio(ah, ah->led_pin, 1);
|
||||
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
|
||||
}
|
||||
|
||||
ath_prepare_reset(sc, false, true);
|
||||
|
||||
if (sc->rx.frag) {
|
||||
dev_kfree_skb_any(sc->rx.frag);
|
||||
sc->rx.frag = NULL;
|
||||
}
|
||||
|
||||
if (!ah->curchan)
|
||||
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
|
||||
|
||||
ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
|
||||
ath9k_hw_phy_disable(ah);
|
||||
|
||||
ath9k_hw_configpcipowersave(ah, true);
|
||||
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
sc->ps_idle = true;
|
||||
ath_radio_disable(sc, hw);
|
||||
|
||||
sc->sc_flags |= SC_OP_INVALID;
|
||||
sc->ps_idle = prev_idle;
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
|
||||
@ -1627,8 +1588,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
bool disable_radio = false;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
mutex_lock(&sc->mutex);
|
||||
|
||||
/*
|
||||
@ -1639,13 +1600,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
*/
|
||||
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
|
||||
sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
|
||||
if (!sc->ps_idle) {
|
||||
ath_radio_enable(sc, hw);
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"not-idle: enabling radio\n");
|
||||
} else {
|
||||
disable_radio = true;
|
||||
}
|
||||
if (sc->ps_idle)
|
||||
ath_cancel_work(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1752,18 +1708,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
ath_dbg(common, ATH_DBG_CONFIG,
|
||||
"Set power: %d\n", conf->power_level);
|
||||
sc->config.txpowlimit = 2 * conf->power_level;
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||
sc->config.txpowlimit, &sc->curtxpow);
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
||||
if (disable_radio) {
|
||||
ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
|
||||
ath_radio_disable(sc, hw);
|
||||
}
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2331,9 +2281,6 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
|
||||
return;
|
||||
}
|
||||
|
||||
if (drop)
|
||||
timeout = 1;
|
||||
|
||||
for (j = 0; j < timeout; j++) {
|
||||
bool npend = false;
|
||||
|
||||
@ -2351,21 +2298,22 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
|
||||
}
|
||||
|
||||
if (!npend)
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
drain_txq = ath_drain_all_txq(sc, false);
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
if (drop) {
|
||||
ath9k_ps_wakeup(sc);
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
drain_txq = ath_drain_all_txq(sc, false);
|
||||
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||
|
||||
if (!drain_txq)
|
||||
ath_reset(sc, false);
|
||||
if (!drain_txq)
|
||||
ath_reset(sc, false);
|
||||
|
||||
ath9k_ps_restore(sc);
|
||||
ieee80211_wake_queues(hw);
|
||||
ath9k_ps_restore(sc);
|
||||
ieee80211_wake_queues(hw);
|
||||
}
|
||||
|
||||
out:
|
||||
ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
@ -307,12 +307,11 @@ static int ath_pci_suspend(struct device *device)
|
||||
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
||||
struct ath_softc *sc = hw->priv;
|
||||
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
|
||||
|
||||
/* The device has to be moved to FULLSLEEP forcibly.
|
||||
* Otherwise the chip never moved to full sleep,
|
||||
* when no interface is up.
|
||||
*/
|
||||
ath9k_hw_disable(sc->sc_ah);
|
||||
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
|
||||
|
||||
return 0;
|
||||
@ -321,8 +320,6 @@ static int ath_pci_suspend(struct device *device)
|
||||
static int ath_pci_resume(struct device *device)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
||||
struct ath_softc *sc = hw->priv;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
@ -334,22 +331,6 @@ static int ath_pci_resume(struct device *device)
|
||||
if ((val & 0x0000ff00) != 0)
|
||||
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
/* Enable LED */
|
||||
ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
|
||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||
ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
|
||||
|
||||
/*
|
||||
* Reset key cache to sane defaults (all entries cleared) instead of
|
||||
* semi-random values after suspend/resume.
|
||||
*/
|
||||
ath9k_cmn_init_crypto(sc->sc_ah);
|
||||
ath9k_ps_restore(sc);
|
||||
|
||||
sc->ps_idle = true;
|
||||
ath_radio_disable(sc, hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1954,7 +1954,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
||||
skb_pull(skb, padsize);
|
||||
}
|
||||
|
||||
if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
|
||||
if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
|
||||
sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
|
||||
ath_dbg(common, ATH_DBG_PS,
|
||||
"Going back to sleep after having received TX status (0x%lx)\n",
|
||||
|
@ -2786,9 +2786,8 @@ il_tx_queue_alloc(struct il_priv *il, struct il_tx_queue *txq, u32 id)
|
||||
/* Driver ilate data, only for Tx (not command) queues,
|
||||
* not shared with device. */
|
||||
if (id != il->cmd_queue) {
|
||||
txq->txb =
|
||||
kzalloc(sizeof(txq->txb[0]) * TFD_QUEUE_SIZE_MAX,
|
||||
GFP_KERNEL);
|
||||
txq->txb = kcalloc(TFD_QUEUE_SIZE_MAX, sizeof(txq->txb[0]),
|
||||
GFP_KERNEL);
|
||||
if (!txq->txb) {
|
||||
IL_ERR("kmalloc for auxiliary BD "
|
||||
"structures failed\n");
|
||||
|
@ -1,7 +1,7 @@
|
||||
# WIFI
|
||||
obj-$(CONFIG_IWLWIFI) += iwlwifi.o
|
||||
iwlwifi-objs := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
|
||||
iwlwifi-objs += iwl-agn-ucode.o iwl-agn-tx.o
|
||||
iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o
|
||||
iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
|
||||
iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
|
||||
|
||||
@ -18,7 +18,7 @@ iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
|
||||
|
||||
iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
|
||||
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
|
||||
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o
|
||||
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-testmode.o
|
||||
|
||||
CFLAGS_iwl-devtrace.o := -I$(src)
|
||||
|
||||
|
@ -934,57 +934,6 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
|
||||
return ant;
|
||||
}
|
||||
|
||||
/* notification wait support */
|
||||
void iwlagn_init_notification_wait(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
u8 cmd,
|
||||
void (*fn)(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt,
|
||||
void *data),
|
||||
void *fn_data)
|
||||
{
|
||||
wait_entry->fn = fn;
|
||||
wait_entry->fn_data = fn_data;
|
||||
wait_entry->cmd = cmd;
|
||||
wait_entry->triggered = false;
|
||||
wait_entry->aborted = false;
|
||||
|
||||
spin_lock_bh(&priv->notif_wait_lock);
|
||||
list_add(&wait_entry->list, &priv->notif_waits);
|
||||
spin_unlock_bh(&priv->notif_wait_lock);
|
||||
}
|
||||
|
||||
int iwlagn_wait_notification(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
unsigned long timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wait_event_timeout(priv->notif_waitq,
|
||||
wait_entry->triggered || wait_entry->aborted,
|
||||
timeout);
|
||||
|
||||
spin_lock_bh(&priv->notif_wait_lock);
|
||||
list_del(&wait_entry->list);
|
||||
spin_unlock_bh(&priv->notif_wait_lock);
|
||||
|
||||
if (wait_entry->aborted)
|
||||
return -EIO;
|
||||
|
||||
/* return value is always >= 0 */
|
||||
if (ret <= 0)
|
||||
return -ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iwlagn_remove_notification(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry)
|
||||
{
|
||||
spin_lock_bh(&priv->notif_wait_lock);
|
||||
list_del(&wait_entry->list);
|
||||
spin_unlock_bh(&priv->notif_wait_lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
|
||||
{
|
||||
|
@ -1131,9 +1131,9 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
|
||||
priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
|
||||
|
||||
/* set up notification wait support */
|
||||
spin_lock_init(&priv->notif_wait_lock);
|
||||
INIT_LIST_HEAD(&priv->notif_waits);
|
||||
init_waitqueue_head(&priv->notif_waitq);
|
||||
spin_lock_init(&priv->shrd->notif_wait_lock);
|
||||
INIT_LIST_HEAD(&priv->shrd->notif_waits);
|
||||
init_waitqueue_head(&priv->shrd->notif_waitq);
|
||||
|
||||
/* Set up BT Rx handlers */
|
||||
if (priv->cfg->lib->bt_rx_handler_setup)
|
||||
@ -1152,11 +1152,11 @@ int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
|
||||
* even if the RX handler consumes the RXB we have
|
||||
* access to it in the notification wait entry.
|
||||
*/
|
||||
if (!list_empty(&priv->notif_waits)) {
|
||||
if (!list_empty(&priv->shrd->notif_waits)) {
|
||||
struct iwl_notification_wait *w;
|
||||
|
||||
spin_lock(&priv->notif_wait_lock);
|
||||
list_for_each_entry(w, &priv->notif_waits, list) {
|
||||
spin_lock(&priv->shrd->notif_wait_lock);
|
||||
list_for_each_entry(w, &priv->shrd->notif_waits, list) {
|
||||
if (w->cmd != pkt->hdr.cmd)
|
||||
continue;
|
||||
IWL_DEBUG_RX(priv,
|
||||
@ -1167,9 +1167,9 @@ int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
|
||||
if (w->fn)
|
||||
w->fn(priv, pkt, w->fn_data);
|
||||
}
|
||||
spin_unlock(&priv->notif_wait_lock);
|
||||
spin_unlock(&priv->shrd->notif_wait_lock);
|
||||
|
||||
wake_up_all(&priv->notif_waitq);
|
||||
wake_up_all(&priv->shrd->notif_waitq);
|
||||
}
|
||||
|
||||
if (priv->pre_rx_handler)
|
||||
|
@ -60,7 +60,7 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
|
||||
u8 old_dev_type = send->dev_type;
|
||||
int ret;
|
||||
|
||||
iwlagn_init_notification_wait(priv, &disable_wait,
|
||||
iwl_init_notification_wait(priv->shrd, &disable_wait,
|
||||
REPLY_WIPAN_DEACTIVATION_COMPLETE,
|
||||
NULL, NULL);
|
||||
|
||||
@ -74,9 +74,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
|
||||
|
||||
if (ret) {
|
||||
IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
|
||||
iwlagn_remove_notification(priv, &disable_wait);
|
||||
iwl_remove_notification(priv->shrd, &disable_wait);
|
||||
} else {
|
||||
ret = iwlagn_wait_notification(priv, &disable_wait, HZ);
|
||||
ret = iwl_wait_notification(priv->shrd, &disable_wait, HZ);
|
||||
if (ret)
|
||||
IWL_ERR(priv, "Timed out waiting for PAN disable\n");
|
||||
}
|
||||
|
@ -1232,14 +1232,14 @@ int iwl_alive_start(struct iwl_priv *priv)
|
||||
priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
|
||||
priv->cur_rssi_ctx = NULL;
|
||||
|
||||
iwlagn_send_prio_tbl(priv);
|
||||
iwl_send_prio_tbl(trans(priv));
|
||||
|
||||
/* FIXME: w/a to force change uCode BT state machine */
|
||||
ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
|
||||
ret = iwl_send_bt_env(trans(priv), IWL_BT_COEX_ENV_OPEN,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
|
||||
ret = iwl_send_bt_env(trans(priv), IWL_BT_COEX_ENV_CLOSE,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -108,8 +108,8 @@ void iwlagn_config_ht40(struct ieee80211_conf *conf,
|
||||
int iwlagn_rx_calib_result(struct iwl_priv *priv,
|
||||
struct iwl_rx_mem_buffer *rxb,
|
||||
struct iwl_device_cmd *cmd);
|
||||
int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
|
||||
void iwlagn_send_prio_tbl(struct iwl_priv *priv);
|
||||
int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type);
|
||||
void iwl_send_prio_tbl(struct iwl_trans *trans);
|
||||
int iwlagn_run_init_ucode(struct iwl_priv *priv);
|
||||
int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
|
||||
enum iwl_ucode_type ucode_type);
|
||||
@ -356,22 +356,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
|
||||
void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv);
|
||||
void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
|
||||
|
||||
/* notification wait support */
|
||||
void __acquires(wait_entry)
|
||||
iwlagn_init_notification_wait(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
u8 cmd,
|
||||
void (*fn)(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt,
|
||||
void *data),
|
||||
void *fn_data);
|
||||
int __must_check __releases(wait_entry)
|
||||
iwlagn_wait_notification(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
unsigned long timeout);
|
||||
void __releases(wait_entry)
|
||||
iwlagn_remove_notification(struct iwl_priv *priv,
|
||||
struct iwl_notification_wait *wait_entry);
|
||||
extern int iwlagn_init_alive_start(struct iwl_priv *priv);
|
||||
extern int iwl_alive_start(struct iwl_priv *priv);
|
||||
/* svtool */
|
||||
|
@ -836,19 +836,6 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void iwlagn_abort_notification_waits(struct iwl_priv *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct iwl_notification_wait *wait_entry;
|
||||
|
||||
spin_lock_irqsave(&priv->notif_wait_lock, flags);
|
||||
list_for_each_entry(wait_entry, &priv->notif_waits, list)
|
||||
wait_entry->aborted = true;
|
||||
spin_unlock_irqrestore(&priv->notif_wait_lock, flags);
|
||||
|
||||
wake_up_all(&priv->notif_waitq);
|
||||
}
|
||||
|
||||
void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
|
||||
{
|
||||
unsigned int reload_msec;
|
||||
@ -860,7 +847,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
|
||||
/* Cancel currently queued command. */
|
||||
clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
|
||||
|
||||
iwlagn_abort_notification_waits(priv);
|
||||
iwl_abort_notification_waits(priv->shrd);
|
||||
|
||||
/* Keep the restart process from trying to send host
|
||||
* commands by clearing the ready bit */
|
||||
|
@ -134,48 +134,43 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
|
||||
*/
|
||||
|
||||
/* 0x0000000F - 0x00000001 */
|
||||
#define IWL_DL_INFO (1 << 0)
|
||||
#define IWL_DL_MAC80211 (1 << 1)
|
||||
#define IWL_DL_HCMD (1 << 2)
|
||||
#define IWL_DL_STATE (1 << 3)
|
||||
#define IWL_DL_INFO 0x00000001
|
||||
#define IWL_DL_MAC80211 0x00000002
|
||||
#define IWL_DL_HCMD 0x00000004
|
||||
#define IWL_DL_STATE 0x00000008
|
||||
/* 0x000000F0 - 0x00000010 */
|
||||
#define IWL_DL_MACDUMP (1 << 4)
|
||||
#define IWL_DL_HCMD_DUMP (1 << 5)
|
||||
#define IWL_DL_EEPROM (1 << 6)
|
||||
#define IWL_DL_RADIO (1 << 7)
|
||||
#define IWL_DL_EEPROM 0x00000040
|
||||
#define IWL_DL_RADIO 0x00000080
|
||||
/* 0x00000F00 - 0x00000100 */
|
||||
#define IWL_DL_POWER (1 << 8)
|
||||
#define IWL_DL_TEMP (1 << 9)
|
||||
/* reserved (1 << 10) */
|
||||
#define IWL_DL_SCAN (1 << 11)
|
||||
#define IWL_DL_POWER 0x00000100
|
||||
#define IWL_DL_TEMP 0x00000200
|
||||
#define IWL_DL_SCAN 0x00000800
|
||||
/* 0x0000F000 - 0x00001000 */
|
||||
#define IWL_DL_ASSOC (1 << 12)
|
||||
#define IWL_DL_DROP (1 << 13)
|
||||
/* reserved (1 << 14) */
|
||||
#define IWL_DL_COEX (1 << 15)
|
||||
#define IWL_DL_ASSOC 0x00001000
|
||||
#define IWL_DL_DROP 0x00002000
|
||||
#define IWL_DL_COEX 0x00008000
|
||||
/* 0x000F0000 - 0x00010000 */
|
||||
#define IWL_DL_FW (1 << 16)
|
||||
#define IWL_DL_RF_KILL (1 << 17)
|
||||
#define IWL_DL_FW_ERRORS (1 << 18)
|
||||
#define IWL_DL_LED (1 << 19)
|
||||
#define IWL_DL_FW 0x00010000
|
||||
#define IWL_DL_RF_KILL 0x00020000
|
||||
#define IWL_DL_FW_ERRORS 0x00040000
|
||||
#define IWL_DL_LED 0x00080000
|
||||
/* 0x00F00000 - 0x00100000 */
|
||||
#define IWL_DL_RATE (1 << 20)
|
||||
#define IWL_DL_CALIB (1 << 21)
|
||||
#define IWL_DL_WEP (1 << 22)
|
||||
#define IWL_DL_TX (1 << 23)
|
||||
#define IWL_DL_RATE 0x00100000
|
||||
#define IWL_DL_CALIB 0x00200000
|
||||
#define IWL_DL_WEP 0x00400000
|
||||
#define IWL_DL_TX 0x00800000
|
||||
/* 0x0F000000 - 0x01000000 */
|
||||
#define IWL_DL_RX (1 << 24)
|
||||
#define IWL_DL_ISR (1 << 25)
|
||||
#define IWL_DL_HT (1 << 26)
|
||||
#define IWL_DL_RX 0x01000000
|
||||
#define IWL_DL_ISR 0x02000000
|
||||
#define IWL_DL_HT 0x04000000
|
||||
/* 0xF0000000 - 0x10000000 */
|
||||
#define IWL_DL_11H (1 << 28)
|
||||
#define IWL_DL_STATS (1 << 29)
|
||||
#define IWL_DL_TX_REPLY (1 << 30)
|
||||
#define IWL_DL_TX_QUEUES (1 << 31)
|
||||
#define IWL_DL_11H 0x10000000
|
||||
#define IWL_DL_STATS 0x20000000
|
||||
#define IWL_DL_TX_REPLY 0x40000000
|
||||
#define IWL_DL_TX_QUEUES 0x80000000
|
||||
|
||||
#define IWL_DEBUG_INFO(p, f, a...) IWL_DEBUG(p, IWL_DL_INFO, f, ## a)
|
||||
#define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a)
|
||||
#define IWL_DEBUG_MACDUMP(p, f, a...) IWL_DEBUG(p, IWL_DL_MACDUMP, f, ## a)
|
||||
#define IWL_DEBUG_TEMP(p, f, a...) IWL_DEBUG(p, IWL_DL_TEMP, f, ## a)
|
||||
#define IWL_DEBUG_SCAN(p, f, a...) IWL_DEBUG(p, IWL_DL_SCAN, f, ## a)
|
||||
#define IWL_DEBUG_RX(p, f, a...) IWL_DEBUG(p, IWL_DL_RX, f, ## a)
|
||||
@ -184,7 +179,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
|
||||
#define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a)
|
||||
#define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
|
||||
#define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
|
||||
#define IWL_DEBUG_HC_DUMP(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD_DUMP, f, ## a)
|
||||
#define IWL_DEBUG_EEPROM(p, f, a...) IWL_DEBUG(p, IWL_DL_EEPROM, f, ## a)
|
||||
#define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
|
||||
#define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a)
|
||||
@ -206,8 +200,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
|
||||
#define IWL_DEBUG_STATS_LIMIT(p, f, a...) \
|
||||
IWL_DEBUG_LIMIT(p, IWL_DL_STATS, f, ## a)
|
||||
#define IWL_DEBUG_TX_REPLY(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_REPLY, f, ## a)
|
||||
#define IWL_DEBUG_TX_REPLY_LIMIT(p, f, a...) \
|
||||
IWL_DEBUG_LIMIT(p, IWL_DL_TX_REPLY, f, ## a)
|
||||
#define IWL_DEBUG_TX_QUEUES(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_QUEUES, f, ## a)
|
||||
#define IWL_DEBUG_RADIO(p, f, a...) IWL_DEBUG(p, IWL_DL_RADIO, f, ## a)
|
||||
#define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a)
|
||||
|
@ -234,11 +234,12 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
||||
|
||||
/* default is to dump the entire data segment */
|
||||
if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
|
||||
struct iwl_trans *trans = trans(priv);
|
||||
priv->dbgfs_sram_offset = 0x800000;
|
||||
if (priv->ucode_type == IWL_UCODE_INIT)
|
||||
priv->dbgfs_sram_len = trans(priv)->ucode_init.data.len;
|
||||
if (trans->shrd->ucode_type == IWL_UCODE_INIT)
|
||||
priv->dbgfs_sram_len = trans->ucode_init.data.len;
|
||||
else
|
||||
priv->dbgfs_sram_len = trans(priv)->ucode_rt.data.len;
|
||||
priv->dbgfs_sram_len = trans->ucode_rt.data.len;
|
||||
}
|
||||
len = priv->dbgfs_sram_len;
|
||||
|
||||
|
@ -689,35 +689,6 @@ struct iwl_force_reset {
|
||||
*/
|
||||
#define IWLAGN_EXT_BEACON_TIME_POS 22
|
||||
|
||||
/**
|
||||
* struct iwl_notification_wait - notification wait entry
|
||||
* @list: list head for global list
|
||||
* @fn: function called with the notification
|
||||
* @cmd: command ID
|
||||
*
|
||||
* This structure is not used directly, to wait for a
|
||||
* notification declare it on the stack, and call
|
||||
* iwlagn_init_notification_wait() with appropriate
|
||||
* parameters. Then do whatever will cause the ucode
|
||||
* to notify the driver, and to wait for that then
|
||||
* call iwlagn_wait_notification().
|
||||
*
|
||||
* Each notification is one-shot. If at some point we
|
||||
* need to support multi-shot notifications (which
|
||||
* can't be allocated on the stack) we need to modify
|
||||
* the code for them.
|
||||
*/
|
||||
struct iwl_notification_wait {
|
||||
struct list_head list;
|
||||
|
||||
void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt,
|
||||
void *data);
|
||||
void *fn_data;
|
||||
|
||||
u8 cmd;
|
||||
bool triggered, aborted;
|
||||
};
|
||||
|
||||
struct iwl_rxon_context {
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
@ -790,6 +761,12 @@ struct iwl_testmode_trace {
|
||||
dma_addr_t dma_addr;
|
||||
bool trace_enabled;
|
||||
};
|
||||
struct iwl_testmode_sram {
|
||||
u32 buff_size;
|
||||
u32 num_chunks;
|
||||
u8 *buff_addr;
|
||||
bool sram_readed;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct iwl_wipan_noa_data {
|
||||
@ -883,7 +860,6 @@ struct iwl_priv {
|
||||
u32 ucode_ver; /* version of ucode, copy of
|
||||
iwl_ucode.ver */
|
||||
|
||||
enum iwl_ucode_type ucode_type;
|
||||
char firmware_name[25];
|
||||
|
||||
struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
|
||||
@ -987,10 +963,6 @@ struct iwl_priv {
|
||||
/* counts reply_tx error */
|
||||
struct reply_tx_error_statistics reply_tx_stats;
|
||||
struct reply_agg_tx_error_statistics reply_agg_tx_stats;
|
||||
/* notification wait support */
|
||||
struct list_head notif_waits;
|
||||
spinlock_t notif_wait_lock;
|
||||
wait_queue_head_t notif_waitq;
|
||||
|
||||
/* remain-on-channel offload support */
|
||||
struct ieee80211_channel *hw_roc_channel;
|
||||
@ -1070,6 +1042,7 @@ struct iwl_priv {
|
||||
bool led_registered;
|
||||
#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
|
||||
struct iwl_testmode_trace testmode_trace;
|
||||
struct iwl_testmode_sram testmode_sram;
|
||||
u32 tm_fixed_rate;
|
||||
#endif
|
||||
|
||||
|
@ -481,15 +481,11 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
|
||||
IWL_DEBUG_MACDUMP(priv, "enter\n");
|
||||
|
||||
IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
|
||||
ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
|
||||
|
||||
if (iwlagn_tx_skb(priv, skb))
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
IWL_DEBUG_MACDUMP(priv, "leave\n");
|
||||
}
|
||||
|
||||
static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
@ -521,6 +517,17 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
/* fall through */
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We could program these keys into the hardware as well, but we
|
||||
* don't expect much multicast traffic in IBSS and having keys
|
||||
|
@ -256,6 +256,52 @@ struct iwl_tid_data {
|
||||
struct iwl_ht_agg agg;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_ucode_type
|
||||
*
|
||||
* The type of ucode currently loaded on the hardware.
|
||||
*
|
||||
* @IWL_UCODE_NONE: No ucode loaded
|
||||
* @IWL_UCODE_REGULAR: Normal runtime ucode
|
||||
* @IWL_UCODE_INIT: Initial ucode
|
||||
* @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode
|
||||
*/
|
||||
enum iwl_ucode_type {
|
||||
IWL_UCODE_NONE,
|
||||
IWL_UCODE_REGULAR,
|
||||
IWL_UCODE_INIT,
|
||||
IWL_UCODE_WOWLAN,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_notification_wait - notification wait entry
|
||||
* @list: list head for global list
|
||||
* @fn: function called with the notification
|
||||
* @cmd: command ID
|
||||
*
|
||||
* This structure is not used directly, to wait for a
|
||||
* notification declare it on the stack, and call
|
||||
* iwlagn_init_notification_wait() with appropriate
|
||||
* parameters. Then do whatever will cause the ucode
|
||||
* to notify the driver, and to wait for that then
|
||||
* call iwlagn_wait_notification().
|
||||
*
|
||||
* Each notification is one-shot. If at some point we
|
||||
* need to support multi-shot notifications (which
|
||||
* can't be allocated on the stack) we need to modify
|
||||
* the code for them.
|
||||
*/
|
||||
struct iwl_notification_wait {
|
||||
struct list_head list;
|
||||
|
||||
void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt,
|
||||
void *data);
|
||||
void *fn_data;
|
||||
|
||||
u8 cmd;
|
||||
bool triggered, aborted;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_shared - shared fields for all the layers of the driver
|
||||
*
|
||||
@ -273,6 +319,10 @@ struct iwl_tid_data {
|
||||
* @sta_lock: protects the station table.
|
||||
* If lock and sta_lock are needed, lock must be acquired first.
|
||||
* @mutex:
|
||||
* @ucode_type: indicator of loaded ucode image
|
||||
* @notif_waits: things waiting for notification
|
||||
* @notif_wait_lock: lock protecting notification
|
||||
* @notif_waitq: head of notification wait queue
|
||||
*/
|
||||
struct iwl_shared {
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
@ -300,6 +350,14 @@ struct iwl_shared {
|
||||
struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT];
|
||||
|
||||
wait_queue_head_t wait_command_queue;
|
||||
|
||||
/* ucode related variables */
|
||||
enum iwl_ucode_type ucode_type;
|
||||
|
||||
/* notification wait support */
|
||||
struct list_head notif_waits;
|
||||
spinlock_t notif_wait_lock;
|
||||
wait_queue_head_t notif_waitq;
|
||||
};
|
||||
|
||||
/*Whatever _m is (iwl_trans, iwl_priv, iwl_bus, these macros will work */
|
||||
@ -443,6 +501,24 @@ bool iwl_check_for_ct_kill(struct iwl_priv *priv);
|
||||
void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac);
|
||||
void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac);
|
||||
|
||||
/* notification wait support */
|
||||
void iwl_abort_notification_waits(struct iwl_shared *shrd);
|
||||
void __acquires(wait_entry)
|
||||
iwl_init_notification_wait(struct iwl_shared *shrd,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
u8 cmd,
|
||||
void (*fn)(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt,
|
||||
void *data),
|
||||
void *fn_data);
|
||||
int __must_check __releases(wait_entry)
|
||||
iwl_wait_notification(struct iwl_shared *shrd,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
unsigned long timeout);
|
||||
void __releases(wait_entry)
|
||||
iwl_remove_notification(struct iwl_shared *shrd,
|
||||
struct iwl_notification_wait *wait_entry);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
void iwl_reset_traffic_log(struct iwl_priv *priv);
|
||||
#endif /* CONFIG_IWLWIFI_DEBUGFS */
|
||||
|
@ -106,6 +106,10 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
|
||||
[IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
|
||||
|
||||
[IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, },
|
||||
|
||||
[IWL_TM_ATTR_SRAM_ADDR] = { .type = NLA_U32, },
|
||||
[IWL_TM_ATTR_SRAM_SIZE] = { .type = NLA_U32, },
|
||||
[IWL_TM_ATTR_SRAM_DUMP] = { .type = NLA_UNSPEC, },
|
||||
};
|
||||
|
||||
/*
|
||||
@ -177,6 +181,18 @@ void iwl_testmode_init(struct iwl_priv *priv)
|
||||
{
|
||||
priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
|
||||
priv->testmode_trace.trace_enabled = false;
|
||||
priv->testmode_sram.sram_readed = false;
|
||||
}
|
||||
|
||||
static void iwl_sram_cleanup(struct iwl_priv *priv)
|
||||
{
|
||||
if (priv->testmode_sram.sram_readed) {
|
||||
kfree(priv->testmode_sram.buff_addr);
|
||||
priv->testmode_sram.buff_addr = NULL;
|
||||
priv->testmode_sram.buff_size = 0;
|
||||
priv->testmode_sram.num_chunks = 0;
|
||||
priv->testmode_sram.sram_readed = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_trace_cleanup(struct iwl_priv *priv)
|
||||
@ -201,6 +217,7 @@ static void iwl_trace_cleanup(struct iwl_priv *priv)
|
||||
void iwl_testmode_cleanup(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_trace_cleanup(priv);
|
||||
iwl_sram_cleanup(priv);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -356,7 +373,7 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
|
||||
struct iwl_notification_wait calib_wait;
|
||||
int ret;
|
||||
|
||||
iwlagn_init_notification_wait(priv, &calib_wait,
|
||||
iwl_init_notification_wait(priv->shrd, &calib_wait,
|
||||
CALIBRATION_COMPLETE_NOTIFICATION,
|
||||
NULL, NULL);
|
||||
ret = iwlagn_init_alive_start(priv);
|
||||
@ -366,14 +383,14 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
|
||||
goto cfg_init_calib_error;
|
||||
}
|
||||
|
||||
ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ);
|
||||
ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ);
|
||||
if (ret)
|
||||
IWL_DEBUG_INFO(priv, "Error detecting"
|
||||
" CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
|
||||
return ret;
|
||||
|
||||
cfg_init_calib_error:
|
||||
iwlagn_remove_notification(priv, &calib_wait);
|
||||
iwl_remove_notification(priv->shrd, &calib_wait);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -446,6 +463,21 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
|
||||
"Error starting the device: %d\n", status);
|
||||
break;
|
||||
|
||||
case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
|
||||
iwl_scan_cancel_timeout(priv, 200);
|
||||
iwl_trans_stop_device(trans(priv));
|
||||
status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
|
||||
if (status) {
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"Error loading WOWLAN ucode: %d\n", status);
|
||||
break;
|
||||
}
|
||||
status = iwl_alive_start(priv);
|
||||
if (status)
|
||||
IWL_DEBUG_INFO(priv,
|
||||
"Error starting the device: %d\n", status);
|
||||
break;
|
||||
|
||||
case IWL_TM_CMD_APP2DEV_GET_EEPROM:
|
||||
if (priv->eeprom) {
|
||||
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
|
||||
@ -558,7 +590,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
|
||||
}
|
||||
priv->testmode_trace.num_chunks =
|
||||
DIV_ROUND_UP(priv->testmode_trace.buff_size,
|
||||
TRACE_CHUNK_SIZE);
|
||||
DUMP_CHUNK_SIZE);
|
||||
break;
|
||||
|
||||
case IWL_TM_CMD_APP2DEV_END_TRACE:
|
||||
@ -590,15 +622,15 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb,
|
||||
idx = cb->args[4];
|
||||
if (idx >= priv->testmode_trace.num_chunks)
|
||||
return -ENOENT;
|
||||
length = TRACE_CHUNK_SIZE;
|
||||
length = DUMP_CHUNK_SIZE;
|
||||
if (((idx + 1) == priv->testmode_trace.num_chunks) &&
|
||||
(priv->testmode_trace.buff_size % TRACE_CHUNK_SIZE))
|
||||
(priv->testmode_trace.buff_size % DUMP_CHUNK_SIZE))
|
||||
length = priv->testmode_trace.buff_size %
|
||||
TRACE_CHUNK_SIZE;
|
||||
DUMP_CHUNK_SIZE;
|
||||
|
||||
NLA_PUT(skb, IWL_TM_ATTR_TRACE_DUMP, length,
|
||||
priv->testmode_trace.trace_addr +
|
||||
(TRACE_CHUNK_SIZE * idx));
|
||||
(DUMP_CHUNK_SIZE * idx));
|
||||
idx++;
|
||||
cb->args[4] = idx;
|
||||
return 0;
|
||||
@ -644,6 +676,110 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the user application commands for SRAM data dump
|
||||
*
|
||||
* It retrieves the mandatory fields IWL_TM_ATTR_SRAM_ADDR and
|
||||
* IWL_TM_ATTR_SRAM_SIZE to decide the memory area for SRAM data reading
|
||||
*
|
||||
* Several error will be retured, -EBUSY if the SRAM data retrieved by
|
||||
* previous command has not been delivered to userspace, or -ENOMSG if
|
||||
* the mandatory fields (IWL_TM_ATTR_SRAM_ADDR,IWL_TM_ATTR_SRAM_SIZE)
|
||||
* are missing, or -ENOMEM if the buffer allocation fails.
|
||||
*
|
||||
* Otherwise 0 is replied indicating the success of the SRAM reading.
|
||||
*
|
||||
* @hw: ieee80211_hw object that represents the device
|
||||
* @tb: gnl message fields from the user space
|
||||
*/
|
||||
static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
u32 base, ofs, size, maxsize;
|
||||
|
||||
if (priv->testmode_sram.sram_readed)
|
||||
return -EBUSY;
|
||||
|
||||
if (!tb[IWL_TM_ATTR_SRAM_ADDR]) {
|
||||
IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n");
|
||||
return -ENOMSG;
|
||||
}
|
||||
ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]);
|
||||
if (!tb[IWL_TM_ATTR_SRAM_SIZE]) {
|
||||
IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n");
|
||||
return -ENOMSG;
|
||||
}
|
||||
size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]);
|
||||
switch (priv->shrd->ucode_type) {
|
||||
case IWL_UCODE_REGULAR:
|
||||
maxsize = trans(priv)->ucode_rt.data.len;
|
||||
break;
|
||||
case IWL_UCODE_INIT:
|
||||
maxsize = trans(priv)->ucode_init.data.len;
|
||||
break;
|
||||
case IWL_UCODE_WOWLAN:
|
||||
maxsize = trans(priv)->ucode_wowlan.data.len;
|
||||
break;
|
||||
case IWL_UCODE_NONE:
|
||||
IWL_DEBUG_INFO(priv, "Error, uCode does not been loaded\n");
|
||||
return -ENOSYS;
|
||||
default:
|
||||
IWL_DEBUG_INFO(priv, "Error, unsupported uCode type\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
if ((ofs + size) > maxsize) {
|
||||
IWL_DEBUG_INFO(priv, "Invalid offset/size: out of range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
priv->testmode_sram.buff_size = (size / 4) * 4;
|
||||
priv->testmode_sram.buff_addr =
|
||||
kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL);
|
||||
if (priv->testmode_sram.buff_addr == NULL) {
|
||||
IWL_DEBUG_INFO(priv, "Error allocating memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
base = 0x800000;
|
||||
_iwl_read_targ_mem_words(bus(priv), base + ofs,
|
||||
priv->testmode_sram.buff_addr,
|
||||
priv->testmode_sram.buff_size / 4);
|
||||
priv->testmode_sram.num_chunks =
|
||||
DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE);
|
||||
priv->testmode_sram.sram_readed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_testmode_sram_dump(struct ieee80211_hw *hw, struct nlattr **tb,
|
||||
struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
int idx, length;
|
||||
|
||||
if (priv->testmode_sram.sram_readed) {
|
||||
idx = cb->args[4];
|
||||
if (idx >= priv->testmode_sram.num_chunks) {
|
||||
iwl_sram_cleanup(priv);
|
||||
return -ENOENT;
|
||||
}
|
||||
length = DUMP_CHUNK_SIZE;
|
||||
if (((idx + 1) == priv->testmode_sram.num_chunks) &&
|
||||
(priv->testmode_sram.buff_size % DUMP_CHUNK_SIZE))
|
||||
length = priv->testmode_sram.buff_size %
|
||||
DUMP_CHUNK_SIZE;
|
||||
|
||||
NLA_PUT(skb, IWL_TM_ATTR_SRAM_DUMP, length,
|
||||
priv->testmode_sram.buff_addr +
|
||||
(DUMP_CHUNK_SIZE * idx));
|
||||
idx++;
|
||||
cb->args[4] = idx;
|
||||
return 0;
|
||||
} else
|
||||
return -EFAULT;
|
||||
|
||||
nla_put_failure:
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
|
||||
/* The testmode gnl message handler that takes the gnl message from the
|
||||
* user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
|
||||
@ -705,6 +841,7 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
|
||||
case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
|
||||
case IWL_TM_CMD_APP2DEV_GET_EEPROM:
|
||||
case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
|
||||
case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
|
||||
IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
|
||||
result = iwl_testmode_driver(hw, tb);
|
||||
break;
|
||||
@ -721,6 +858,11 @@ int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
|
||||
result = iwl_testmode_ownership(hw, tb);
|
||||
break;
|
||||
|
||||
case IWL_TM_CMD_APP2DEV_READ_SRAM:
|
||||
IWL_DEBUG_INFO(priv, "testmode sram read cmd to driver\n");
|
||||
result = iwl_testmode_sram(hw, tb);
|
||||
break;
|
||||
|
||||
default:
|
||||
IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
|
||||
result = -ENOSYS;
|
||||
@ -769,6 +911,10 @@ int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");
|
||||
result = iwl_testmode_trace_dump(hw, tb, skb, cb);
|
||||
break;
|
||||
case IWL_TM_CMD_APP2DEV_DUMP_SRAM:
|
||||
IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n");
|
||||
result = iwl_testmode_sram_dump(hw, tb, skb, cb);
|
||||
break;
|
||||
default:
|
||||
result = -EINVAL;
|
||||
break;
|
@ -103,14 +103,22 @@
|
||||
* @IWL_TM_CMD_DEV2APP_EEPROM_RSP:
|
||||
* commands from kernel space to carry the eeprom response
|
||||
* to user application
|
||||
*
|
||||
* @IWL_TM_CMD_APP2DEV_OWNERSHIP:
|
||||
* commands from user application to own change the ownership of the uCode
|
||||
* if application has the ownership, the only host command from
|
||||
* testmode will deliver to uCode. Default owner is driver
|
||||
*
|
||||
* @IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32:
|
||||
* @IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32:
|
||||
* commands from user applicaiton to indirectly access peripheral register
|
||||
*
|
||||
* @IWL_TM_CMD_APP2DEV_READ_SRAM:
|
||||
* @IWL_TM_CMD_APP2DEV_DUMP_SRAM:
|
||||
* commands from user applicaiton to read data in sram
|
||||
*
|
||||
* @IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW: load Weak On Wireless LAN uCode image
|
||||
*
|
||||
*/
|
||||
enum iwl_tm_cmd_t {
|
||||
IWL_TM_CMD_APP2DEV_UCODE = 1,
|
||||
@ -132,7 +140,10 @@ enum iwl_tm_cmd_t {
|
||||
IWL_TM_CMD_APP2DEV_OWNERSHIP = 17,
|
||||
IWL_TM_CMD_APP2DEV_INDIRECT_REG_READ32 = 18,
|
||||
IWL_TM_CMD_APP2DEV_INDIRECT_REG_WRITE32 = 19,
|
||||
IWL_TM_CMD_MAX = 20,
|
||||
IWL_TM_CMD_APP2DEV_READ_SRAM = 20,
|
||||
IWL_TM_CMD_APP2DEV_DUMP_SRAM = 21,
|
||||
IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW = 22,
|
||||
IWL_TM_CMD_MAX = 23,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -202,6 +213,18 @@ enum iwl_tm_cmd_t {
|
||||
* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_OWNERSHIP,
|
||||
* The mandatory fields are:
|
||||
* IWL_TM_ATTR_UCODE_OWNER for the new owner
|
||||
*
|
||||
* @IWL_TM_ATTR_SRAM_ADDR:
|
||||
* @IWL_TM_ATTR_SRAM_SIZE:
|
||||
* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_READ_SRAM,
|
||||
* The mandatory fields are:
|
||||
* IWL_TM_ATTR_SRAM_ADDR for the address in sram
|
||||
* IWL_TM_ATTR_SRAM_SIZE for the buffer size of data reading
|
||||
*
|
||||
* @IWL_TM_ATTR_SRAM_DUMP:
|
||||
* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_DUMP_SRAM,
|
||||
* IWL_TM_ATTR_SRAM_DUMP for the data in sram
|
||||
*
|
||||
*/
|
||||
enum iwl_tm_attr_t {
|
||||
IWL_TM_ATTR_NOT_APPLICABLE = 0,
|
||||
@ -219,7 +242,10 @@ enum iwl_tm_attr_t {
|
||||
IWL_TM_ATTR_TRACE_DUMP = 12,
|
||||
IWL_TM_ATTR_FIXRATE = 13,
|
||||
IWL_TM_ATTR_UCODE_OWNER = 14,
|
||||
IWL_TM_ATTR_MAX = 15,
|
||||
IWL_TM_ATTR_SRAM_ADDR = 15,
|
||||
IWL_TM_ATTR_SRAM_SIZE = 16,
|
||||
IWL_TM_ATTR_SRAM_DUMP = 17,
|
||||
IWL_TM_ATTR_MAX = 18,
|
||||
};
|
||||
|
||||
/* uCode trace buffer */
|
||||
@ -227,6 +253,8 @@ enum iwl_tm_attr_t {
|
||||
#define TRACE_BUFF_SIZE_MIN 0x20000
|
||||
#define TRACE_BUFF_SIZE_DEF TRACE_BUFF_SIZE_MIN
|
||||
#define TRACE_BUFF_PADD 0x2000
|
||||
#define TRACE_CHUNK_SIZE (PAGE_SIZE - 1024)
|
||||
|
||||
/* Maximum data size of each dump it packet */
|
||||
#define DUMP_CHUNK_SIZE (PAGE_SIZE - 1024)
|
||||
|
||||
#endif
|
||||
|
@ -595,7 +595,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans)
|
||||
IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
base = priv->device_pointers.error_event_table;
|
||||
if (priv->ucode_type == IWL_UCODE_INIT) {
|
||||
if (trans->shrd->ucode_type == IWL_UCODE_INIT) {
|
||||
if (!base)
|
||||
base = priv->init_errlog_ptr;
|
||||
} else {
|
||||
@ -607,7 +607,7 @@ static void iwl_dump_nic_error_log(struct iwl_trans *trans)
|
||||
IWL_ERR(trans,
|
||||
"Not valid error log pointer 0x%08X for %s uCode\n",
|
||||
base,
|
||||
(priv->ucode_type == IWL_UCODE_INIT)
|
||||
(trans->shrd->ucode_type == IWL_UCODE_INIT)
|
||||
? "Init" : "RT");
|
||||
return;
|
||||
}
|
||||
@ -710,7 +710,7 @@ static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx,
|
||||
return pos;
|
||||
|
||||
base = priv->device_pointers.log_event_table;
|
||||
if (priv->ucode_type == IWL_UCODE_INIT) {
|
||||
if (trans->shrd->ucode_type == IWL_UCODE_INIT) {
|
||||
if (!base)
|
||||
base = priv->init_evtlog_ptr;
|
||||
} else {
|
||||
@ -824,7 +824,7 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log,
|
||||
struct iwl_priv *priv = priv(trans);
|
||||
|
||||
base = priv->device_pointers.log_event_table;
|
||||
if (priv->ucode_type == IWL_UCODE_INIT) {
|
||||
if (trans->shrd->ucode_type == IWL_UCODE_INIT) {
|
||||
logsize = priv->init_evtlog_size;
|
||||
if (!base)
|
||||
base = priv->init_evtlog_ptr;
|
||||
@ -838,7 +838,7 @@ int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log,
|
||||
IWL_ERR(trans,
|
||||
"Invalid event log pointer 0x%08X for %s uCode\n",
|
||||
base,
|
||||
(priv->ucode_type == IWL_UCODE_INIT)
|
||||
(trans->shrd->ucode_type == IWL_UCODE_INIT)
|
||||
? "Init" : "RT");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -220,13 +220,6 @@ struct fw_img {
|
||||
struct fw_desc data; /* firmware data image */
|
||||
};
|
||||
|
||||
enum iwl_ucode_type {
|
||||
IWL_UCODE_NONE,
|
||||
IWL_UCODE_REGULAR,
|
||||
IWL_UCODE_INIT,
|
||||
IWL_UCODE_WOWLAN,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_trans - transport common data
|
||||
* @ops - pointer to iwl_trans_ops
|
||||
|
@ -122,7 +122,7 @@ int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc,
|
||||
/*
|
||||
* ucode
|
||||
*/
|
||||
static int iwlagn_load_section(struct iwl_trans *trans, const char *name,
|
||||
static int iwl_load_section(struct iwl_trans *trans, const char *name,
|
||||
struct fw_desc *image, u32 dst_addr)
|
||||
{
|
||||
struct iwl_bus *bus = bus(trans);
|
||||
@ -188,7 +188,7 @@ static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int iwlagn_load_given_ucode(struct iwl_trans *trans,
|
||||
static int iwl_load_given_ucode(struct iwl_trans *trans,
|
||||
enum iwl_ucode_type ucode_type)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -201,19 +201,19 @@ static int iwlagn_load_given_ucode(struct iwl_trans *trans,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = iwlagn_load_section(trans, "INST", &image->code,
|
||||
ret = iwl_load_section(trans, "INST", &image->code,
|
||||
IWLAGN_RTC_INST_LOWER_BOUND);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return iwlagn_load_section(trans, "DATA", &image->data,
|
||||
return iwl_load_section(trans, "DATA", &image->data,
|
||||
IWLAGN_RTC_DATA_LOWER_BOUND);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calibration
|
||||
*/
|
||||
static int iwlagn_set_Xtal_calib(struct iwl_priv *priv)
|
||||
static int iwl_set_Xtal_calib(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_calib_xtal_freq_cmd cmd;
|
||||
__le16 *xtal_calib =
|
||||
@ -225,7 +225,7 @@ static int iwlagn_set_Xtal_calib(struct iwl_priv *priv)
|
||||
return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv)
|
||||
static int iwl_set_temperature_offset_calib(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_calib_temperature_offset_cmd cmd;
|
||||
__le16 *offset_calib =
|
||||
@ -242,7 +242,7 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv)
|
||||
return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
static int iwlagn_set_temperature_offset_calib_v2(struct iwl_priv *priv)
|
||||
static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_calib_temperature_offset_v2_cmd cmd;
|
||||
__le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv,
|
||||
@ -277,7 +277,7 @@ static int iwlagn_set_temperature_offset_calib_v2(struct iwl_priv *priv)
|
||||
return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
|
||||
static int iwl_send_calib_cfg(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_calib_cfg_cmd calib_cfg_cmd;
|
||||
struct iwl_host_cmd cmd = {
|
||||
@ -293,7 +293,7 @@ static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
|
||||
calib_cfg_cmd.ucd_calib_cfg.flags =
|
||||
IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK;
|
||||
|
||||
return iwl_trans_send_cmd(trans(priv), &cmd);
|
||||
return iwl_trans_send_cmd(trans, &cmd);
|
||||
}
|
||||
|
||||
int iwlagn_rx_calib_result(struct iwl_priv *priv,
|
||||
@ -326,14 +326,14 @@ int iwlagn_init_alive_start(struct iwl_priv *priv)
|
||||
* no need to close the envlope since we are going
|
||||
* to load the runtime uCode later.
|
||||
*/
|
||||
ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
|
||||
ret = iwl_send_bt_env(trans(priv), IWL_BT_COEX_ENV_OPEN,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
ret = iwlagn_send_calib_cfg(priv);
|
||||
ret = iwl_send_calib_cfg(trans(priv));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -343,15 +343,15 @@ int iwlagn_init_alive_start(struct iwl_priv *priv)
|
||||
*/
|
||||
if (priv->cfg->need_temp_offset_calib) {
|
||||
if (priv->cfg->temp_offset_v2)
|
||||
return iwlagn_set_temperature_offset_calib_v2(priv);
|
||||
return iwl_set_temperature_offset_calib_v2(priv);
|
||||
else
|
||||
return iwlagn_set_temperature_offset_calib(priv);
|
||||
return iwl_set_temperature_offset_calib(priv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
|
||||
static int iwl_send_wimax_coex(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_wimax_coex_cmd coex_cmd;
|
||||
|
||||
@ -379,7 +379,7 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
|
||||
sizeof(coex_cmd), &coex_cmd);
|
||||
}
|
||||
|
||||
static const u8 iwlagn_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
|
||||
static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
|
||||
((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
|
||||
(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
|
||||
((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
|
||||
@ -401,42 +401,42 @@ static const u8 iwlagn_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
|
||||
0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
void iwlagn_send_prio_tbl(struct iwl_priv *priv)
|
||||
void iwl_send_prio_tbl(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
|
||||
|
||||
memcpy(prio_tbl_cmd.prio_tbl, iwlagn_bt_prio_tbl,
|
||||
sizeof(iwlagn_bt_prio_tbl));
|
||||
if (iwl_trans_send_cmd_pdu(trans(priv),
|
||||
memcpy(prio_tbl_cmd.prio_tbl, iwl_bt_prio_tbl,
|
||||
sizeof(iwl_bt_prio_tbl));
|
||||
if (iwl_trans_send_cmd_pdu(trans,
|
||||
REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC,
|
||||
sizeof(prio_tbl_cmd), &prio_tbl_cmd))
|
||||
IWL_ERR(priv, "failed to send BT prio tbl command\n");
|
||||
IWL_ERR(trans, "failed to send BT prio tbl command\n");
|
||||
}
|
||||
|
||||
int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
|
||||
int iwl_send_bt_env(struct iwl_trans *trans, u8 action, u8 type)
|
||||
{
|
||||
struct iwl_bt_coex_prot_env_cmd env_cmd;
|
||||
int ret;
|
||||
|
||||
env_cmd.action = action;
|
||||
env_cmd.type = type;
|
||||
ret = iwl_trans_send_cmd_pdu(trans(priv),
|
||||
ret = iwl_trans_send_cmd_pdu(trans,
|
||||
REPLY_BT_COEX_PROT_ENV, CMD_SYNC,
|
||||
sizeof(env_cmd), &env_cmd);
|
||||
if (ret)
|
||||
IWL_ERR(priv, "failed to send BT env command\n");
|
||||
IWL_ERR(trans, "failed to send BT env command\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int iwlagn_alive_notify(struct iwl_priv *priv)
|
||||
static int iwl_alive_notify(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl_rxon_context *ctx;
|
||||
int ret;
|
||||
|
||||
if (!priv->tx_cmd_pool)
|
||||
priv->tx_cmd_pool =
|
||||
kmem_cache_create("iwlagn_dev_cmd",
|
||||
kmem_cache_create("iwl_dev_cmd",
|
||||
sizeof(struct iwl_device_cmd),
|
||||
sizeof(void *), 0, NULL);
|
||||
|
||||
@ -447,12 +447,12 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
|
||||
for_each_context(priv, ctx)
|
||||
ctx->last_tx_rejected = false;
|
||||
|
||||
ret = iwlagn_send_wimax_coex(priv);
|
||||
ret = iwl_send_wimax_coex(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!priv->cfg->no_xtal_calib) {
|
||||
ret = iwlagn_set_Xtal_calib(priv);
|
||||
ret = iwl_set_Xtal_calib(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -548,7 +548,7 @@ struct iwlagn_alive_data {
|
||||
u8 subtype;
|
||||
};
|
||||
|
||||
static void iwlagn_alive_fn(struct iwl_priv *priv,
|
||||
static void iwl_alive_fn(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt,
|
||||
void *data)
|
||||
{
|
||||
@ -571,6 +571,70 @@ static void iwlagn_alive_fn(struct iwl_priv *priv,
|
||||
alive_data->valid = palive->is_valid == UCODE_VALID_OK;
|
||||
}
|
||||
|
||||
/* notification wait support */
|
||||
void iwl_init_notification_wait(struct iwl_shared *shrd,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
u8 cmd,
|
||||
void (*fn)(struct iwl_priv *priv,
|
||||
struct iwl_rx_packet *pkt,
|
||||
void *data),
|
||||
void *fn_data)
|
||||
{
|
||||
wait_entry->fn = fn;
|
||||
wait_entry->fn_data = fn_data;
|
||||
wait_entry->cmd = cmd;
|
||||
wait_entry->triggered = false;
|
||||
wait_entry->aborted = false;
|
||||
|
||||
spin_lock_bh(&shrd->notif_wait_lock);
|
||||
list_add(&wait_entry->list, &shrd->notif_waits);
|
||||
spin_unlock_bh(&shrd->notif_wait_lock);
|
||||
}
|
||||
|
||||
int iwl_wait_notification(struct iwl_shared *shrd,
|
||||
struct iwl_notification_wait *wait_entry,
|
||||
unsigned long timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wait_event_timeout(shrd->notif_waitq,
|
||||
wait_entry->triggered || wait_entry->aborted,
|
||||
timeout);
|
||||
|
||||
spin_lock_bh(&shrd->notif_wait_lock);
|
||||
list_del(&wait_entry->list);
|
||||
spin_unlock_bh(&shrd->notif_wait_lock);
|
||||
|
||||
if (wait_entry->aborted)
|
||||
return -EIO;
|
||||
|
||||
/* return value is always >= 0 */
|
||||
if (ret <= 0)
|
||||
return -ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iwl_remove_notification(struct iwl_shared *shrd,
|
||||
struct iwl_notification_wait *wait_entry)
|
||||
{
|
||||
spin_lock_bh(&shrd->notif_wait_lock);
|
||||
list_del(&wait_entry->list);
|
||||
spin_unlock_bh(&shrd->notif_wait_lock);
|
||||
}
|
||||
|
||||
void iwl_abort_notification_waits(struct iwl_shared *shrd)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct iwl_notification_wait *wait_entry;
|
||||
|
||||
spin_lock_irqsave(&shrd->notif_wait_lock, flags);
|
||||
list_for_each_entry(wait_entry, &shrd->notif_waits, list)
|
||||
wait_entry->aborted = true;
|
||||
spin_unlock_irqrestore(&shrd->notif_wait_lock, flags);
|
||||
|
||||
wake_up_all(&shrd->notif_waitq);
|
||||
}
|
||||
|
||||
#define UCODE_ALIVE_TIMEOUT HZ
|
||||
#define UCODE_CALIB_TIMEOUT (2*HZ)
|
||||
|
||||
@ -579,41 +643,43 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
|
||||
{
|
||||
struct iwl_notification_wait alive_wait;
|
||||
struct iwlagn_alive_data alive_data;
|
||||
struct iwl_trans *trans = trans(priv);
|
||||
int ret;
|
||||
enum iwl_ucode_type old_type;
|
||||
|
||||
ret = iwl_trans_start_device(trans(priv));
|
||||
ret = iwl_trans_start_device(trans);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE,
|
||||
iwlagn_alive_fn, &alive_data);
|
||||
iwl_init_notification_wait(trans->shrd, &alive_wait, REPLY_ALIVE,
|
||||
iwl_alive_fn, &alive_data);
|
||||
|
||||
old_type = priv->ucode_type;
|
||||
priv->ucode_type = ucode_type;
|
||||
old_type = trans->shrd->ucode_type;
|
||||
trans->shrd->ucode_type = ucode_type;
|
||||
|
||||
ret = iwlagn_load_given_ucode(trans(priv), ucode_type);
|
||||
ret = iwl_load_given_ucode(trans, ucode_type);
|
||||
if (ret) {
|
||||
priv->ucode_type = old_type;
|
||||
iwlagn_remove_notification(priv, &alive_wait);
|
||||
trans->shrd->ucode_type = old_type;
|
||||
iwl_remove_notification(trans->shrd, &alive_wait);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iwl_trans_kick_nic(trans(priv));
|
||||
iwl_trans_kick_nic(trans);
|
||||
|
||||
/*
|
||||
* Some things may run in the background now, but we
|
||||
* just wait for the ALIVE notification here.
|
||||
*/
|
||||
ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT);
|
||||
ret = iwl_wait_notification(trans->shrd, &alive_wait,
|
||||
UCODE_ALIVE_TIMEOUT);
|
||||
if (ret) {
|
||||
priv->ucode_type = old_type;
|
||||
trans->shrd->ucode_type = old_type;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!alive_data.valid) {
|
||||
IWL_ERR(priv, "Loaded ucode is not valid!\n");
|
||||
priv->ucode_type = old_type;
|
||||
trans->shrd->ucode_type = old_type;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -623,9 +689,9 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
|
||||
* skip it for WoWLAN.
|
||||
*/
|
||||
if (ucode_type != IWL_UCODE_WOWLAN) {
|
||||
ret = iwl_verify_ucode(trans(priv), ucode_type);
|
||||
ret = iwl_verify_ucode(trans, ucode_type);
|
||||
if (ret) {
|
||||
priv->ucode_type = old_type;
|
||||
trans->shrd->ucode_type = old_type;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -633,11 +699,11 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
|
||||
msleep(5);
|
||||
}
|
||||
|
||||
ret = iwlagn_alive_notify(priv);
|
||||
ret = iwl_alive_notify(priv);
|
||||
if (ret) {
|
||||
IWL_WARN(priv,
|
||||
"Could not complete ALIVE transition: %d\n", ret);
|
||||
priv->ucode_type = old_type;
|
||||
trans->shrd->ucode_type = old_type;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -655,10 +721,10 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
|
||||
if (!trans(priv)->ucode_init.code.len)
|
||||
return 0;
|
||||
|
||||
if (priv->ucode_type != IWL_UCODE_NONE)
|
||||
if (priv->shrd->ucode_type != IWL_UCODE_NONE)
|
||||
return 0;
|
||||
|
||||
iwlagn_init_notification_wait(priv, &calib_wait,
|
||||
iwl_init_notification_wait(priv->shrd, &calib_wait,
|
||||
CALIBRATION_COMPLETE_NOTIFICATION,
|
||||
NULL, NULL);
|
||||
|
||||
@ -675,12 +741,13 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
|
||||
* Some things may run in the background now, but we
|
||||
* just wait for the calibration complete notification.
|
||||
*/
|
||||
ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT);
|
||||
ret = iwl_wait_notification(priv->shrd, &calib_wait,
|
||||
UCODE_CALIB_TIMEOUT);
|
||||
|
||||
goto out;
|
||||
|
||||
error:
|
||||
iwlagn_remove_notification(priv, &calib_wait);
|
||||
iwl_remove_notification(priv->shrd, &calib_wait);
|
||||
out:
|
||||
/* Whatever happened, stop the device */
|
||||
iwl_trans_stop_device(trans(priv));
|
@ -831,11 +831,11 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
|
||||
if (spec->supported_rates & SUPPORT_RATE_OFDM)
|
||||
num_rates += 8;
|
||||
|
||||
channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL);
|
||||
channels = kcalloc(spec->num_channels, sizeof(*channels), GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
rates = kzalloc(sizeof(*rates) * num_rates, GFP_KERNEL);
|
||||
rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL);
|
||||
if (!rates)
|
||||
goto exit_free_channels;
|
||||
|
||||
|
@ -262,10 +262,10 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
|
||||
u32 fwsize;
|
||||
enum version_8192c version = rtlhal->version;
|
||||
|
||||
pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
|
||||
if (!rtlhal->pfirmware)
|
||||
return 1;
|
||||
|
||||
pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
|
||||
pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
|
||||
pfwdata = (u8 *) rtlhal->pfirmware;
|
||||
fwsize = rtlhal->fwsize;
|
||||
|
@ -42,16 +42,6 @@ config WL12XX_SDIO
|
||||
If you choose to build a module, it'll be called wl12xx_sdio.
|
||||
Say N if unsure.
|
||||
|
||||
config WL12XX_SDIO_TEST
|
||||
tristate "TI wl12xx SDIO testing support"
|
||||
depends on WL12XX && MMC && WL12XX_SDIO
|
||||
default n
|
||||
---help---
|
||||
This module adds support for the SDIO bus testing with the
|
||||
TI wl12xx chipsets. You probably don't want this unless you are
|
||||
testing a new hardware platform. Select this if you want to test the
|
||||
SDIO bus which is connected to the wl12xx chip.
|
||||
|
||||
config WL12XX_PLATFORM_DATA
|
||||
bool
|
||||
depends on WL12XX_SDIO != n || WL1251_SDIO != n
|
||||
|
@ -3,14 +3,11 @@ wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
|
||||
|
||||
wl12xx_spi-objs = spi.o
|
||||
wl12xx_sdio-objs = sdio.o
|
||||
wl12xx_sdio_test-objs = sdio_test.o
|
||||
|
||||
wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
obj-$(CONFIG_WL12XX) += wl12xx.o
|
||||
obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o
|
||||
obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o
|
||||
|
||||
obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o
|
||||
|
||||
# small builtin driver bit
|
||||
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
|
||||
|
@ -29,11 +29,12 @@
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "wl12xx_80211.h"
|
||||
#include "reg.h"
|
||||
#include "ps.h"
|
||||
|
||||
int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
|
||||
int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_wake_up_condition *wake_up;
|
||||
int ret;
|
||||
@ -46,7 +47,7 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wake_up->role_id = wl->role_id;
|
||||
wake_up->role_id = wlvif->role_id;
|
||||
wake_up->wake_up_event = wl->conf.conn.wake_up_event;
|
||||
wake_up->listen_interval = wl->conf.conn.listen_interval;
|
||||
|
||||
@ -84,7 +85,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, int power)
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
int power)
|
||||
{
|
||||
struct acx_current_tx_power *acx;
|
||||
int ret;
|
||||
@ -100,7 +102,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->current_tx_power = power * 10;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
|
||||
@ -114,7 +116,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_feature_cfg(struct wl1271 *wl)
|
||||
int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_feature_config *feature;
|
||||
int ret;
|
||||
@ -128,7 +130,7 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl)
|
||||
}
|
||||
|
||||
/* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
|
||||
feature->role_id = wl->role_id;
|
||||
feature->role_id = wlvif->role_id;
|
||||
feature->data_flow_options = 0;
|
||||
feature->options = 0;
|
||||
|
||||
@ -210,7 +212,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
|
||||
int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_slot_type slot_time)
|
||||
{
|
||||
struct acx_slot *slot;
|
||||
int ret;
|
||||
@ -223,7 +226,7 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
|
||||
goto out;
|
||||
}
|
||||
|
||||
slot->role_id = wl->role_id;
|
||||
slot->role_id = wlvif->role_id;
|
||||
slot->wone_index = STATION_WONE_INDEX;
|
||||
slot->slot_time = slot_time;
|
||||
|
||||
@ -238,8 +241,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
|
||||
void *mc_list, u32 mc_list_len)
|
||||
int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable, void *mc_list, u32 mc_list_len)
|
||||
{
|
||||
struct acx_dot11_grp_addr_tbl *acx;
|
||||
int ret;
|
||||
@ -253,7 +256,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
|
||||
}
|
||||
|
||||
/* MAC filtering */
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->enabled = enable;
|
||||
acx->num_groups = mc_list_len;
|
||||
memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);
|
||||
@ -270,7 +273,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_service_period_timeout(struct wl1271 *wl)
|
||||
int wl1271_acx_service_period_timeout(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_rx_timeout *rx_timeout;
|
||||
int ret;
|
||||
@ -283,7 +287,7 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl)
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx service period timeout");
|
||||
|
||||
rx_timeout->role_id = wl->role_id;
|
||||
rx_timeout->role_id = wlvif->role_id;
|
||||
rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout);
|
||||
rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout);
|
||||
|
||||
@ -300,7 +304,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
|
||||
int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u32 rts_threshold)
|
||||
{
|
||||
struct acx_rts_threshold *rts;
|
||||
int ret;
|
||||
@ -320,7 +325,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rts->role_id = wl->role_id;
|
||||
rts->role_id = wlvif->role_id;
|
||||
rts->threshold = cpu_to_le16((u16)rts_threshold);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
|
||||
@ -363,7 +368,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
|
||||
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable_filter)
|
||||
{
|
||||
struct acx_beacon_filter_option *beacon_filter = NULL;
|
||||
int ret = 0;
|
||||
@ -380,7 +386,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
|
||||
goto out;
|
||||
}
|
||||
|
||||
beacon_filter->role_id = wl->role_id;
|
||||
beacon_filter->role_id = wlvif->role_id;
|
||||
beacon_filter->enable = enable_filter;
|
||||
|
||||
/*
|
||||
@ -401,7 +407,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
|
||||
int wl1271_acx_beacon_filter_table(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_beacon_filter_ie_table *ie_table;
|
||||
int i, idx = 0;
|
||||
@ -417,7 +424,7 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
|
||||
}
|
||||
|
||||
/* configure default beacon pass-through rules */
|
||||
ie_table->role_id = wl->role_id;
|
||||
ie_table->role_id = wlvif->role_id;
|
||||
ie_table->num_ie = 0;
|
||||
for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) {
|
||||
struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]);
|
||||
@ -458,7 +465,8 @@ out:
|
||||
|
||||
#define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff
|
||||
|
||||
int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable)
|
||||
int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
{
|
||||
struct acx_conn_monit_params *acx;
|
||||
u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE;
|
||||
@ -479,7 +487,7 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable)
|
||||
timeout = wl->conf.conn.bss_lose_timeout;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->synch_fail_thold = cpu_to_le32(threshold);
|
||||
acx->bss_lose_timeout = cpu_to_le32(timeout);
|
||||
|
||||
@ -582,7 +590,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
|
||||
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_beacon_broadcast *bb;
|
||||
int ret;
|
||||
@ -595,7 +603,7 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
bb->role_id = wl->role_id;
|
||||
bb->role_id = wlvif->role_id;
|
||||
bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout);
|
||||
bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout);
|
||||
bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps;
|
||||
@ -612,7 +620,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
|
||||
int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid)
|
||||
{
|
||||
struct acx_aid *acx_aid;
|
||||
int ret;
|
||||
@ -625,7 +633,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx_aid->role_id = wl->role_id;
|
||||
acx_aid->role_id = wlvif->role_id;
|
||||
acx_aid->aid = cpu_to_le16(aid);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
|
||||
@ -668,7 +676,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble)
|
||||
int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_preamble_type preamble)
|
||||
{
|
||||
struct acx_preamble *acx;
|
||||
int ret;
|
||||
@ -681,7 +690,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble)
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->preamble = preamble;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
|
||||
@ -695,7 +704,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl,
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_ctsprotect_type ctsprotect)
|
||||
{
|
||||
struct acx_ctsprotect *acx;
|
||||
@ -709,7 +718,7 @@ int wl1271_acx_cts_protect(struct wl1271 *wl,
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->ctsprotect = ctsprotect;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
|
||||
@ -739,7 +748,7 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct acx_rate_policy *acx;
|
||||
struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf;
|
||||
@ -755,11 +764,11 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x",
|
||||
wl->basic_rate, wl->rate_set);
|
||||
wlvif->basic_rate, wlvif->rate_set);
|
||||
|
||||
/* configure one basic rate class */
|
||||
acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE);
|
||||
acx->rate_policy.enabled_rates = cpu_to_le32(wl->basic_rate);
|
||||
acx->rate_policy_idx = cpu_to_le32(wlvif->sta.basic_rate_idx);
|
||||
acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->basic_rate);
|
||||
acx->rate_policy.short_retry_limit = c->short_retry_limit;
|
||||
acx->rate_policy.long_retry_limit = c->long_retry_limit;
|
||||
acx->rate_policy.aflags = c->aflags;
|
||||
@ -771,8 +780,8 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
|
||||
}
|
||||
|
||||
/* configure one AP supported rate class */
|
||||
acx->rate_policy_idx = cpu_to_le32(ACX_TX_AP_FULL_RATE);
|
||||
acx->rate_policy.enabled_rates = cpu_to_le32(wl->rate_set);
|
||||
acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx);
|
||||
acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->rate_set);
|
||||
acx->rate_policy.short_retry_limit = c->short_retry_limit;
|
||||
acx->rate_policy.long_retry_limit = c->long_retry_limit;
|
||||
acx->rate_policy.aflags = c->aflags;
|
||||
@ -788,7 +797,7 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
|
||||
* (p2p packets should always go out with OFDM rates, even
|
||||
* if we are currently connected to 11b AP)
|
||||
*/
|
||||
acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE_P2P);
|
||||
acx->rate_policy_idx = cpu_to_le32(wlvif->sta.p2p_rate_idx);
|
||||
acx->rate_policy.enabled_rates =
|
||||
cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P);
|
||||
acx->rate_policy.short_retry_limit = c->short_retry_limit;
|
||||
@ -839,8 +848,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
|
||||
u8 aifsn, u16 txop)
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop)
|
||||
{
|
||||
struct acx_ac_cfg *acx;
|
||||
int ret = 0;
|
||||
@ -855,7 +864,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->ac = ac;
|
||||
acx->cw_min = cw_min;
|
||||
acx->cw_max = cpu_to_le16(cw_max);
|
||||
@ -873,7 +882,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
|
||||
int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 queue_id, u8 channel_type,
|
||||
u8 tsid, u8 ps_scheme, u8 ack_policy,
|
||||
u32 apsd_conf0, u32 apsd_conf1)
|
||||
{
|
||||
@ -889,7 +899,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->queue_id = queue_id;
|
||||
acx->channel_type = channel_type;
|
||||
acx->tsid = tsid;
|
||||
@ -1098,7 +1108,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
|
||||
int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
{
|
||||
struct wl1271_acx_bet_enable *acx = NULL;
|
||||
int ret = 0;
|
||||
@ -1114,7 +1125,7 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE;
|
||||
acx->max_consecutive = wl->conf.conn.bet_max_consecutive;
|
||||
|
||||
@ -1129,7 +1140,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
|
||||
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 enable, __be32 address)
|
||||
{
|
||||
struct wl1271_acx_arp_filter *acx;
|
||||
int ret;
|
||||
@ -1142,7 +1154,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->version = ACX_IPV4_VERSION;
|
||||
acx->enable = enable;
|
||||
|
||||
@ -1189,7 +1201,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
{
|
||||
struct wl1271_acx_keep_alive_mode *acx = NULL;
|
||||
int ret = 0;
|
||||
@ -1202,7 +1215,7 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->enabled = enable;
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx));
|
||||
@ -1216,7 +1229,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
|
||||
int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 index, u8 tpl_valid)
|
||||
{
|
||||
struct wl1271_acx_keep_alive_config *acx = NULL;
|
||||
int ret = 0;
|
||||
@ -1229,7 +1243,7 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval);
|
||||
acx->index = index;
|
||||
acx->tpl_validation = tpl_valid;
|
||||
@ -1247,8 +1261,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
|
||||
s16 thold, u8 hyst)
|
||||
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable, s16 thold, u8 hyst)
|
||||
{
|
||||
struct wl1271_acx_rssi_snr_trigger *acx = NULL;
|
||||
int ret = 0;
|
||||
@ -1261,9 +1275,9 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->last_rssi_event = -1;
|
||||
wlvif->last_rssi_event = -1;
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing);
|
||||
acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON;
|
||||
acx->type = WL1271_ACX_TRIG_TYPE_EDGE;
|
||||
@ -1288,7 +1302,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
|
||||
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_acx_rssi_snr_avg_weights *acx = NULL;
|
||||
struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger;
|
||||
@ -1302,7 +1317,7 @@ int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->rssi_beacon = c->avg_weight_rssi_beacon;
|
||||
acx->rssi_data = c->avg_weight_rssi_data;
|
||||
acx->snr_beacon = c->avg_weight_snr_beacon;
|
||||
@ -1367,6 +1382,7 @@ out:
|
||||
}
|
||||
|
||||
int wl1271_acx_set_ht_information(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u16 ht_operation_mode)
|
||||
{
|
||||
struct wl1271_acx_ht_information *acx;
|
||||
@ -1380,7 +1396,7 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl,
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->ht_protection =
|
||||
(u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION);
|
||||
acx->rifs_mode = 0;
|
||||
@ -1402,7 +1418,8 @@ out:
|
||||
}
|
||||
|
||||
/* Configure BA session initiator/receiver parameters setting in the FW. */
|
||||
int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl)
|
||||
int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_acx_ba_initiator_policy *acx;
|
||||
int ret;
|
||||
@ -1416,7 +1433,7 @@ int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl)
|
||||
}
|
||||
|
||||
/* set for the current role */
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap;
|
||||
acx->win_size = wl->conf.ht.tx_ba_win_size;
|
||||
acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
|
||||
@ -1494,7 +1511,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
|
||||
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable)
|
||||
{
|
||||
struct wl1271_acx_ps_rx_streaming *rx_streaming;
|
||||
u32 conf_queues, enable_queues;
|
||||
@ -1523,7 +1541,7 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
|
||||
if (!(conf_queues & BIT(i)))
|
||||
continue;
|
||||
|
||||
rx_streaming->role_id = wl->role_id;
|
||||
rx_streaming->role_id = wlvif->role_id;
|
||||
rx_streaming->tid = i;
|
||||
rx_streaming->enable = enable_queues & BIT(i);
|
||||
rx_streaming->period = wl->conf.rx_streaming.interval;
|
||||
@ -1542,7 +1560,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
|
||||
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_acx_ap_max_tx_retry *acx = NULL;
|
||||
int ret;
|
||||
@ -1553,7 +1571,7 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
|
||||
if (!acx)
|
||||
return -ENOMEM;
|
||||
|
||||
acx->role_id = wl->role_id;
|
||||
acx->role_id = wlvif->role_id;
|
||||
acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
|
||||
@ -1567,7 +1585,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_acx_config_ps(struct wl1271 *wl)
|
||||
int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_acx_config_ps *config_ps;
|
||||
int ret;
|
||||
@ -1582,7 +1600,7 @@ int wl1271_acx_config_ps(struct wl1271 *wl)
|
||||
|
||||
config_ps->exit_retries = wl->conf.conn.psm_exit_retries;
|
||||
config_ps->enter_retries = wl->conf.conn.psm_entry_retries;
|
||||
config_ps->null_data_rate = cpu_to_le32(wl->basic_rate);
|
||||
config_ps->null_data_rate = cpu_to_le32(wlvif->basic_rate);
|
||||
|
||||
ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps,
|
||||
sizeof(*config_ps));
|
||||
|
@ -654,11 +654,6 @@ struct acx_rate_class {
|
||||
u8 reserved;
|
||||
};
|
||||
|
||||
#define ACX_TX_BASIC_RATE 0
|
||||
#define ACX_TX_AP_FULL_RATE 1
|
||||
#define ACX_TX_BASIC_RATE_P2P 2
|
||||
#define ACX_TX_AP_MODE_MGMT_RATE 4
|
||||
#define ACX_TX_AP_MODE_BCST_RATE 5
|
||||
struct acx_rate_policy {
|
||||
struct acx_header header;
|
||||
|
||||
@ -1234,39 +1229,49 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
int wl1271_acx_wake_up_conditions(struct wl1271 *wl);
|
||||
int wl1271_acx_wake_up_conditions(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, int power);
|
||||
int wl1271_acx_feature_cfg(struct wl1271 *wl);
|
||||
int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
int power);
|
||||
int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_mem_map(struct wl1271 *wl,
|
||||
struct acx_header *mem_map, size_t len);
|
||||
int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl);
|
||||
int wl1271_acx_pd_threshold(struct wl1271 *wl);
|
||||
int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time);
|
||||
int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
|
||||
void *mc_list, u32 mc_list_len);
|
||||
int wl1271_acx_service_period_timeout(struct wl1271 *wl);
|
||||
int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold);
|
||||
int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_slot_type slot_time);
|
||||
int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable, void *mc_list, u32 mc_list_len);
|
||||
int wl1271_acx_service_period_timeout(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u32 rts_threshold);
|
||||
int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
|
||||
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
|
||||
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
|
||||
int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable);
|
||||
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable_filter);
|
||||
int wl1271_acx_beacon_filter_table(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable);
|
||||
int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable);
|
||||
int wl12xx_acx_sg_cfg(struct wl1271 *wl);
|
||||
int wl1271_acx_cca_threshold(struct wl1271 *wl);
|
||||
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl);
|
||||
int wl1271_acx_aid(struct wl1271 *wl, u16 aid);
|
||||
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid);
|
||||
int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask);
|
||||
int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl,
|
||||
int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_preamble_type preamble);
|
||||
int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum acx_ctsprotect_type ctsprotect);
|
||||
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl);
|
||||
int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
|
||||
u8 idx);
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
|
||||
u8 aifsn, u16 txop);
|
||||
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
|
||||
int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop);
|
||||
int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 queue_id, u8 channel_type,
|
||||
u8 tsid, u8 ps_scheme, u8 ack_policy,
|
||||
u32 apsd_conf0, u32 apsd_conf1);
|
||||
int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
|
||||
@ -1276,26 +1281,34 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl);
|
||||
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
|
||||
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
|
||||
int wl1271_acx_smart_reflex(struct wl1271 *wl);
|
||||
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
|
||||
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address);
|
||||
int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable);
|
||||
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 enable, __be32 address);
|
||||
int wl1271_acx_pm_config(struct wl1271 *wl);
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
|
||||
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
|
||||
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
|
||||
s16 thold, u8 hyst);
|
||||
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
|
||||
int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *vif,
|
||||
bool enable);
|
||||
int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 index, u8 tpl_valid);
|
||||
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable, s16 thold, u8 hyst);
|
||||
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
|
||||
struct ieee80211_sta_ht_cap *ht_cap,
|
||||
bool allow_ht_operation, u8 hlid);
|
||||
int wl1271_acx_set_ht_information(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u16 ht_operation_mode);
|
||||
int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl);
|
||||
int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
|
||||
u16 ssn, bool enable, u8 peer_hlid);
|
||||
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
|
||||
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
|
||||
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
|
||||
int wl1271_acx_config_ps(struct wl1271 *wl);
|
||||
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
bool enable);
|
||||
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
|
||||
int wl1271_acx_fm_coex(struct wl1271 *wl);
|
||||
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/wl12xx.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "acx.h"
|
||||
#include "reg.h"
|
||||
#include "boot.h"
|
||||
@ -347,6 +348,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
||||
nvs_ptr += 3;
|
||||
|
||||
for (i = 0; i < burst_len; i++) {
|
||||
if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len)
|
||||
goto out_badnvs;
|
||||
|
||||
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
|
||||
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
|
||||
|
||||
@ -358,6 +362,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
||||
nvs_ptr += 4;
|
||||
dest_addr += 4;
|
||||
}
|
||||
|
||||
if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
|
||||
goto out_badnvs;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -369,6 +376,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
||||
*/
|
||||
nvs_ptr = (u8 *)wl->nvs +
|
||||
ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
|
||||
|
||||
if (nvs_ptr >= (u8 *) wl->nvs + nvs_len)
|
||||
goto out_badnvs;
|
||||
|
||||
nvs_len -= nvs_ptr - (u8 *)wl->nvs;
|
||||
|
||||
/* Now we must set the partition correctly */
|
||||
@ -384,6 +395,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
|
||||
|
||||
kfree(nvs_aligned);
|
||||
return 0;
|
||||
|
||||
out_badnvs:
|
||||
wl1271_error("nvs data is malformed");
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "reg.h"
|
||||
#include "io.h"
|
||||
#include "acx.h"
|
||||
@ -120,6 +121,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
|
||||
if (!wl->nvs)
|
||||
return -ENODEV;
|
||||
|
||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
||||
wl1271_warning("FEM index from INI out of bounds");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
|
||||
if (!gen_parms)
|
||||
return -ENOMEM;
|
||||
@ -143,6 +149,12 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
|
||||
gp->tx_bip_fem_manufacturer =
|
||||
gen_parms->general_params.tx_bip_fem_manufacturer;
|
||||
|
||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
||||
wl1271_warning("FEM index from FW out of bounds");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
|
||||
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
|
||||
|
||||
@ -162,6 +174,11 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
|
||||
if (!wl->nvs)
|
||||
return -ENODEV;
|
||||
|
||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
||||
wl1271_warning("FEM index from ini out of bounds");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
|
||||
if (!gen_parms)
|
||||
return -ENOMEM;
|
||||
@ -186,6 +203,12 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
|
||||
gp->tx_bip_fem_manufacturer =
|
||||
gen_parms->general_params.tx_bip_fem_manufacturer;
|
||||
|
||||
if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) {
|
||||
wl1271_warning("FEM index from FW out of bounds");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
|
||||
answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
|
||||
|
||||
@ -358,7 +381,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)
|
||||
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
|
||||
u8 *role_id)
|
||||
{
|
||||
struct wl12xx_cmd_role_enable *cmd;
|
||||
int ret;
|
||||
@ -381,7 +405,7 @@ int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(cmd->mac_address, addr, ETH_ALEN);
|
||||
cmd->role_type = role_type;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0);
|
||||
@ -433,37 +457,41 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl12xx_allocate_link(struct wl1271 *wl, u8 *hlid)
|
||||
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
|
||||
{
|
||||
u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS);
|
||||
if (link >= WL12XX_MAX_LINKS)
|
||||
return -EBUSY;
|
||||
|
||||
__set_bit(link, wl->links_map);
|
||||
__set_bit(link, wlvif->links_map);
|
||||
*hlid = link;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wl12xx_free_link(struct wl1271 *wl, u8 *hlid)
|
||||
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
|
||||
{
|
||||
if (*hlid == WL12XX_INVALID_LINK_ID)
|
||||
return;
|
||||
|
||||
__clear_bit(*hlid, wl->links_map);
|
||||
__clear_bit(*hlid, wlvif->links_map);
|
||||
*hlid = WL12XX_INVALID_LINK_ID;
|
||||
}
|
||||
|
||||
static int wl12xx_get_new_session_id(struct wl1271 *wl)
|
||||
static int wl12xx_get_new_session_id(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
if (wl->session_counter >= SESSION_COUNTER_MAX)
|
||||
wl->session_counter = 0;
|
||||
if (wlvif->session_counter >= SESSION_COUNTER_MAX)
|
||||
wlvif->session_counter = 0;
|
||||
|
||||
wl->session_counter++;
|
||||
wlvif->session_counter++;
|
||||
|
||||
return wl->session_counter;
|
||||
return wlvif->session_counter;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_start_dev(struct wl1271 *wl)
|
||||
static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
int ret;
|
||||
@ -474,20 +502,20 @@ int wl12xx_cmd_role_start_dev(struct wl1271 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wl->dev_role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id);
|
||||
|
||||
cmd->role_id = wl->dev_role_id;
|
||||
if (wl->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->role_id = wlvif->dev_role_id;
|
||||
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->band = WL12XX_BAND_5GHZ;
|
||||
cmd->channel = wl->channel;
|
||||
cmd->channel = wlvif->channel;
|
||||
|
||||
if (wl->dev_hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, &wl->dev_hlid);
|
||||
if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
}
|
||||
cmd->device.hlid = wl->dev_hlid;
|
||||
cmd->device.session = wl->session_counter;
|
||||
cmd->device.hlid = wlvif->dev_hlid;
|
||||
cmd->device.session = wlvif->session_counter;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d",
|
||||
cmd->role_id, cmd->device.hlid, cmd->device.session);
|
||||
@ -502,9 +530,7 @@ int wl12xx_cmd_role_start_dev(struct wl1271 *wl)
|
||||
|
||||
err_hlid:
|
||||
/* clear links on error */
|
||||
__clear_bit(wl->dev_hlid, wl->links_map);
|
||||
wl->dev_hlid = WL12XX_INVALID_LINK_ID;
|
||||
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
@ -513,12 +539,13 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_stop_dev(struct wl1271 *wl)
|
||||
static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_stop *cmd;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(wl->dev_hlid == WL12XX_INVALID_LINK_ID))
|
||||
if (WARN_ON(wlvif->dev_hlid == WL12XX_INVALID_LINK_ID))
|
||||
return -EINVAL;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
@ -529,7 +556,7 @@ int wl12xx_cmd_role_stop_dev(struct wl1271 *wl)
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop dev");
|
||||
|
||||
cmd->role_id = wl->dev_role_id;
|
||||
cmd->role_id = wlvif->dev_role_id;
|
||||
cmd->disc_type = DISCONNECT_IMMEDIATE;
|
||||
cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
|
||||
|
||||
@ -545,7 +572,7 @@ int wl12xx_cmd_role_stop_dev(struct wl1271 *wl)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
wl12xx_free_link(wl, &wl->dev_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
@ -554,8 +581,9 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_start_sta(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
int ret;
|
||||
|
||||
@ -565,33 +593,33 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id);
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
if (wl->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->role_id = wlvif->role_id;
|
||||
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->band = WL12XX_BAND_5GHZ;
|
||||
cmd->channel = wl->channel;
|
||||
cmd->sta.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
|
||||
cmd->sta.beacon_interval = cpu_to_le16(wl->beacon_int);
|
||||
cmd->channel = wlvif->channel;
|
||||
cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
||||
cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int);
|
||||
cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY;
|
||||
cmd->sta.ssid_len = wl->ssid_len;
|
||||
memcpy(cmd->sta.ssid, wl->ssid, wl->ssid_len);
|
||||
memcpy(cmd->sta.bssid, wl->bssid, ETH_ALEN);
|
||||
cmd->sta.local_rates = cpu_to_le32(wl->rate_set);
|
||||
cmd->sta.ssid_len = wlvif->ssid_len;
|
||||
memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len);
|
||||
memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN);
|
||||
cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
|
||||
|
||||
if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, &wl->sta_hlid);
|
||||
if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
}
|
||||
cmd->sta.hlid = wl->sta_hlid;
|
||||
cmd->sta.session = wl12xx_get_new_session_id(wl);
|
||||
cmd->sta.remote_rates = cpu_to_le32(wl->rate_set);
|
||||
cmd->sta.hlid = wlvif->sta.hlid;
|
||||
cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif);
|
||||
cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set);
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
|
||||
"basic_rate_set: 0x%x, remote_rates: 0x%x",
|
||||
wl->role_id, cmd->sta.hlid, cmd->sta.session,
|
||||
wl->basic_rate_set, wl->rate_set);
|
||||
wlvif->role_id, cmd->sta.hlid, cmd->sta.session,
|
||||
wlvif->basic_rate_set, wlvif->rate_set);
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
@ -603,7 +631,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl)
|
||||
|
||||
err_hlid:
|
||||
/* clear links on error. */
|
||||
wl12xx_free_link(wl, &wl->sta_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
@ -613,12 +641,12 @@ out:
|
||||
}
|
||||
|
||||
/* use this function to stop ibss as well */
|
||||
int wl12xx_cmd_role_stop_sta(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_stop *cmd;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(wl->sta_hlid == WL12XX_INVALID_LINK_ID))
|
||||
if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID))
|
||||
return -EINVAL;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
@ -627,9 +655,9 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id);
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
cmd->role_id = wlvif->role_id;
|
||||
cmd->disc_type = DISCONNECT_IMMEDIATE;
|
||||
cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED);
|
||||
|
||||
@ -639,7 +667,7 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
wl12xx_free_link(wl, &wl->sta_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
@ -648,16 +676,17 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
int ret;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id);
|
||||
|
||||
/* trying to use hidden SSID with an old hostapd version */
|
||||
if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) {
|
||||
if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) {
|
||||
wl1271_error("got a null SSID from beacon/bss");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@ -669,30 +698,30 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl12xx_allocate_link(wl, &wl->ap_global_hlid);
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
|
||||
ret = wl12xx_allocate_link(wl, &wl->ap_bcast_hlid);
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid);
|
||||
if (ret < 0)
|
||||
goto out_free_global;
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
cmd->role_id = wlvif->role_id;
|
||||
cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
|
||||
cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
|
||||
cmd->ap.global_hlid = wl->ap_global_hlid;
|
||||
cmd->ap.broadcast_hlid = wl->ap_bcast_hlid;
|
||||
cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
|
||||
cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int);
|
||||
cmd->ap.global_hlid = wlvif->ap.global_hlid;
|
||||
cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid;
|
||||
cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
||||
cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int);
|
||||
cmd->ap.dtim_interval = bss_conf->dtim_period;
|
||||
cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
|
||||
cmd->channel = wl->channel;
|
||||
cmd->channel = wlvif->channel;
|
||||
|
||||
if (!bss_conf->hidden_ssid) {
|
||||
/* take the SSID from the beacon for backward compatibility */
|
||||
cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
|
||||
cmd->ap.ssid_len = wl->ssid_len;
|
||||
memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
|
||||
cmd->ap.ssid_len = wlvif->ssid_len;
|
||||
memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len);
|
||||
} else {
|
||||
cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN;
|
||||
cmd->ap.ssid_len = bss_conf->ssid_len;
|
||||
@ -701,7 +730,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
||||
|
||||
cmd->ap.local_rates = cpu_to_le32(0xffffffff);
|
||||
|
||||
switch (wl->band) {
|
||||
switch (wlvif->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
cmd->band = RADIO_BAND_2_4GHZ;
|
||||
break;
|
||||
@ -709,7 +738,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
||||
cmd->band = RADIO_BAND_5GHZ;
|
||||
break;
|
||||
default:
|
||||
wl1271_warning("ap start - unknown band: %d", (int)wl->band);
|
||||
wl1271_warning("ap start - unknown band: %d", (int)wlvif->band);
|
||||
cmd->band = RADIO_BAND_2_4GHZ;
|
||||
break;
|
||||
}
|
||||
@ -723,10 +752,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
|
||||
goto out_free;
|
||||
|
||||
out_free_bcast:
|
||||
wl12xx_free_link(wl, &wl->ap_bcast_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid);
|
||||
|
||||
out_free_global:
|
||||
wl12xx_free_link(wl, &wl->ap_global_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
@ -735,7 +764,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_stop_ap(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_cmd_role_stop *cmd;
|
||||
int ret;
|
||||
@ -746,9 +775,9 @@ int wl12xx_cmd_role_stop_ap(struct wl1271 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wlvif->role_id);
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
cmd->role_id = wlvif->role_id;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
@ -756,8 +785,8 @@ int wl12xx_cmd_role_stop_ap(struct wl1271 *wl)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
wl12xx_free_link(wl, &wl->ap_bcast_hlid);
|
||||
wl12xx_free_link(wl, &wl->ap_global_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
@ -766,10 +795,11 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl)
|
||||
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct wl12xx_cmd_role_start *cmd;
|
||||
struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
int ret;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
@ -778,35 +808,36 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wl->role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id);
|
||||
|
||||
cmd->role_id = wl->role_id;
|
||||
if (wl->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->role_id = wlvif->role_id;
|
||||
if (wlvif->band == IEEE80211_BAND_5GHZ)
|
||||
cmd->band = WL12XX_BAND_5GHZ;
|
||||
cmd->channel = wl->channel;
|
||||
cmd->ibss.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
|
||||
cmd->ibss.beacon_interval = cpu_to_le16(wl->beacon_int);
|
||||
cmd->channel = wlvif->channel;
|
||||
cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
|
||||
cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int);
|
||||
cmd->ibss.dtim_interval = bss_conf->dtim_period;
|
||||
cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY;
|
||||
cmd->ibss.ssid_len = wl->ssid_len;
|
||||
memcpy(cmd->ibss.ssid, wl->ssid, wl->ssid_len);
|
||||
memcpy(cmd->ibss.bssid, wl->bssid, ETH_ALEN);
|
||||
cmd->sta.local_rates = cpu_to_le32(wl->rate_set);
|
||||
cmd->ibss.ssid_len = wlvif->ssid_len;
|
||||
memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len);
|
||||
memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN);
|
||||
cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
|
||||
|
||||
if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, &wl->sta_hlid);
|
||||
if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
|
||||
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
}
|
||||
cmd->ibss.hlid = wl->sta_hlid;
|
||||
cmd->ibss.remote_rates = cpu_to_le32(wl->rate_set);
|
||||
cmd->ibss.hlid = wlvif->sta.hlid;
|
||||
cmd->ibss.remote_rates = cpu_to_le32(wlvif->rate_set);
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
|
||||
"basic_rate_set: 0x%x, remote_rates: 0x%x",
|
||||
wl->role_id, cmd->sta.hlid, cmd->sta.session,
|
||||
wl->basic_rate_set, wl->rate_set);
|
||||
wlvif->role_id, cmd->sta.hlid, cmd->sta.session,
|
||||
wlvif->basic_rate_set, wlvif->rate_set);
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "wl->bssid = %pM", wl->bssid);
|
||||
wl1271_debug(DEBUG_CMD, "vif->bss_conf.bssid = %pM",
|
||||
vif->bss_conf.bssid);
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
|
||||
if (ret < 0) {
|
||||
@ -818,7 +849,7 @@ int wl12xx_cmd_role_start_ibss(struct wl1271 *wl)
|
||||
|
||||
err_hlid:
|
||||
/* clear links on error. */
|
||||
wl12xx_free_link(wl, &wl->sta_hlid);
|
||||
wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
|
||||
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
@ -962,7 +993,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ps_mode)
|
||||
{
|
||||
struct wl1271_cmd_ps_params *ps_params = NULL;
|
||||
int ret = 0;
|
||||
@ -975,7 +1007,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ps_params->role_id = wl->role_id;
|
||||
ps_params->role_id = wlvif->role_id;
|
||||
ps_params->ps_mode = ps_mode;
|
||||
|
||||
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
|
||||
@ -1030,7 +1062,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_null_data(struct wl1271 *wl)
|
||||
int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
int size;
|
||||
@ -1038,11 +1070,12 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
|
||||
int ret = -ENOMEM;
|
||||
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_IBSS) {
|
||||
if (wlvif->bss_type == BSS_TYPE_IBSS) {
|
||||
size = sizeof(struct wl12xx_null_data_template);
|
||||
ptr = NULL;
|
||||
} else {
|
||||
skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
|
||||
skb = ieee80211_nullfunc_get(wl->hw,
|
||||
wl12xx_wlvif_to_vif(wlvif));
|
||||
if (!skb)
|
||||
goto out;
|
||||
size = skb->len;
|
||||
@ -1050,7 +1083,7 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
|
||||
wl->basic_rate);
|
||||
wlvif->basic_rate);
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
@ -1061,19 +1094,21 @@ out:
|
||||
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
|
||||
int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct sk_buff *skb = NULL;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
|
||||
skb = ieee80211_nullfunc_get(wl->hw, vif);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
|
||||
skb->data, skb->len,
|
||||
CMD_TEMPL_KLV_IDX_NULL_DATA,
|
||||
wl->basic_rate);
|
||||
wlvif->basic_rate);
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
@ -1084,32 +1119,35 @@ out:
|
||||
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
|
||||
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 aid)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct sk_buff *skb;
|
||||
int ret = 0;
|
||||
|
||||
skb = ieee80211_pspoll_get(wl->hw, wl->vif);
|
||||
skb = ieee80211_pspoll_get(wl->hw, vif);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
|
||||
skb->len, 0, wl->basic_rate_set);
|
||||
skb->len, 0, wlvif->basic_rate_set);
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_probe_req(struct wl1271 *wl,
|
||||
int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len, u8 band)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
|
||||
skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,
|
||||
ie, ie_len);
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
@ -1118,7 +1156,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
|
||||
|
||||
wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
|
||||
if (band == IEEE80211_BAND_2GHZ)
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
|
||||
skb->data, skb->len, 0, rate);
|
||||
@ -1132,20 +1170,22 @@ out:
|
||||
}
|
||||
|
||||
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
if (!skb)
|
||||
skb = ieee80211_ap_probereq_get(wl->hw, wl->vif);
|
||||
skb = ieee80211_ap_probereq_get(wl->hw, vif);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[wl->band]);
|
||||
if (wl->band == IEEE80211_BAND_2GHZ)
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ)
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
|
||||
skb->data, skb->len, 0, rate);
|
||||
else
|
||||
@ -1159,9 +1199,11 @@ out:
|
||||
return skb;
|
||||
}
|
||||
|
||||
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
|
||||
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
__be32 ip_addr)
|
||||
{
|
||||
int ret;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
struct wl12xx_arp_rsp_template tmpl;
|
||||
struct ieee80211_hdr_3addr *hdr;
|
||||
struct arphdr *arp_hdr;
|
||||
@ -1173,8 +1215,8 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_DATA |
|
||||
IEEE80211_FCTL_TODS);
|
||||
memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN);
|
||||
memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN);
|
||||
memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN);
|
||||
memcpy(hdr->addr2, vif->addr, ETH_ALEN);
|
||||
memset(hdr->addr3, 0xff, ETH_ALEN);
|
||||
|
||||
/* llc layer */
|
||||
@ -1190,25 +1232,26 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
|
||||
arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
|
||||
|
||||
/* arp payload */
|
||||
memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
|
||||
memcpy(tmpl.sender_hw, vif->addr, ETH_ALEN);
|
||||
tmpl.sender_ip = ip_addr;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
|
||||
&tmpl, sizeof(tmpl), 0,
|
||||
wl->basic_rate);
|
||||
wlvif->basic_rate);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_build_qos_null_data(struct wl1271 *wl)
|
||||
int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct ieee80211_qos_hdr template;
|
||||
|
||||
memset(&template, 0, sizeof(template));
|
||||
|
||||
memcpy(template.addr1, wl->bssid, ETH_ALEN);
|
||||
memcpy(template.addr2, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(template.addr3, wl->bssid, ETH_ALEN);
|
||||
memcpy(template.addr1, vif->bss_conf.bssid, ETH_ALEN);
|
||||
memcpy(template.addr2, vif->addr, ETH_ALEN);
|
||||
memcpy(template.addr3, vif->bss_conf.bssid, ETH_ALEN);
|
||||
|
||||
template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
||||
@ -1219,7 +1262,7 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
|
||||
|
||||
return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
|
||||
sizeof(template), 0,
|
||||
wl->basic_rate);
|
||||
wlvif->basic_rate);
|
||||
}
|
||||
|
||||
int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid)
|
||||
@ -1253,7 +1296,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, const u8 *addr,
|
||||
u32 tx_seq_32, u16 tx_seq_16)
|
||||
{
|
||||
@ -1261,7 +1305,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
int ret = 0;
|
||||
|
||||
/* hlid might have already been deleted */
|
||||
if (wl->sta_hlid == WL12XX_INVALID_LINK_ID)
|
||||
if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
|
||||
return 0;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
@ -1270,7 +1314,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd->hlid = wl->sta_hlid;
|
||||
cmd->hlid = wlvif->sta.hlid;
|
||||
|
||||
if (key_type == KEY_WEP)
|
||||
cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
|
||||
@ -1321,9 +1365,10 @@ out:
|
||||
* TODO: merge with sta/ibss into 1 set_key function.
|
||||
* note there are slight diffs
|
||||
*/
|
||||
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
|
||||
u16 tx_seq_16)
|
||||
int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
|
||||
u16 tx_seq_16)
|
||||
{
|
||||
struct wl1271_cmd_set_keys *cmd;
|
||||
int ret = 0;
|
||||
@ -1333,7 +1378,7 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
if (hlid == wl->ap_bcast_hlid) {
|
||||
if (hlid == wlvif->ap.bcast_hlid) {
|
||||
if (key_type == KEY_WEP)
|
||||
lid_type = WEP_DEFAULT_LID_TYPE;
|
||||
else
|
||||
@ -1411,7 +1456,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
|
||||
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct ieee80211_sta *sta, u8 hlid)
|
||||
{
|
||||
struct wl12xx_cmd_add_peer *cmd;
|
||||
int i, ret;
|
||||
@ -1438,13 +1484,13 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
|
||||
else
|
||||
cmd->psd_type[i] = WL1271_PSD_LEGACY;
|
||||
|
||||
sta_rates = sta->supp_rates[wl->band];
|
||||
sta_rates = sta->supp_rates[wlvif->band];
|
||||
if (sta->ht_cap.ht_supported)
|
||||
sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
|
||||
|
||||
cmd->supported_rates =
|
||||
cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
|
||||
wl->band));
|
||||
wlvif->band));
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x",
|
||||
cmd->supported_rates, sta->uapsd_queues);
|
||||
@ -1584,12 +1630,13 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id)
|
||||
static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 role_id)
|
||||
{
|
||||
struct wl12xx_cmd_roc *cmd;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id);
|
||||
wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id);
|
||||
|
||||
if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID))
|
||||
return -EINVAL;
|
||||
@ -1601,8 +1648,8 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id)
|
||||
}
|
||||
|
||||
cmd->role_id = role_id;
|
||||
cmd->channel = wl->channel;
|
||||
switch (wl->band) {
|
||||
cmd->channel = wlvif->channel;
|
||||
switch (wlvif->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
cmd->band = RADIO_BAND_2_4GHZ;
|
||||
break;
|
||||
@ -1610,7 +1657,7 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id)
|
||||
cmd->band = RADIO_BAND_5GHZ;
|
||||
break;
|
||||
default:
|
||||
wl1271_error("roc - unknown band: %d", (int)wl->band);
|
||||
wl1271_error("roc - unknown band: %d", (int)wlvif->band);
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
@ -1657,14 +1704,14 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl12xx_roc(struct wl1271 *wl, u8 role_id)
|
||||
int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON(test_bit(role_id, wl->roc_map)))
|
||||
return 0;
|
||||
|
||||
ret = wl12xx_cmd_roc(wl, role_id);
|
||||
ret = wl12xx_cmd_roc(wl, wlvif, role_id);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@ -1753,3 +1800,50 @@ out_free:
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* start dev role and roc on its channel */
|
||||
int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS ||
|
||||
wlvif->bss_type == BSS_TYPE_IBSS)))
|
||||
return -EINVAL;
|
||||
|
||||
ret = wl12xx_cmd_role_start_dev(wl, wlvif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
|
||||
if (ret < 0)
|
||||
goto out_stop;
|
||||
|
||||
return 0;
|
||||
|
||||
out_stop:
|
||||
wl12xx_cmd_role_stop_dev(wl, wlvif);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* croc dev hlid, and stop the role */
|
||||
int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS ||
|
||||
wlvif->bss_type == BSS_TYPE_IBSS)))
|
||||
return -EINVAL;
|
||||
|
||||
if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
|
||||
ret = wl12xx_croc(wl, wlvif->dev_role_id);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -36,45 +36,54 @@ int wl128x_cmd_general_parms(struct wl1271 *wl);
|
||||
int wl1271_cmd_radio_parms(struct wl1271 *wl);
|
||||
int wl128x_cmd_radio_parms(struct wl1271 *wl);
|
||||
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
|
||||
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id);
|
||||
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
|
||||
u8 *role_id);
|
||||
int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
|
||||
int wl12xx_cmd_role_start_dev(struct wl1271 *wl);
|
||||
int wl12xx_cmd_role_stop_dev(struct wl1271 *wl);
|
||||
int wl12xx_cmd_role_start_sta(struct wl1271 *wl);
|
||||
int wl12xx_cmd_role_stop_sta(struct wl1271 *wl);
|
||||
int wl12xx_cmd_role_start_ap(struct wl1271 *wl);
|
||||
int wl12xx_cmd_role_stop_ap(struct wl1271 *wl);
|
||||
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl);
|
||||
int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
|
||||
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
|
||||
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
|
||||
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
|
||||
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 ps_mode);
|
||||
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
|
||||
size_t len);
|
||||
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
|
||||
void *buf, size_t buf_len, int index, u32 rates);
|
||||
int wl1271_cmd_build_null_data(struct wl1271 *wl);
|
||||
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
|
||||
int wl1271_cmd_build_probe_req(struct wl1271 *wl,
|
||||
int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 aid);
|
||||
int wl1271_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len, u8 band);
|
||||
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb);
|
||||
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr);
|
||||
int wl1271_build_qos_null_data(struct wl1271 *wl);
|
||||
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
|
||||
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
__be32 ip_addr);
|
||||
int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif);
|
||||
int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif);
|
||||
int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid);
|
||||
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, const u8 *addr,
|
||||
u32 tx_seq_32, u16 tx_seq_16);
|
||||
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
|
||||
int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u16 action, u8 id, u8 key_type,
|
||||
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
|
||||
u16 tx_seq_16);
|
||||
int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid);
|
||||
int wl12xx_roc(struct wl1271 *wl, u8 role_id);
|
||||
int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id);
|
||||
int wl12xx_croc(struct wl1271 *wl, u8 role_id);
|
||||
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
|
||||
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct ieee80211_sta *sta, u8 hlid);
|
||||
int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
|
||||
int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
|
||||
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
|
||||
@ -82,6 +91,9 @@ int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
|
||||
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
|
||||
struct ieee80211_channel_switch *ch_switch);
|
||||
int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
|
||||
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 *hlid);
|
||||
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
|
||||
|
||||
enum wl1271_commands {
|
||||
CMD_INTERROGATE = 1, /*use this to read information elements*/
|
||||
|
@ -440,6 +440,10 @@ struct conf_rx_settings {
|
||||
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
|
||||
CONF_HW_BIT_RATE_54MBPS)
|
||||
|
||||
#define CONF_TX_CCK_RATES (CONF_HW_BIT_RATE_1MBPS | \
|
||||
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
|
||||
CONF_HW_BIT_RATE_11MBPS)
|
||||
|
||||
#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \
|
||||
CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \
|
||||
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
|
||||
|
101
drivers/net/wireless/wl12xx/debug.h
Normal file
101
drivers/net/wireless/wl12xx/debug.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of wl12xx
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments. All rights reserved.
|
||||
* Copyright (C) 2008-2009 Nokia Corporation
|
||||
*
|
||||
* Contact: Luciano Coelho <coelho@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#define DRIVER_NAME "wl12xx"
|
||||
#define DRIVER_PREFIX DRIVER_NAME ": "
|
||||
|
||||
enum {
|
||||
DEBUG_NONE = 0,
|
||||
DEBUG_IRQ = BIT(0),
|
||||
DEBUG_SPI = BIT(1),
|
||||
DEBUG_BOOT = BIT(2),
|
||||
DEBUG_MAILBOX = BIT(3),
|
||||
DEBUG_TESTMODE = BIT(4),
|
||||
DEBUG_EVENT = BIT(5),
|
||||
DEBUG_TX = BIT(6),
|
||||
DEBUG_RX = BIT(7),
|
||||
DEBUG_SCAN = BIT(8),
|
||||
DEBUG_CRYPT = BIT(9),
|
||||
DEBUG_PSM = BIT(10),
|
||||
DEBUG_MAC80211 = BIT(11),
|
||||
DEBUG_CMD = BIT(12),
|
||||
DEBUG_ACX = BIT(13),
|
||||
DEBUG_SDIO = BIT(14),
|
||||
DEBUG_FILTERS = BIT(15),
|
||||
DEBUG_ADHOC = BIT(16),
|
||||
DEBUG_AP = BIT(17),
|
||||
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
|
||||
DEBUG_ALL = ~0,
|
||||
};
|
||||
|
||||
extern u32 wl12xx_debug_level;
|
||||
|
||||
#define DEBUG_DUMP_LIMIT 1024
|
||||
|
||||
#define wl1271_error(fmt, arg...) \
|
||||
pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_warning(fmt, arg...) \
|
||||
pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_notice(fmt, arg...) \
|
||||
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_info(fmt, arg...) \
|
||||
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_debug(level, fmt, arg...) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \
|
||||
} while (0)
|
||||
|
||||
/* TODO: use pr_debug_hex_dump when it becomes available */
|
||||
#define wl1271_dump(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
0); \
|
||||
} while (0)
|
||||
|
||||
#define wl1271_dump_ascii(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
true); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __DEBUG_H__ */
|
@ -27,6 +27,7 @@
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "acx.h"
|
||||
#include "ps.h"
|
||||
#include "io.h"
|
||||
@ -346,29 +347,14 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
|
||||
DRIVER_STATE_PRINT_INT(tx_results_count);
|
||||
DRIVER_STATE_PRINT_LHEX(flags);
|
||||
DRIVER_STATE_PRINT_INT(tx_blocks_freed);
|
||||
DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb);
|
||||
DRIVER_STATE_PRINT_INT(rx_counter);
|
||||
DRIVER_STATE_PRINT_INT(session_counter);
|
||||
DRIVER_STATE_PRINT_INT(state);
|
||||
DRIVER_STATE_PRINT_INT(bss_type);
|
||||
DRIVER_STATE_PRINT_INT(channel);
|
||||
DRIVER_STATE_PRINT_HEX(rate_set);
|
||||
DRIVER_STATE_PRINT_HEX(basic_rate_set);
|
||||
DRIVER_STATE_PRINT_HEX(basic_rate);
|
||||
DRIVER_STATE_PRINT_INT(band);
|
||||
DRIVER_STATE_PRINT_INT(beacon_int);
|
||||
DRIVER_STATE_PRINT_INT(psm_entry_retry);
|
||||
DRIVER_STATE_PRINT_INT(ps_poll_failures);
|
||||
DRIVER_STATE_PRINT_INT(power_level);
|
||||
DRIVER_STATE_PRINT_INT(rssi_thold);
|
||||
DRIVER_STATE_PRINT_INT(last_rssi_event);
|
||||
DRIVER_STATE_PRINT_INT(sg_enabled);
|
||||
DRIVER_STATE_PRINT_INT(enable_11a);
|
||||
DRIVER_STATE_PRINT_INT(noise);
|
||||
DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]);
|
||||
DRIVER_STATE_PRINT_INT(last_tx_hlid);
|
||||
DRIVER_STATE_PRINT_INT(ba_support);
|
||||
DRIVER_STATE_PRINT_HEX(ba_rx_bitmap);
|
||||
DRIVER_STATE_PRINT_HEX(ap_fw_ps_map);
|
||||
DRIVER_STATE_PRINT_LHEX(ap_ps_map);
|
||||
DRIVER_STATE_PRINT_HEX(quirks);
|
||||
@ -399,6 +385,115 @@ static const struct file_operations driver_state_ops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl12xx_vif *wlvif;
|
||||
int ret, res = 0;
|
||||
const int buf_size = 4096;
|
||||
char *buf;
|
||||
char tmp_buf[64];
|
||||
|
||||
buf = kzalloc(buf_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
#define VIF_STATE_PRINT(x, fmt) \
|
||||
(res += scnprintf(buf + res, buf_size - res, \
|
||||
#x " = " fmt "\n", wlvif->x))
|
||||
|
||||
#define VIF_STATE_PRINT_LONG(x) VIF_STATE_PRINT(x, "%ld")
|
||||
#define VIF_STATE_PRINT_INT(x) VIF_STATE_PRINT(x, "%d")
|
||||
#define VIF_STATE_PRINT_STR(x) VIF_STATE_PRINT(x, "%s")
|
||||
#define VIF_STATE_PRINT_LHEX(x) VIF_STATE_PRINT(x, "0x%lx")
|
||||
#define VIF_STATE_PRINT_LLHEX(x) VIF_STATE_PRINT(x, "0x%llx")
|
||||
#define VIF_STATE_PRINT_HEX(x) VIF_STATE_PRINT(x, "0x%x")
|
||||
|
||||
#define VIF_STATE_PRINT_NSTR(x, len) \
|
||||
do { \
|
||||
memset(tmp_buf, 0, sizeof(tmp_buf)); \
|
||||
memcpy(tmp_buf, wlvif->x, \
|
||||
min_t(u8, len, sizeof(tmp_buf) - 1)); \
|
||||
res += scnprintf(buf + res, buf_size - res, \
|
||||
#x " = %s\n", tmp_buf); \
|
||||
} while (0)
|
||||
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
VIF_STATE_PRINT_INT(role_id);
|
||||
VIF_STATE_PRINT_INT(bss_type);
|
||||
VIF_STATE_PRINT_LHEX(flags);
|
||||
VIF_STATE_PRINT_INT(p2p);
|
||||
VIF_STATE_PRINT_INT(dev_role_id);
|
||||
VIF_STATE_PRINT_INT(dev_hlid);
|
||||
|
||||
if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
|
||||
wlvif->bss_type == BSS_TYPE_IBSS) {
|
||||
VIF_STATE_PRINT_INT(sta.hlid);
|
||||
VIF_STATE_PRINT_INT(sta.ba_rx_bitmap);
|
||||
VIF_STATE_PRINT_INT(sta.basic_rate_idx);
|
||||
VIF_STATE_PRINT_INT(sta.ap_rate_idx);
|
||||
VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
|
||||
} else {
|
||||
VIF_STATE_PRINT_INT(ap.global_hlid);
|
||||
VIF_STATE_PRINT_INT(ap.bcast_hlid);
|
||||
VIF_STATE_PRINT_LHEX(ap.sta_hlid_map[0]);
|
||||
VIF_STATE_PRINT_INT(ap.mgmt_rate_idx);
|
||||
VIF_STATE_PRINT_INT(ap.bcast_rate_idx);
|
||||
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[0]);
|
||||
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[1]);
|
||||
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[2]);
|
||||
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]);
|
||||
}
|
||||
VIF_STATE_PRINT_INT(last_tx_hlid);
|
||||
VIF_STATE_PRINT_LHEX(links_map[0]);
|
||||
VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len);
|
||||
VIF_STATE_PRINT_INT(band);
|
||||
VIF_STATE_PRINT_INT(channel);
|
||||
VIF_STATE_PRINT_HEX(bitrate_masks[0]);
|
||||
VIF_STATE_PRINT_HEX(bitrate_masks[1]);
|
||||
VIF_STATE_PRINT_HEX(basic_rate_set);
|
||||
VIF_STATE_PRINT_HEX(basic_rate);
|
||||
VIF_STATE_PRINT_HEX(rate_set);
|
||||
VIF_STATE_PRINT_INT(beacon_int);
|
||||
VIF_STATE_PRINT_INT(default_key);
|
||||
VIF_STATE_PRINT_INT(aid);
|
||||
VIF_STATE_PRINT_INT(session_counter);
|
||||
VIF_STATE_PRINT_INT(ps_poll_failures);
|
||||
VIF_STATE_PRINT_INT(psm_entry_retry);
|
||||
VIF_STATE_PRINT_INT(power_level);
|
||||
VIF_STATE_PRINT_INT(rssi_thold);
|
||||
VIF_STATE_PRINT_INT(last_rssi_event);
|
||||
VIF_STATE_PRINT_INT(ba_support);
|
||||
VIF_STATE_PRINT_INT(ba_allowed);
|
||||
VIF_STATE_PRINT_LLHEX(tx_security_seq);
|
||||
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
|
||||
}
|
||||
|
||||
#undef VIF_STATE_PRINT_INT
|
||||
#undef VIF_STATE_PRINT_LONG
|
||||
#undef VIF_STATE_PRINT_HEX
|
||||
#undef VIF_STATE_PRINT_LHEX
|
||||
#undef VIF_STATE_PRINT_LLHEX
|
||||
#undef VIF_STATE_PRINT_STR
|
||||
#undef VIF_STATE_PRINT_NSTR
|
||||
#undef VIF_STATE_PRINT
|
||||
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, res);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations vifs_state_ops = {
|
||||
.read = vifs_state_read,
|
||||
.open = wl1271_open_file_generic,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t dtim_interval_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@ -520,6 +615,7 @@ static ssize_t rx_streaming_interval_write(struct file *file,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl12xx_vif *wlvif;
|
||||
unsigned long value;
|
||||
int ret;
|
||||
|
||||
@ -543,7 +639,9 @@ static ssize_t rx_streaming_interval_write(struct file *file,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_recalc_rx_streaming(wl);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
wl1271_recalc_rx_streaming(wl, wlvif);
|
||||
}
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
@ -572,6 +670,7 @@ static ssize_t rx_streaming_always_write(struct file *file,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl12xx_vif *wlvif;
|
||||
unsigned long value;
|
||||
int ret;
|
||||
|
||||
@ -595,7 +694,9 @@ static ssize_t rx_streaming_always_write(struct file *file,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_recalc_rx_streaming(wl);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
wl1271_recalc_rx_streaming(wl, wlvif);
|
||||
}
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
@ -624,6 +725,7 @@ static ssize_t beacon_filtering_write(struct file *file,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wl1271 *wl = file->private_data;
|
||||
struct wl12xx_vif *wlvif;
|
||||
char buf[10];
|
||||
size_t len;
|
||||
unsigned long value;
|
||||
@ -646,7 +748,9 @@ static ssize_t beacon_filtering_write(struct file *file,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, !!value);
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, !!value);
|
||||
}
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
@ -770,6 +874,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
||||
DEBUGFS_ADD(gpio_power, rootdir);
|
||||
DEBUGFS_ADD(start_recovery, rootdir);
|
||||
DEBUGFS_ADD(driver_state, rootdir);
|
||||
DEBUGFS_ADD(vifs_state, rootdir);
|
||||
DEBUGFS_ADD(dtim_interval, rootdir);
|
||||
DEBUGFS_ADD(beacon_interval, rootdir);
|
||||
DEBUGFS_ADD(beacon_filtering, rootdir);
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "reg.h"
|
||||
#include "io.h"
|
||||
#include "event.h"
|
||||
@ -31,12 +32,16 @@
|
||||
|
||||
void wl1271_pspoll_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
struct delayed_work *dwork;
|
||||
struct wl1271 *wl;
|
||||
int ret;
|
||||
|
||||
dwork = container_of(work, struct delayed_work, work);
|
||||
wl = container_of(dwork, struct wl1271, pspoll_work);
|
||||
wlvif = container_of(dwork, struct wl12xx_vif, pspoll_work);
|
||||
vif = container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
|
||||
wl = wlvif->wl;
|
||||
|
||||
wl1271_debug(DEBUG_EVENT, "pspoll work");
|
||||
|
||||
@ -45,10 +50,10 @@ void wl1271_pspoll_work(struct work_struct *work)
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
goto out;
|
||||
|
||||
if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
|
||||
if (!test_and_clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags))
|
||||
goto out;
|
||||
|
||||
if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
|
||||
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
@ -60,31 +65,33 @@ void wl1271_pspoll_work(struct work_struct *work)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true);
|
||||
wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
|
||||
wlvif->basic_rate, true);
|
||||
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
};
|
||||
|
||||
static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
|
||||
static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int delay = wl->conf.conn.ps_poll_recovery_period;
|
||||
int ret;
|
||||
|
||||
wl->ps_poll_failures++;
|
||||
if (wl->ps_poll_failures == 1)
|
||||
wlvif->ps_poll_failures++;
|
||||
if (wlvif->ps_poll_failures == 1)
|
||||
wl1271_info("AP with dysfunctional ps-poll, "
|
||||
"trying to work around it.");
|
||||
|
||||
/* force active mode receive data from the AP */
|
||||
if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
|
||||
ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
|
||||
wl->basic_rate, true);
|
||||
if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
|
||||
ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
|
||||
wlvif->basic_rate, true);
|
||||
if (ret < 0)
|
||||
return;
|
||||
set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work,
|
||||
set_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
|
||||
ieee80211_queue_delayed_work(wl->hw, &wlvif->pspoll_work,
|
||||
msecs_to_jiffies(delay));
|
||||
}
|
||||
|
||||
@ -97,6 +104,7 @@ static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
|
||||
}
|
||||
|
||||
static int wl1271_event_ps_report(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct event_mailbox *mbox,
|
||||
bool *beacon_loss)
|
||||
{
|
||||
@ -109,41 +117,37 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
|
||||
case EVENT_ENTER_POWER_SAVE_FAIL:
|
||||
wl1271_debug(DEBUG_PSM, "PSM entry failed");
|
||||
|
||||
if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
|
||||
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
|
||||
/* remain in active mode */
|
||||
wl->psm_entry_retry = 0;
|
||||
wlvif->psm_entry_retry = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wl->psm_entry_retry < total_retries) {
|
||||
wl->psm_entry_retry++;
|
||||
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
|
||||
wl->basic_rate, true);
|
||||
if (wlvif->psm_entry_retry < total_retries) {
|
||||
wlvif->psm_entry_retry++;
|
||||
ret = wl1271_ps_set_mode(wl, wlvif,
|
||||
STATION_POWER_SAVE_MODE,
|
||||
wlvif->basic_rate, true);
|
||||
} else {
|
||||
wl1271_info("No ack to nullfunc from AP.");
|
||||
wl->psm_entry_retry = 0;
|
||||
wlvif->psm_entry_retry = 0;
|
||||
*beacon_loss = true;
|
||||
}
|
||||
break;
|
||||
case EVENT_ENTER_POWER_SAVE_SUCCESS:
|
||||
wl->psm_entry_retry = 0;
|
||||
|
||||
/* enable beacon filtering */
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, true);
|
||||
if (ret < 0)
|
||||
break;
|
||||
wlvif->psm_entry_retry = 0;
|
||||
|
||||
/*
|
||||
* BET has only a minor effect in 5GHz and masks
|
||||
* channel switch IEs, so we only enable BET on 2.4GHz
|
||||
*/
|
||||
if (wl->band == IEEE80211_BAND_2GHZ)
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ)
|
||||
/* enable beacon early termination */
|
||||
ret = wl1271_acx_bet_enable(wl, true);
|
||||
ret = wl1271_acx_bet_enable(wl, wlvif, true);
|
||||
|
||||
if (wl->ps_compl) {
|
||||
complete(wl->ps_compl);
|
||||
wl->ps_compl = NULL;
|
||||
if (wlvif->ps_compl) {
|
||||
complete(wlvif->ps_compl);
|
||||
wlvif->ps_compl = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -154,39 +158,44 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
|
||||
}
|
||||
|
||||
static void wl1271_event_rssi_trigger(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct event_mailbox *mbox)
|
||||
{
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
enum nl80211_cqm_rssi_threshold_event event;
|
||||
s8 metric = mbox->rssi_snr_trigger_metric[0];
|
||||
|
||||
wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric);
|
||||
|
||||
if (metric <= wl->rssi_thold)
|
||||
if (metric <= wlvif->rssi_thold)
|
||||
event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
|
||||
else
|
||||
event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
|
||||
|
||||
if (event != wl->last_rssi_event)
|
||||
ieee80211_cqm_rssi_notify(wl->vif, event, GFP_KERNEL);
|
||||
wl->last_rssi_event = event;
|
||||
if (event != wlvif->last_rssi_event)
|
||||
ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
|
||||
wlvif->last_rssi_event = event;
|
||||
}
|
||||
|
||||
static void wl1271_stop_ba_event(struct wl1271 *wl)
|
||||
static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS) {
|
||||
if (!wl->ba_rx_bitmap)
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
|
||||
if (!wlvif->sta.ba_rx_bitmap)
|
||||
return;
|
||||
ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap,
|
||||
wl->bssid);
|
||||
ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap,
|
||||
vif->bss_conf.bssid);
|
||||
} else {
|
||||
int i;
|
||||
u8 hlid;
|
||||
struct wl1271_link *lnk;
|
||||
for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) {
|
||||
lnk = &wl->links[i];
|
||||
if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap)
|
||||
for_each_set_bit(hlid, wlvif->ap.sta_hlid_map,
|
||||
WL12XX_MAX_LINKS) {
|
||||
lnk = &wl->links[hlid];
|
||||
if (!lnk->ba_bitmap)
|
||||
continue;
|
||||
|
||||
ieee80211_stop_rx_ba_session(wl->vif,
|
||||
ieee80211_stop_rx_ba_session(vif,
|
||||
lnk->ba_bitmap,
|
||||
lnk->addr);
|
||||
}
|
||||
@ -196,14 +205,23 @@ static void wl1271_stop_ba_event(struct wl1271 *wl)
|
||||
static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
|
||||
u8 enable)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
|
||||
if (enable) {
|
||||
/* disable dynamic PS when requested by the firmware */
|
||||
ieee80211_disable_dyn_ps(wl->vif);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
ieee80211_disable_dyn_ps(vif);
|
||||
}
|
||||
set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
|
||||
} else {
|
||||
ieee80211_enable_dyn_ps(wl->vif);
|
||||
clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
|
||||
wl1271_recalc_rx_streaming(wl);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
ieee80211_enable_dyn_ps(vif);
|
||||
wl1271_recalc_rx_streaming(wl, wlvif);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -217,10 +235,11 @@ static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
|
||||
|
||||
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
int ret;
|
||||
u32 vector;
|
||||
bool beacon_loss = false;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
bool disconnect_sta = false;
|
||||
unsigned long sta_bitmap = 0;
|
||||
|
||||
@ -234,7 +253,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||
wl1271_debug(DEBUG_EVENT, "status: 0x%x",
|
||||
mbox->scheduled_scan_status);
|
||||
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, wl->scan_vif);
|
||||
}
|
||||
|
||||
if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
|
||||
@ -253,8 +272,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||
}
|
||||
}
|
||||
|
||||
if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
|
||||
wl->bss_type == BSS_TYPE_STA_BSS)
|
||||
if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
|
||||
wl12xx_event_soft_gemini_sense(wl,
|
||||
mbox->soft_gemini_sense_info);
|
||||
|
||||
@ -267,40 +285,54 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||
* BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
|
||||
*
|
||||
*/
|
||||
if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
|
||||
if (vector & BSS_LOSE_EVENT_ID) {
|
||||
/* TODO: check for multi-role */
|
||||
wl1271_info("Beacon loss detected.");
|
||||
|
||||
/* indicate to the stack, that beacons have been lost */
|
||||
beacon_loss = true;
|
||||
}
|
||||
|
||||
if ((vector & PS_REPORT_EVENT_ID) && !is_ap) {
|
||||
if (vector & PS_REPORT_EVENT_ID) {
|
||||
wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
|
||||
ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
ret = wl1271_event_ps_report(wl, wlvif,
|
||||
mbox, &beacon_loss);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap)
|
||||
wl1271_event_pspoll_delivery_fail(wl);
|
||||
if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
wl1271_event_pspoll_delivery_fail(wl, wlvif);
|
||||
}
|
||||
|
||||
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
|
||||
/* TODO: check actual multi-role support */
|
||||
wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
|
||||
if (wl->vif)
|
||||
wl1271_event_rssi_trigger(wl, mbox);
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
wl1271_event_rssi_trigger(wl, wlvif, mbox);
|
||||
}
|
||||
}
|
||||
|
||||
if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) {
|
||||
if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) {
|
||||
u8 role_id = mbox->role_id;
|
||||
wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
|
||||
"ba_allowed = 0x%x", mbox->rx_ba_allowed);
|
||||
"ba_allowed = 0x%x, role_id=%d",
|
||||
mbox->rx_ba_allowed, role_id);
|
||||
|
||||
wl->ba_allowed = !!mbox->rx_ba_allowed;
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
if (role_id != 0xff && role_id != wlvif->role_id)
|
||||
continue;
|
||||
|
||||
if (wl->vif && !wl->ba_allowed)
|
||||
wl1271_stop_ba_event(wl);
|
||||
wlvif->ba_allowed = !!mbox->rx_ba_allowed;
|
||||
if (!wlvif->ba_allowed)
|
||||
wl1271_stop_ba_event(wl, wlvif);
|
||||
}
|
||||
}
|
||||
|
||||
if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) {
|
||||
if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) {
|
||||
wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
|
||||
"status = 0x%x",
|
||||
mbox->channel_switch_status);
|
||||
@ -309,50 +341,65 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||
* 1) channel switch complete with status=0
|
||||
* 2) channel switch failed status=1
|
||||
*/
|
||||
if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) &&
|
||||
(wl->vif))
|
||||
ieee80211_chswitch_done(wl->vif,
|
||||
mbox->channel_switch_status ? false : true);
|
||||
|
||||
/* TODO: configure only the relevant vif */
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
bool success;
|
||||
|
||||
if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
|
||||
&wl->flags))
|
||||
continue;
|
||||
|
||||
success = mbox->channel_switch_status ? false : true;
|
||||
ieee80211_chswitch_done(vif, success);
|
||||
}
|
||||
}
|
||||
|
||||
if ((vector & DUMMY_PACKET_EVENT_ID)) {
|
||||
wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
|
||||
if (wl->vif)
|
||||
wl1271_tx_dummy_packet(wl);
|
||||
wl1271_tx_dummy_packet(wl);
|
||||
}
|
||||
|
||||
/*
|
||||
* "TX retries exceeded" has a different meaning according to mode.
|
||||
* In AP mode the offending station is disconnected.
|
||||
*/
|
||||
if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) {
|
||||
if (vector & MAX_TX_RETRY_EVENT_ID) {
|
||||
wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
|
||||
sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
|
||||
disconnect_sta = true;
|
||||
}
|
||||
|
||||
if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
|
||||
if (vector & INACTIVE_STA_EVENT_ID) {
|
||||
wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
|
||||
sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
|
||||
disconnect_sta = true;
|
||||
}
|
||||
|
||||
if (is_ap && disconnect_sta) {
|
||||
if (disconnect_sta) {
|
||||
u32 num_packets = wl->conf.tx.max_tx_retries;
|
||||
struct ieee80211_sta *sta;
|
||||
const u8 *addr;
|
||||
int h;
|
||||
|
||||
for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
|
||||
h < AP_MAX_LINKS;
|
||||
h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
|
||||
if (!wl1271_is_active_sta(wl, h))
|
||||
for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
|
||||
bool found = false;
|
||||
/* find the ap vif connected to this sta */
|
||||
wl12xx_for_each_wlvif_ap(wl, wlvif) {
|
||||
if (!test_bit(h, wlvif->ap.sta_hlid_map))
|
||||
continue;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
addr = wl->links[h].addr;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(wl->vif, addr);
|
||||
sta = ieee80211_find_sta(vif, addr);
|
||||
if (sta) {
|
||||
wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
|
||||
ieee80211_report_low_ack(sta, num_packets);
|
||||
@ -361,8 +408,11 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
|
||||
}
|
||||
}
|
||||
|
||||
if (wl->vif && beacon_loss)
|
||||
ieee80211_connection_loss(wl->vif);
|
||||
if (beacon_loss)
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
ieee80211_connection_loss(vif);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -132,7 +132,4 @@ void wl1271_event_mbox_config(struct wl1271 *wl);
|
||||
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
|
||||
void wl1271_pspoll_work(struct work_struct *work);
|
||||
|
||||
/* Functions from main.c */
|
||||
bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid);
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "init.h"
|
||||
#include "wl12xx_80211.h"
|
||||
#include "acx.h"
|
||||
@ -33,7 +34,7 @@
|
||||
#include "tx.h"
|
||||
#include "io.h"
|
||||
|
||||
int wl1271_sta_init_templates_config(struct wl1271 *wl)
|
||||
int wl1271_init_templates_config(struct wl1271 *wl)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
@ -64,7 +65,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
|
||||
sizeof
|
||||
(struct wl12xx_qos_null_data_template),
|
||||
(struct ieee80211_qos_hdr),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -88,105 +89,6 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
|
||||
WL1271_CMD_TEMPL_DFLT_SIZE, i,
|
||||
WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_deauth_template(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_disconn_template *tmpl;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
|
||||
if (!tmpl) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_DEAUTH);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
|
||||
tmpl, sizeof(*tmpl), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(tmpl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_null_template(struct wl1271 *wl)
|
||||
{
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
|
||||
if (!nullfunc) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* nullfunc->addr1 is filled by FW */
|
||||
|
||||
memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
|
||||
sizeof(*nullfunc), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(nullfunc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_qos_null_template(struct wl1271 *wl)
|
||||
{
|
||||
struct ieee80211_qos_hdr *qosnull;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
|
||||
if (!qosnull) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* qosnull->addr1 is filled by FW */
|
||||
|
||||
memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
|
||||
sizeof(*qosnull), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(qosnull);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_templates_config(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Put very large empty placeholders for all templates. These
|
||||
* reserve memory for later.
|
||||
@ -210,22 +112,106 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
|
||||
sizeof(struct wl12xx_null_data_template),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
|
||||
sizeof
|
||||
(struct wl12xx_qos_null_data_template),
|
||||
0, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
|
||||
sizeof(struct ieee80211_qos_hdr),
|
||||
i, WL1271_RATE_AUTOMATIC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl12xx_disconn_template *tmpl;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
|
||||
if (!tmpl) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_DEAUTH);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
|
||||
tmpl, sizeof(*tmpl), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(tmpl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_null_template(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
|
||||
if (!nullfunc) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* nullfunc->addr1 is filled by FW */
|
||||
|
||||
memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
|
||||
memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
|
||||
sizeof(*nullfunc), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(nullfunc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct ieee80211_qos_hdr *qosnull;
|
||||
int ret;
|
||||
u32 rate;
|
||||
|
||||
qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
|
||||
if (!qosnull) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
||||
IEEE80211_FCTL_FROMDS);
|
||||
|
||||
/* qosnull->addr1 is filled by FW */
|
||||
|
||||
memcpy(qosnull->addr2, vif->addr, ETH_ALEN);
|
||||
memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
|
||||
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
|
||||
sizeof(*qosnull), 0, rate);
|
||||
|
||||
out:
|
||||
kfree(qosnull);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl12xx_init_rx_config(struct wl1271 *wl)
|
||||
{
|
||||
int ret;
|
||||
@ -245,31 +231,40 @@ int wl1271_init_phy_config(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl12xx_init_phy_vif_config(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_service_period_timeout(wl);
|
||||
ret = wl1271_acx_service_period_timeout(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold);
|
||||
ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_init_beacon_filter(struct wl1271 *wl)
|
||||
static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* disable beacon filtering at this stage */
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, false);
|
||||
ret = wl1271_acx_beacon_filter_table(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_beacon_filter_table(wl);
|
||||
/* enable beacon filtering */
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -302,11 +297,12 @@ int wl1271_init_energy_detection(struct wl1271 *wl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
|
||||
static int wl1271_init_beacon_broadcast(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_acx_bcn_dtim_options(wl);
|
||||
ret = wl1271_acx_bcn_dtim_options(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -327,7 +323,8 @@ static int wl12xx_init_fwlog(struct wl1271 *wl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_sta_hw_init(struct wl1271 *wl)
|
||||
/* generic sta initialization (non vif-specific) */
|
||||
static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -338,25 +335,7 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
|
||||
}
|
||||
|
||||
/* PS config */
|
||||
ret = wl1271_acx_config_ps(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_sta_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Initialize connection monitoring thresholds */
|
||||
ret = wl1271_acx_conn_monit_params(wl, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacon filtering */
|
||||
ret = wl1271_init_beacon_filter(wl);
|
||||
ret = wl12xx_acx_config_ps(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -365,103 +344,61 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacons and broadcast settings */
|
||||
ret = wl1271_init_beacon_broadcast(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure for ELP power saving */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure rssi/snr averaging weights */
|
||||
ret = wl1271_acx_rssi_snr_avg_weights(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_sta_rate_policies(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure the FW logger */
|
||||
ret = wl12xx_init_fwlog(wl);
|
||||
ret = wl1271_acx_sta_rate_policies(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl)
|
||||
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, i,
|
||||
ret = wl1271_acx_keep_alive_config(wl, wlvif, i,
|
||||
ACX_KEEP_ALIVE_TPL_INVALID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* disable the keep-alive feature */
|
||||
ret = wl1271_acx_keep_alive_mode(wl, false);
|
||||
ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_hw_init(struct wl1271 *wl)
|
||||
/* generic ap initialization (non vif-specific) */
|
||||
static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_ap_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure for power always on */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_init_ap_rates(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_ap_max_tx_retry(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* initialize Tx power */
|
||||
ret = wl1271_acx_tx_power(wl, wl->power_level);
|
||||
ret = wl1271_init_ap_rates(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_ap_init_templates(struct wl1271 *wl)
|
||||
int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret;
|
||||
|
||||
ret = wl1271_ap_init_deauth_template(wl);
|
||||
ret = wl1271_ap_init_deauth_template(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_ap_init_null_template(wl);
|
||||
ret = wl1271_ap_init_null_template(wl, vif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_ap_init_qos_null_template(wl);
|
||||
ret = wl1271_ap_init_qos_null_template(wl, vif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -469,43 +406,45 @@ int wl1271_ap_init_templates(struct wl1271 *wl)
|
||||
* when operating as AP we want to receive external beacons for
|
||||
* configuring ERP protection.
|
||||
*/
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, false);
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
|
||||
static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
return wl1271_ap_init_templates(wl);
|
||||
return wl1271_ap_init_templates(wl, vif);
|
||||
}
|
||||
|
||||
int wl1271_init_ap_rates(struct wl1271 *wl)
|
||||
int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int i, ret;
|
||||
struct conf_tx_rate_class rc;
|
||||
u32 supported_rates;
|
||||
|
||||
wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wl->basic_rate_set);
|
||||
wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
|
||||
wlvif->basic_rate_set);
|
||||
|
||||
if (wl->basic_rate_set == 0)
|
||||
if (wlvif->basic_rate_set == 0)
|
||||
return -EINVAL;
|
||||
|
||||
rc.enabled_rates = wl->basic_rate_set;
|
||||
rc.enabled_rates = wlvif->basic_rate_set;
|
||||
rc.long_retry_limit = 10;
|
||||
rc.short_retry_limit = 10;
|
||||
rc.aflags = 0;
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE);
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* use the min basic rate for AP broadcast/multicast */
|
||||
rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
|
||||
rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
||||
rc.short_retry_limit = 10;
|
||||
rc.long_retry_limit = 10;
|
||||
rc.aflags = 0;
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE);
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -513,7 +452,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
|
||||
* If the basic rates contain OFDM rates, use OFDM only
|
||||
* rates for unicast TX as well. Else use all supported rates.
|
||||
*/
|
||||
if ((wl->basic_rate_set & CONF_TX_OFDM_RATES))
|
||||
if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
|
||||
supported_rates = CONF_TX_OFDM_RATES;
|
||||
else
|
||||
supported_rates = CONF_TX_AP_ENABLED_RATES;
|
||||
@ -527,7 +466,8 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
|
||||
rc.short_retry_limit = 10;
|
||||
rc.long_retry_limit = 10;
|
||||
rc.aflags = 0;
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc, i);
|
||||
ret = wl1271_acx_ap_rate_policy(wl, &rc,
|
||||
wlvif->ap.ucast_rate_idx[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@ -535,24 +475,23 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wl1271_set_ba_policies(struct wl1271 *wl)
|
||||
static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
/* Reset the BA RX indicators */
|
||||
wl->ba_rx_bitmap = 0;
|
||||
wl->ba_allowed = true;
|
||||
wlvif->ba_allowed = true;
|
||||
wl->ba_rx_session_count = 0;
|
||||
|
||||
/* BA is supported in STA/AP modes */
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS &&
|
||||
wl->bss_type != BSS_TYPE_STA_BSS) {
|
||||
wl->ba_support = false;
|
||||
if (wlvif->bss_type != BSS_TYPE_AP_BSS &&
|
||||
wlvif->bss_type != BSS_TYPE_STA_BSS) {
|
||||
wlvif->ba_support = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
wl->ba_support = true;
|
||||
wlvif->ba_support = true;
|
||||
|
||||
/* 802.11n initiator BA session setting */
|
||||
return wl12xx_acx_set_ba_initiator_policy(wl);
|
||||
return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
|
||||
}
|
||||
|
||||
int wl1271_chip_specific_init(struct wl1271 *wl)
|
||||
@ -562,7 +501,7 @@ int wl1271_chip_specific_init(struct wl1271 *wl)
|
||||
if (wl->chip.id == CHIP_ID_1283_PG20) {
|
||||
u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
|
||||
|
||||
if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT)
|
||||
if (!(wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT))
|
||||
/* Enable SDIO padding */
|
||||
host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
|
||||
|
||||
@ -575,13 +514,150 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* vif-specifc initialization */
|
||||
static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Initialize connection monitoring thresholds */
|
||||
ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacon filtering */
|
||||
ret = wl1271_init_sta_beacon_filter(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Beacons and broadcast settings */
|
||||
ret = wl1271_init_beacon_broadcast(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure rssi/snr averaging weights */
|
||||
ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vif-specific intialization */
|
||||
static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* initialize Tx power */
|
||||
ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct conf_tx_ac_category *conf_ac;
|
||||
struct conf_tx_tid *conf_tid;
|
||||
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||
int ret, i;
|
||||
|
||||
/*
|
||||
* consider all existing roles before configuring psm.
|
||||
* TODO: reconfigure on interface removal.
|
||||
*/
|
||||
if (!wl->ap_count) {
|
||||
if (is_ap) {
|
||||
/* Configure for power always on */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (!wl->sta_count) {
|
||||
/* Configure for ELP power saving */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mode specific init */
|
||||
if (is_ap) {
|
||||
ret = wl1271_ap_hw_init(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_init_ap_role(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
ret = wl1271_sta_hw_init(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_init_sta_role(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
wl12xx_init_phy_vif_config(wl, wlvif);
|
||||
|
||||
/* Default TID/AC configuration */
|
||||
BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
|
||||
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
|
||||
conf_ac = &wl->conf.tx.ac_conf[i];
|
||||
ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac,
|
||||
conf_ac->cw_min, conf_ac->cw_max,
|
||||
conf_ac->aifsn, conf_ac->tx_op_limit);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
conf_tid = &wl->conf.tx.tid_conf[i];
|
||||
ret = wl1271_acx_tid_cfg(wl, wlvif,
|
||||
conf_tid->queue_id,
|
||||
conf_tid->channel_type,
|
||||
conf_tid->tsid,
|
||||
conf_tid->ps_scheme,
|
||||
conf_tid->ack_policy,
|
||||
conf_tid->apsd_conf[0],
|
||||
conf_tid->apsd_conf[1]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure HW encryption */
|
||||
ret = wl1271_acx_feature_cfg(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Mode specific init - post mem init */
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_hw_init_post_mem(wl, vif);
|
||||
else
|
||||
ret = wl1271_sta_hw_init_post_mem(wl, vif);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure initiator BA sessions policies */
|
||||
ret = wl1271_set_ba_policies(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_hw_init(struct wl1271 *wl)
|
||||
{
|
||||
struct conf_tx_ac_category *conf_ac;
|
||||
struct conf_tx_tid *conf_tid;
|
||||
int ret, i;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
int ret;
|
||||
|
||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
||||
ret = wl128x_cmd_general_parms(wl);
|
||||
@ -602,12 +678,17 @@ int wl1271_hw_init(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Mode specific init */
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_hw_init(wl);
|
||||
else
|
||||
ret = wl1271_sta_hw_init(wl);
|
||||
/* Init templates */
|
||||
ret = wl1271_init_templates_config(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl12xx_acx_mem_cfg(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure the FW logger */
|
||||
ret = wl12xx_init_fwlog(wl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -655,61 +736,20 @@ int wl1271_hw_init(struct wl1271 *wl)
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Default TID/AC configuration */
|
||||
BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
|
||||
for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
|
||||
conf_ac = &wl->conf.tx.ac_conf[i];
|
||||
ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
|
||||
conf_ac->cw_max, conf_ac->aifsn,
|
||||
conf_ac->tx_op_limit);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
conf_tid = &wl->conf.tx.tid_conf[i];
|
||||
ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
|
||||
conf_tid->channel_type,
|
||||
conf_tid->tsid,
|
||||
conf_tid->ps_scheme,
|
||||
conf_tid->ack_policy,
|
||||
conf_tid->apsd_conf[0],
|
||||
conf_tid->apsd_conf[1]);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
}
|
||||
|
||||
/* Enable data path */
|
||||
ret = wl1271_cmd_data_path(wl, 1);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure HW encryption */
|
||||
ret = wl1271_acx_feature_cfg(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* configure PM */
|
||||
ret = wl1271_acx_pm_config(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Mode specific init - post mem init */
|
||||
if (is_ap)
|
||||
ret = wl1271_ap_hw_init_post_mem(wl);
|
||||
else
|
||||
ret = wl1271_sta_hw_init_post_mem(wl);
|
||||
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
ret = wl12xx_acx_set_rate_mgmt_params(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* Configure initiator BA sessions policies */
|
||||
ret = wl1271_set_ba_policies(wl);
|
||||
if (ret < 0)
|
||||
goto out_free_memmap;
|
||||
|
||||
/* configure hangover */
|
||||
ret = wl12xx_acx_config_hangover(wl);
|
||||
if (ret < 0)
|
||||
|
@ -27,13 +27,14 @@
|
||||
#include "wl12xx.h"
|
||||
|
||||
int wl1271_hw_init_power_auth(struct wl1271 *wl);
|
||||
int wl1271_sta_init_templates_config(struct wl1271 *wl);
|
||||
int wl1271_init_templates_config(struct wl1271 *wl);
|
||||
int wl1271_init_phy_config(struct wl1271 *wl);
|
||||
int wl1271_init_pta(struct wl1271 *wl);
|
||||
int wl1271_init_energy_detection(struct wl1271 *wl);
|
||||
int wl1271_chip_specific_init(struct wl1271 *wl);
|
||||
int wl1271_hw_init(struct wl1271 *wl);
|
||||
int wl1271_init_ap_rates(struct wl1271 *wl);
|
||||
int wl1271_ap_init_templates(struct wl1271 *wl);
|
||||
int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif);
|
||||
int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif);
|
||||
|
||||
#endif
|
||||
|
@ -24,8 +24,10 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "wl12xx_80211.h"
|
||||
#include "io.h"
|
||||
#include "tx.h"
|
||||
@ -46,7 +48,7 @@
|
||||
bool wl1271_set_block_size(struct wl1271 *wl)
|
||||
{
|
||||
if (wl->if_ops->set_block_size) {
|
||||
wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE);
|
||||
wl->if_ops->set_block_size(wl->dev, WL12XX_BUS_BLOCK_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -55,12 +57,12 @@ bool wl1271_set_block_size(struct wl1271 *wl)
|
||||
|
||||
void wl1271_disable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
wl->if_ops->disable_irq(wl);
|
||||
disable_irq(wl->irq);
|
||||
}
|
||||
|
||||
void wl1271_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
wl->if_ops->enable_irq(wl);
|
||||
enable_irq(wl->irq);
|
||||
}
|
||||
|
||||
/* Set the SPI partitions to access the chip addresses
|
||||
@ -128,13 +130,13 @@ EXPORT_SYMBOL_GPL(wl1271_set_partition);
|
||||
void wl1271_io_reset(struct wl1271 *wl)
|
||||
{
|
||||
if (wl->if_ops->reset)
|
||||
wl->if_ops->reset(wl);
|
||||
wl->if_ops->reset(wl->dev);
|
||||
}
|
||||
|
||||
void wl1271_io_init(struct wl1271 *wl)
|
||||
{
|
||||
if (wl->if_ops->init)
|
||||
wl->if_ops->init(wl);
|
||||
wl->if_ops->init(wl->dev);
|
||||
}
|
||||
|
||||
void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
|
||||
|
@ -51,23 +51,17 @@ void wl1271_enable_interrupts(struct wl1271 *wl);
|
||||
void wl1271_io_reset(struct wl1271 *wl);
|
||||
void wl1271_io_init(struct wl1271 *wl);
|
||||
|
||||
static inline struct device *wl1271_wl_to_dev(struct wl1271 *wl)
|
||||
{
|
||||
return wl->if_ops->dev(wl);
|
||||
}
|
||||
|
||||
|
||||
/* Raw target IO, address is not translated */
|
||||
static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
wl->if_ops->write(wl, addr, buf, len, fixed);
|
||||
wl->if_ops->write(wl->dev, addr, buf, len, fixed);
|
||||
}
|
||||
|
||||
static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
wl->if_ops->read(wl, addr, buf, len, fixed);
|
||||
wl->if_ops->read(wl->dev, addr, buf, len, fixed);
|
||||
}
|
||||
|
||||
static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
|
||||
@ -155,13 +149,13 @@ static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
|
||||
|
||||
static inline void wl1271_power_off(struct wl1271 *wl)
|
||||
{
|
||||
wl->if_ops->power(wl, false);
|
||||
wl->if_ops->power(wl->dev, false);
|
||||
clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
|
||||
}
|
||||
|
||||
static inline int wl1271_power_on(struct wl1271 *wl)
|
||||
{
|
||||
int ret = wl->if_ops->power(wl, true);
|
||||
int ret = wl->if_ops->power(wl->dev, true);
|
||||
if (ret == 0)
|
||||
set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
|
||||
|
||||
@ -176,15 +170,10 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
|
||||
int wl1271_set_partition(struct wl1271 *wl,
|
||||
struct wl1271_partition_set *p);
|
||||
|
||||
bool wl1271_set_block_size(struct wl1271 *wl);
|
||||
|
||||
/* Functions from wl1271_main.c */
|
||||
|
||||
int wl1271_register_hw(struct wl1271 *wl);
|
||||
void wl1271_unregister_hw(struct wl1271 *wl);
|
||||
int wl1271_init_ieee80211(struct wl1271 *wl);
|
||||
struct ieee80211_hw *wl1271_alloc_hw(void);
|
||||
int wl1271_free_hw(struct wl1271 *wl);
|
||||
irqreturn_t wl1271_irq(int irq, void *data);
|
||||
bool wl1271_set_block_size(struct wl1271 *wl);
|
||||
int wl1271_tx_dummy_packet(struct wl1271 *wl);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,6 +25,7 @@
|
||||
#include "ps.h"
|
||||
#include "io.h"
|
||||
#include "tx.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define WL1271_WAKEUP_TIMEOUT 500
|
||||
|
||||
@ -32,6 +33,7 @@ void wl1271_elp_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork;
|
||||
struct wl1271 *wl;
|
||||
struct wl12xx_vif *wlvif;
|
||||
|
||||
dwork = container_of(work, struct delayed_work, work);
|
||||
wl = container_of(dwork, struct wl1271, elp_work);
|
||||
@ -47,11 +49,15 @@ void wl1271_elp_work(struct work_struct *work)
|
||||
if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
|
||||
goto out;
|
||||
|
||||
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
|
||||
(!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
|
||||
!test_bit(WL1271_FLAG_IDLE, &wl->flags)))
|
||||
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
|
||||
goto out;
|
||||
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
|
||||
!test_bit(WL1271_FLAG_IDLE, &wl->flags))
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl1271_debug(DEBUG_PSM, "chip to elp");
|
||||
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
|
||||
set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
|
||||
@ -65,13 +71,17 @@ out:
|
||||
/* Routines to toggle sleep mode while in ELP */
|
||||
void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
|
||||
/* we shouldn't get consecutive sleep requests */
|
||||
if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
|
||||
return;
|
||||
|
||||
if (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
|
||||
!test_bit(WL1271_FLAG_IDLE, &wl->flags))
|
||||
return;
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags) &&
|
||||
!test_bit(WL1271_FLAG_IDLE, &wl->flags))
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
|
||||
msecs_to_jiffies(ELP_ENTRY_DELAY));
|
||||
@ -143,8 +153,8 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
|
||||
u32 rates, bool send)
|
||||
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum wl1271_cmd_ps_mode mode, u32 rates, bool send)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -152,39 +162,34 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
|
||||
case STATION_POWER_SAVE_MODE:
|
||||
wl1271_debug(DEBUG_PSM, "entering psm");
|
||||
|
||||
ret = wl1271_acx_wake_up_conditions(wl);
|
||||
ret = wl1271_acx_wake_up_conditions(wl, wlvif);
|
||||
if (ret < 0) {
|
||||
wl1271_error("couldn't set wake up conditions");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
|
||||
ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
set_bit(WL1271_FLAG_PSM, &wl->flags);
|
||||
set_bit(WLVIF_FLAG_PSM, &wlvif->flags);
|
||||
break;
|
||||
case STATION_ACTIVE_MODE:
|
||||
default:
|
||||
wl1271_debug(DEBUG_PSM, "leaving psm");
|
||||
|
||||
/* disable beacon early termination */
|
||||
if (wl->band == IEEE80211_BAND_2GHZ) {
|
||||
ret = wl1271_acx_bet_enable(wl, false);
|
||||
if (wlvif->band == IEEE80211_BAND_2GHZ) {
|
||||
ret = wl1271_acx_bet_enable(wl, wlvif, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* disable beacon filtering */
|
||||
ret = wl1271_acx_beacon_filter_opt(wl, false);
|
||||
ret = wl1271_cmd_ps_mode(wl, wlvif, STATION_ACTIVE_MODE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
clear_bit(WL1271_FLAG_PSM, &wl->flags);
|
||||
clear_bit(WLVIF_FLAG_PSM, &wlvif->flags);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -223,9 +228,11 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
|
||||
wl1271_handle_tx_low_watermark(wl);
|
||||
}
|
||||
|
||||
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
|
||||
void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 hlid, bool clean_queues)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
if (test_bit(hlid, &wl->ap_ps_map))
|
||||
return;
|
||||
@ -235,7 +242,7 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
|
||||
clean_queues);
|
||||
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr);
|
||||
sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
|
||||
if (!sta) {
|
||||
wl1271_error("could not find sta %pM for starting ps",
|
||||
wl->links[hlid].addr);
|
||||
@ -253,9 +260,10 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
|
||||
__set_bit(hlid, &wl->ap_ps_map);
|
||||
}
|
||||
|
||||
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid)
|
||||
void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
if (!test_bit(hlid, &wl->ap_ps_map))
|
||||
return;
|
||||
@ -265,7 +273,7 @@ void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid)
|
||||
__clear_bit(hlid, &wl->ap_ps_map);
|
||||
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr);
|
||||
sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
|
||||
if (!sta) {
|
||||
wl1271_error("could not find sta %pM for ending ps",
|
||||
wl->links[hlid].addr);
|
||||
|
@ -27,13 +27,14 @@
|
||||
#include "wl12xx.h"
|
||||
#include "acx.h"
|
||||
|
||||
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
|
||||
u32 rates, bool send);
|
||||
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
enum wl1271_cmd_ps_mode mode, u32 rates, bool send);
|
||||
void wl1271_ps_elp_sleep(struct wl1271 *wl);
|
||||
int wl1271_ps_elp_wakeup(struct wl1271 *wl);
|
||||
void wl1271_elp_work(struct work_struct *work);
|
||||
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues);
|
||||
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid);
|
||||
void wl12xx_ps_link_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
u8 hlid, bool clean_queues);
|
||||
void wl12xx_ps_link_end(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
|
||||
|
||||
#define WL1271_PS_COMPLETE_TIMEOUT 500
|
||||
|
||||
|
@ -408,7 +408,7 @@
|
||||
|
||||
|
||||
/* Firmware image load chunk size */
|
||||
#define CHUNK_SIZE 512
|
||||
#define CHUNK_SIZE 16384
|
||||
|
||||
/* Firmware image header size */
|
||||
#define FW_HDR_SIZE 8
|
||||
|
@ -25,9 +25,11 @@
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "acx.h"
|
||||
#include "reg.h"
|
||||
#include "rx.h"
|
||||
#include "tx.h"
|
||||
#include "io.h"
|
||||
|
||||
static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status,
|
||||
@ -96,7 +98,7 @@ static void wl1271_rx_status(struct wl1271 *wl,
|
||||
}
|
||||
|
||||
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||
bool unaligned)
|
||||
bool unaligned, u8 *hlid)
|
||||
{
|
||||
struct wl1271_rx_descriptor *desc;
|
||||
struct sk_buff *skb;
|
||||
@ -159,6 +161,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||
* payload aligned to 4 bytes.
|
||||
*/
|
||||
memcpy(buf, data + sizeof(*desc), length - sizeof(*desc));
|
||||
*hlid = desc->hlid;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (ieee80211_is_beacon(hdr->frame_control))
|
||||
@ -169,10 +172,10 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
|
||||
|
||||
seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
|
||||
wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d", skb,
|
||||
wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb,
|
||||
skb->len - desc->pad_len,
|
||||
beacon ? "beacon" : "",
|
||||
seq_num);
|
||||
seq_num, *hlid);
|
||||
|
||||
skb_trim(skb, skb->len - desc->pad_len);
|
||||
|
||||
@ -185,6 +188,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||
void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
||||
{
|
||||
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
|
||||
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
|
||||
u32 buf_size;
|
||||
u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
||||
u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
|
||||
@ -192,8 +196,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
||||
u32 mem_block;
|
||||
u32 pkt_length;
|
||||
u32 pkt_offset;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
bool had_data = false;
|
||||
u8 hlid;
|
||||
bool unaligned = false;
|
||||
|
||||
while (drv_rx_counter != fw_rx_counter) {
|
||||
@ -253,8 +256,11 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
||||
*/
|
||||
if (wl1271_rx_handle_data(wl,
|
||||
wl->aggr_buf + pkt_offset,
|
||||
pkt_length, unaligned) == 1)
|
||||
had_data = true;
|
||||
pkt_length, unaligned,
|
||||
&hlid) == 1) {
|
||||
WARN_ON(hlid >= WL12XX_MAX_LINKS);
|
||||
__set_bit(hlid, active_hlids);
|
||||
}
|
||||
|
||||
wl->rx_counter++;
|
||||
drv_rx_counter++;
|
||||
@ -270,17 +276,5 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
|
||||
if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION)
|
||||
wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
|
||||
|
||||
if (!is_ap && wl->conf.rx_streaming.interval && had_data &&
|
||||
(wl->conf.rx_streaming.always ||
|
||||
test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) {
|
||||
u32 timeout = wl->conf.rx_streaming.duration;
|
||||
|
||||
/* restart rx streaming */
|
||||
if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
|
||||
ieee80211_queue_work(wl->hw,
|
||||
&wl->rx_streaming_enable_work);
|
||||
|
||||
mod_timer(&wl->rx_streaming_timer,
|
||||
jiffies + msecs_to_jiffies(timeout));
|
||||
}
|
||||
wl12xx_rearm_rx_streaming(wl, active_hlids);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/ieee80211.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "cmd.h"
|
||||
#include "scan.h"
|
||||
#include "acx.h"
|
||||
@ -34,6 +35,8 @@ void wl1271_scan_complete_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork;
|
||||
struct wl1271 *wl;
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
int ret;
|
||||
bool is_sta, is_ibss;
|
||||
|
||||
@ -50,28 +53,31 @@ void wl1271_scan_complete_work(struct work_struct *work)
|
||||
if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
|
||||
goto out;
|
||||
|
||||
vif = wl->scan_vif;
|
||||
wlvif = wl12xx_vif_to_data(vif);
|
||||
|
||||
wl->scan.state = WL1271_SCAN_STATE_IDLE;
|
||||
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
|
||||
wl->scan.req = NULL;
|
||||
wl->scan_vif = NULL;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
|
||||
if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
|
||||
/* restore hardware connection monitoring template */
|
||||
wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
|
||||
wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq);
|
||||
}
|
||||
|
||||
/* return to ROC if needed */
|
||||
is_sta = (wl->bss_type == BSS_TYPE_STA_BSS);
|
||||
is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
|
||||
if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ||
|
||||
(is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) &&
|
||||
!test_bit(wl->dev_role_id, wl->roc_map)) {
|
||||
is_sta = (wlvif->bss_type == BSS_TYPE_STA_BSS);
|
||||
is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
|
||||
if (((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) ||
|
||||
(is_ibss && !test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))) &&
|
||||
!test_bit(wlvif->dev_role_id, wl->roc_map)) {
|
||||
/* restore remain on channel */
|
||||
wl12xx_cmd_role_start_dev(wl);
|
||||
wl12xx_roc(wl, wl->dev_role_id);
|
||||
wl12xx_start_dev(wl, wlvif);
|
||||
}
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
|
||||
@ -155,9 +161,11 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
|
||||
|
||||
#define WL1271_NOTHING_TO_SCAN 1
|
||||
|
||||
static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
|
||||
bool passive, u32 basic_rate)
|
||||
static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
|
||||
enum ieee80211_band band,
|
||||
bool passive, u32 basic_rate)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
struct wl1271_cmd_scan *cmd;
|
||||
struct wl1271_cmd_trigger_scan_to *trigger;
|
||||
int ret;
|
||||
@ -177,11 +185,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
|
||||
if (passive)
|
||||
scan_options |= WL1271_SCAN_OPT_PASSIVE;
|
||||
|
||||
if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) {
|
||||
if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
cmd->params.role_id = wl->role_id;
|
||||
cmd->params.role_id = wlvif->role_id;
|
||||
cmd->params.scan_options = cpu_to_le16(scan_options);
|
||||
|
||||
cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
|
||||
@ -194,7 +202,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
|
||||
|
||||
cmd->params.tx_rate = cpu_to_le32(basic_rate);
|
||||
cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
|
||||
cmd->params.tx_rate = cpu_to_le32(basic_rate);
|
||||
cmd->params.tid_trigger = 0;
|
||||
cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
|
||||
|
||||
@ -208,11 +215,11 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
|
||||
memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
|
||||
}
|
||||
|
||||
memcpy(cmd->addr, wl->mac_addr, ETH_ALEN);
|
||||
memcpy(cmd->addr, vif->addr, ETH_ALEN);
|
||||
|
||||
ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
|
||||
wl->scan.req->ie, wl->scan.req->ie_len,
|
||||
band);
|
||||
ret = wl1271_cmd_build_probe_req(wl, wlvif, wl->scan.ssid,
|
||||
wl->scan.ssid_len, wl->scan.req->ie,
|
||||
wl->scan.req->ie_len, band);
|
||||
if (ret < 0) {
|
||||
wl1271_error("PROBE request template failed");
|
||||
goto out;
|
||||
@ -241,11 +248,12 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wl1271_scan_stm(struct wl1271 *wl)
|
||||
void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret = 0;
|
||||
enum ieee80211_band band;
|
||||
u32 rate;
|
||||
u32 rate, mask;
|
||||
|
||||
switch (wl->scan.state) {
|
||||
case WL1271_SCAN_STATE_IDLE:
|
||||
@ -253,47 +261,59 @@ void wl1271_scan_stm(struct wl1271 *wl)
|
||||
|
||||
case WL1271_SCAN_STATE_2GHZ_ACTIVE:
|
||||
band = IEEE80211_BAND_2GHZ;
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, band, false, rate);
|
||||
mask = wlvif->bitrate_masks[band];
|
||||
if (wl->scan.req->no_cck) {
|
||||
mask &= ~CONF_TX_CCK_RATES;
|
||||
if (!mask)
|
||||
mask = CONF_TX_RATE_MASK_BASIC_P2P;
|
||||
}
|
||||
rate = wl1271_tx_min_rate_get(wl, mask);
|
||||
ret = wl1271_scan_send(wl, vif, band, false, rate);
|
||||
if (ret == WL1271_NOTHING_TO_SCAN) {
|
||||
wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WL1271_SCAN_STATE_2GHZ_PASSIVE:
|
||||
band = IEEE80211_BAND_2GHZ;
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, band, true, rate);
|
||||
mask = wlvif->bitrate_masks[band];
|
||||
if (wl->scan.req->no_cck) {
|
||||
mask &= ~CONF_TX_CCK_RATES;
|
||||
if (!mask)
|
||||
mask = CONF_TX_RATE_MASK_BASIC_P2P;
|
||||
}
|
||||
rate = wl1271_tx_min_rate_get(wl, mask);
|
||||
ret = wl1271_scan_send(wl, vif, band, true, rate);
|
||||
if (ret == WL1271_NOTHING_TO_SCAN) {
|
||||
if (wl->enable_11a)
|
||||
wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
|
||||
else
|
||||
wl->scan.state = WL1271_SCAN_STATE_DONE;
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WL1271_SCAN_STATE_5GHZ_ACTIVE:
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, band, false, rate);
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, vif, band, false, rate);
|
||||
if (ret == WL1271_NOTHING_TO_SCAN) {
|
||||
wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WL1271_SCAN_STATE_5GHZ_PASSIVE:
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, band, true, rate);
|
||||
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
|
||||
ret = wl1271_scan_send(wl, vif, band, true, rate);
|
||||
if (ret == WL1271_NOTHING_TO_SCAN) {
|
||||
wl->scan.state = WL1271_SCAN_STATE_DONE;
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -317,7 +337,8 @@ void wl1271_scan_stm(struct wl1271 *wl)
|
||||
}
|
||||
}
|
||||
|
||||
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
||||
int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
struct cfg80211_scan_request *req)
|
||||
{
|
||||
/*
|
||||
@ -338,6 +359,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
||||
wl->scan.ssid_len = 0;
|
||||
}
|
||||
|
||||
wl->scan_vif = vif;
|
||||
wl->scan.req = req;
|
||||
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
|
||||
|
||||
@ -346,7 +368,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
|
||||
msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
|
||||
|
||||
wl1271_scan_stm(wl);
|
||||
wl1271_scan_stm(wl, vif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -550,6 +572,9 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
|
||||
* so they're used in probe requests.
|
||||
*/
|
||||
for (i = 0; i < req->n_ssids; i++) {
|
||||
if (!req->ssids[i].ssid_len)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < cmd->n_ssids; j++)
|
||||
if (!memcmp(req->ssids[i].ssid,
|
||||
cmd->ssids[j].ssid,
|
||||
@ -585,6 +610,7 @@ out:
|
||||
}
|
||||
|
||||
int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies)
|
||||
{
|
||||
@ -631,7 +657,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
||||
}
|
||||
|
||||
if (!force_passive && cfg->active[0]) {
|
||||
ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
|
||||
ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
|
||||
req->ssids[0].ssid_len,
|
||||
ies->ie[IEEE80211_BAND_2GHZ],
|
||||
ies->len[IEEE80211_BAND_2GHZ],
|
||||
@ -643,7 +669,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
||||
}
|
||||
|
||||
if (!force_passive && cfg->active[1]) {
|
||||
ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
|
||||
ret = wl1271_cmd_build_probe_req(wl, wlvif, req->ssids[0].ssid,
|
||||
req->ssids[0].ssid_len,
|
||||
ies->ie[IEEE80211_BAND_5GHZ],
|
||||
ies->len[IEEE80211_BAND_5GHZ],
|
||||
@ -667,14 +693,14 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wl1271_scan_sched_scan_start(struct wl1271 *wl)
|
||||
int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct wl1271_cmd_sched_scan_start *start;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
|
||||
|
||||
if (wl->bss_type != BSS_TYPE_STA_BSS)
|
||||
if (wlvif->bss_type != BSS_TYPE_STA_BSS)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!test_bit(WL1271_FLAG_IDLE, &wl->flags))
|
||||
|
@ -26,18 +26,20 @@
|
||||
|
||||
#include "wl12xx.h"
|
||||
|
||||
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
||||
int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
struct cfg80211_scan_request *req);
|
||||
int wl1271_scan_stop(struct wl1271 *wl);
|
||||
int wl1271_scan_build_probe_req(struct wl1271 *wl,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len, u8 band);
|
||||
void wl1271_scan_stm(struct wl1271 *wl);
|
||||
void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif);
|
||||
void wl1271_scan_complete_work(struct work_struct *work);
|
||||
int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies);
|
||||
int wl1271_scan_sched_scan_start(struct wl1271 *wl);
|
||||
int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
void wl1271_scan_sched_scan_stop(struct wl1271 *wl);
|
||||
void wl1271_scan_sched_scan_results(struct wl1271 *wl);
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/card.h>
|
||||
@ -44,107 +45,67 @@
|
||||
#define SDIO_DEVICE_ID_TI_WL1271 0x4076
|
||||
#endif
|
||||
|
||||
struct wl12xx_sdio_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *core;
|
||||
};
|
||||
|
||||
static const struct sdio_device_id wl1271_devices[] __devinitconst = {
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(sdio, wl1271_devices);
|
||||
|
||||
static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz)
|
||||
static void wl1271_sdio_set_block_size(struct device *child,
|
||||
unsigned int blksz)
|
||||
{
|
||||
sdio_claim_host(wl->if_priv);
|
||||
sdio_set_block_size(wl->if_priv, blksz);
|
||||
sdio_release_host(wl->if_priv);
|
||||
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
sdio_claim_host(func);
|
||||
sdio_set_block_size(func, blksz);
|
||||
sdio_release_host(func);
|
||||
}
|
||||
|
||||
static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
|
||||
{
|
||||
return wl->if_priv;
|
||||
}
|
||||
|
||||
static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
|
||||
{
|
||||
return &(wl_to_func(wl)->dev);
|
||||
}
|
||||
|
||||
static irqreturn_t wl1271_hardirq(int irq, void *cookie)
|
||||
{
|
||||
struct wl1271 *wl = cookie;
|
||||
unsigned long flags;
|
||||
|
||||
wl1271_debug(DEBUG_IRQ, "IRQ");
|
||||
|
||||
/* complete the ELP completion */
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
|
||||
if (wl->elp_compl) {
|
||||
complete(wl->elp_compl);
|
||||
wl->elp_compl = NULL;
|
||||
}
|
||||
|
||||
if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
|
||||
/* don't enqueue a work right now. mark it as pending */
|
||||
set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
|
||||
wl1271_debug(DEBUG_IRQ, "should not enqueue work");
|
||||
disable_irq_nosync(wl->irq);
|
||||
pm_wakeup_event(wl1271_sdio_wl_to_dev(wl), 0);
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static void wl1271_sdio_disable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
disable_irq(wl->irq);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
enable_irq(wl->irq);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
int ret;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
||||
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
} else {
|
||||
if (fixed)
|
||||
ret = sdio_readsb(func, buf, addr, len);
|
||||
else
|
||||
ret = sdio_memcpy_fromio(func, buf, addr, len);
|
||||
|
||||
wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes",
|
||||
addr, len);
|
||||
wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
|
||||
dev_dbg(child->parent, "sdio read 53 addr 0x%x, %zu bytes\n",
|
||||
addr, len);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
wl1271_error("sdio read failed (%d)", ret);
|
||||
dev_err(child->parent, "sdio read failed (%d)\n", ret);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
int ret;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
||||
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
} else {
|
||||
wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes",
|
||||
addr, len);
|
||||
wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
|
||||
dev_dbg(child->parent, "sdio write 53 addr 0x%x, %zu bytes\n",
|
||||
addr, len);
|
||||
|
||||
if (fixed)
|
||||
ret = sdio_writesb(func, addr, buf, len);
|
||||
@ -153,13 +114,13 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
}
|
||||
|
||||
if (ret)
|
||||
wl1271_error("sdio write failed (%d)", ret);
|
||||
dev_err(child->parent, "sdio write failed (%d)\n", ret);
|
||||
}
|
||||
|
||||
static int wl1271_sdio_power_on(struct wl1271 *wl)
|
||||
static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue)
|
||||
{
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
int ret;
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
/* If enabled, tell runtime PM not to power off the card */
|
||||
if (pm_runtime_enabled(&func->dev)) {
|
||||
@ -180,10 +141,10 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_sdio_power_off(struct wl1271 *wl)
|
||||
static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue)
|
||||
{
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
int ret;
|
||||
struct sdio_func *func = dev_to_sdio_func(glue->dev);
|
||||
|
||||
sdio_disable_func(func);
|
||||
sdio_release_host(func);
|
||||
@ -200,46 +161,43 @@ static int wl1271_sdio_power_off(struct wl1271 *wl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
|
||||
static int wl12xx_sdio_set_power(struct device *child, bool enable)
|
||||
{
|
||||
struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
|
||||
|
||||
if (enable)
|
||||
return wl1271_sdio_power_on(wl);
|
||||
return wl12xx_sdio_power_on(glue);
|
||||
else
|
||||
return wl1271_sdio_power_off(wl);
|
||||
return wl12xx_sdio_power_off(glue);
|
||||
}
|
||||
|
||||
static struct wl1271_if_operations sdio_ops = {
|
||||
.read = wl1271_sdio_raw_read,
|
||||
.write = wl1271_sdio_raw_write,
|
||||
.power = wl1271_sdio_set_power,
|
||||
.dev = wl1271_sdio_wl_to_dev,
|
||||
.enable_irq = wl1271_sdio_enable_interrupts,
|
||||
.disable_irq = wl1271_sdio_disable_interrupts,
|
||||
.read = wl12xx_sdio_raw_read,
|
||||
.write = wl12xx_sdio_raw_write,
|
||||
.power = wl12xx_sdio_set_power,
|
||||
.set_block_size = wl1271_sdio_set_block_size,
|
||||
};
|
||||
|
||||
static int __devinit wl1271_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
struct ieee80211_hw *hw;
|
||||
const struct wl12xx_platform_data *wlan_data;
|
||||
struct wl1271 *wl;
|
||||
unsigned long irqflags;
|
||||
struct wl12xx_platform_data *wlan_data;
|
||||
struct wl12xx_sdio_glue *glue;
|
||||
struct resource res[1];
|
||||
mmc_pm_flag_t mmcflags;
|
||||
int ret;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* We are only able to handle the wlan function */
|
||||
if (func->num != 0x02)
|
||||
return -ENODEV;
|
||||
|
||||
hw = wl1271_alloc_hw();
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&func->dev, "can't allocate glue\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl = hw->priv;
|
||||
|
||||
wl->if_priv = func;
|
||||
wl->if_ops = &sdio_ops;
|
||||
glue->dev = &func->dev;
|
||||
|
||||
/* Grab access to FN0 for ELP reg. */
|
||||
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
|
||||
@ -250,80 +208,79 @@ static int __devinit wl1271_probe(struct sdio_func *func,
|
||||
wlan_data = wl12xx_get_platform_data();
|
||||
if (IS_ERR(wlan_data)) {
|
||||
ret = PTR_ERR(wlan_data);
|
||||
wl1271_error("missing wlan platform data: %d", ret);
|
||||
goto out_free;
|
||||
dev_err(glue->dev, "missing wlan platform data: %d\n", ret);
|
||||
goto out_free_glue;
|
||||
}
|
||||
|
||||
wl->irq = wlan_data->irq;
|
||||
wl->ref_clock = wlan_data->board_ref_clock;
|
||||
wl->tcxo_clock = wlan_data->board_tcxo_clock;
|
||||
wl->platform_quirks = wlan_data->platform_quirks;
|
||||
/* if sdio can keep power while host is suspended, enable wow */
|
||||
mmcflags = sdio_get_host_pm_caps(func);
|
||||
dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
|
||||
|
||||
if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
|
||||
irqflags = IRQF_TRIGGER_RISING;
|
||||
else
|
||||
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
|
||||
if (mmcflags & MMC_PM_KEEP_POWER)
|
||||
wlan_data->pwr_in_suspend = true;
|
||||
|
||||
ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
|
||||
irqflags,
|
||||
DRIVER_NAME, wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("request_irq() failed: %d", ret);
|
||||
goto out_free;
|
||||
}
|
||||
wlan_data->ops = &sdio_ops;
|
||||
|
||||
ret = enable_irq_wake(wl->irq);
|
||||
if (!ret) {
|
||||
wl->irq_wake_enabled = true;
|
||||
device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1);
|
||||
|
||||
/* if sdio can keep power while host is suspended, enable wow */
|
||||
mmcflags = sdio_get_host_pm_caps(func);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags);
|
||||
|
||||
if (mmcflags & MMC_PM_KEEP_POWER)
|
||||
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
|
||||
}
|
||||
disable_irq(wl->irq);
|
||||
|
||||
ret = wl1271_init_ieee80211(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
|
||||
ret = wl1271_register_hw(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
|
||||
sdio_set_drvdata(func, wl);
|
||||
sdio_set_drvdata(func, glue);
|
||||
|
||||
/* Tell PM core that we don't need the card to be powered now */
|
||||
pm_runtime_put_noidle(&func->dev);
|
||||
|
||||
glue->core = platform_device_alloc("wl12xx", -1);
|
||||
if (!glue->core) {
|
||||
dev_err(glue->dev, "can't allocate platform_device");
|
||||
ret = -ENOMEM;
|
||||
goto out_free_glue;
|
||||
}
|
||||
|
||||
glue->core->dev.parent = &func->dev;
|
||||
|
||||
memset(res, 0x00, sizeof(res));
|
||||
|
||||
res[0].start = wlan_data->irq;
|
||||
res[0].flags = IORESOURCE_IRQ;
|
||||
res[0].name = "irq";
|
||||
|
||||
ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res));
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add resources\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(glue->core, wlan_data,
|
||||
sizeof(*wlan_data));
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add platform data\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
ret = platform_device_add(glue->core);
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add platform device\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out_irq:
|
||||
free_irq(wl->irq, wl);
|
||||
out_dev_put:
|
||||
platform_device_put(glue->core);
|
||||
|
||||
out_free:
|
||||
wl1271_free_hw(wl);
|
||||
out_free_glue:
|
||||
kfree(glue);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit wl1271_remove(struct sdio_func *func)
|
||||
{
|
||||
struct wl1271 *wl = sdio_get_drvdata(func);
|
||||
struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
|
||||
|
||||
/* Undo decrement done above in wl1271_probe */
|
||||
pm_runtime_get_noresume(&func->dev);
|
||||
|
||||
wl1271_unregister_hw(wl);
|
||||
if (wl->irq_wake_enabled) {
|
||||
device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0);
|
||||
disable_irq_wake(wl->irq);
|
||||
}
|
||||
free_irq(wl->irq, wl);
|
||||
wl1271_free_hw(wl);
|
||||
platform_device_del(glue->core);
|
||||
platform_device_put(glue->core);
|
||||
kfree(glue);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@ -332,20 +289,21 @@ static int wl1271_suspend(struct device *dev)
|
||||
/* Tell MMC/SDIO core it's OK to power down the card
|
||||
* (if it isn't already), but not to remove it completely */
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct wl1271 *wl = sdio_get_drvdata(func);
|
||||
struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
|
||||
struct wl1271 *wl = platform_get_drvdata(glue->core);
|
||||
mmc_pm_flag_t sdio_flags;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d",
|
||||
wl->wow_enabled);
|
||||
dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n",
|
||||
wl->wow_enabled);
|
||||
|
||||
/* check whether sdio should keep power */
|
||||
if (wl->wow_enabled) {
|
||||
sdio_flags = sdio_get_host_pm_caps(func);
|
||||
|
||||
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
|
||||
wl1271_error("can't keep power while host "
|
||||
"is suspended");
|
||||
dev_err(dev, "can't keep power while host "
|
||||
"is suspended\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -353,7 +311,7 @@ static int wl1271_suspend(struct device *dev)
|
||||
/* keep power while host suspended */
|
||||
ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
|
||||
if (ret) {
|
||||
wl1271_error("error while trying to keep power");
|
||||
dev_err(dev, "error while trying to keep power\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -367,9 +325,10 @@ out:
|
||||
static int wl1271_resume(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct wl1271 *wl = sdio_get_drvdata(func);
|
||||
struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
|
||||
struct wl1271 *wl = platform_get_drvdata(glue->core);
|
||||
|
||||
wl1271_debug(DEBUG_MAC80211, "wl1271 resume");
|
||||
dev_dbg(dev, "wl1271 resume\n");
|
||||
if (wl->wow_enabled) {
|
||||
/* claim back host */
|
||||
sdio_claim_host(func);
|
||||
|
@ -1,543 +0,0 @@
|
||||
/*
|
||||
* SDIO testing driver for wl12xx
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
*
|
||||
* Contact: Roger Quadros <roger.quadros@nokia.com>
|
||||
*
|
||||
* wl12xx read/write routines taken from the main module
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/crc7.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/wl12xx.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "io.h"
|
||||
#include "boot.h"
|
||||
|
||||
#ifndef SDIO_VENDOR_ID_TI
|
||||
#define SDIO_VENDOR_ID_TI 0x0097
|
||||
#endif
|
||||
|
||||
#ifndef SDIO_DEVICE_ID_TI_WL1271
|
||||
#define SDIO_DEVICE_ID_TI_WL1271 0x4076
|
||||
#endif
|
||||
|
||||
static bool rx, tx;
|
||||
|
||||
module_param(rx, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(rx, "Perform rx test. Default (0). "
|
||||
"This test continuously reads data from the SDIO device.\n");
|
||||
|
||||
module_param(tx, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(tx, "Perform tx test. Default (0). "
|
||||
"This test continuously writes data to the SDIO device.\n");
|
||||
|
||||
struct wl1271_test {
|
||||
struct wl1271 wl;
|
||||
struct task_struct *test_task;
|
||||
};
|
||||
|
||||
static const struct sdio_device_id wl1271_devices[] = {
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
|
||||
{}
|
||||
};
|
||||
|
||||
static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
|
||||
{
|
||||
return wl->if_priv;
|
||||
}
|
||||
|
||||
static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
|
||||
{
|
||||
return &(wl_to_func(wl)->dev);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
||||
((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
} else {
|
||||
if (fixed)
|
||||
ret = sdio_readsb(func, buf, addr, len);
|
||||
else
|
||||
ret = sdio_memcpy_fromio(func, buf, addr, len);
|
||||
|
||||
wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes",
|
||||
addr, len);
|
||||
wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
wl1271_error("sdio read failed (%d)", ret);
|
||||
}
|
||||
|
||||
static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
|
||||
if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
|
||||
sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
|
||||
wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
|
||||
addr, ((u8 *)buf)[0]);
|
||||
} else {
|
||||
wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes",
|
||||
addr, len);
|
||||
wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
|
||||
|
||||
if (fixed)
|
||||
ret = sdio_writesb(func, addr, buf, len);
|
||||
else
|
||||
ret = sdio_memcpy_toio(func, addr, buf, len);
|
||||
}
|
||||
if (ret)
|
||||
wl1271_error("sdio write failed (%d)", ret);
|
||||
|
||||
}
|
||||
|
||||
static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
|
||||
{
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
int ret;
|
||||
|
||||
/* Let the SDIO stack handle wlan_enable control, so we
|
||||
* keep host claimed while wlan is in use to keep wl1271
|
||||
* alive.
|
||||
*/
|
||||
if (enable) {
|
||||
/* Power up the card */
|
||||
ret = pm_runtime_get_sync(&func->dev);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* Runtime PM might be disabled, power up the card manually */
|
||||
ret = mmc_power_restore_host(func->card->host);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
sdio_claim_host(func);
|
||||
sdio_enable_func(func);
|
||||
} else {
|
||||
sdio_disable_func(func);
|
||||
sdio_release_host(func);
|
||||
|
||||
/* Runtime PM might be disabled, power off the card manually */
|
||||
ret = mmc_power_save_host(func->card->host);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* Power down the card */
|
||||
ret = pm_runtime_put_sync(&func->dev);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wl1271_sdio_disable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
}
|
||||
|
||||
static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static struct wl1271_if_operations sdio_ops = {
|
||||
.read = wl1271_sdio_raw_read,
|
||||
.write = wl1271_sdio_raw_write,
|
||||
.power = wl1271_sdio_set_power,
|
||||
.dev = wl1271_sdio_wl_to_dev,
|
||||
.enable_irq = wl1271_sdio_enable_interrupts,
|
||||
.disable_irq = wl1271_sdio_disable_interrupts,
|
||||
};
|
||||
|
||||
static void wl1271_fw_wakeup(struct wl1271 *wl)
|
||||
{
|
||||
u32 elp_reg;
|
||||
|
||||
elp_reg = ELPCTRL_WAKE_UP;
|
||||
wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
|
||||
}
|
||||
|
||||
static int wl1271_fetch_firmware(struct wl1271 *wl)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
|
||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
||||
ret = request_firmware(&fw, WL128X_FW_NAME,
|
||||
wl1271_wl_to_dev(wl));
|
||||
else
|
||||
ret = request_firmware(&fw, WL127X_FW_NAME,
|
||||
wl1271_wl_to_dev(wl));
|
||||
|
||||
if (ret < 0) {
|
||||
wl1271_error("could not get firmware: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fw->size % 4) {
|
||||
wl1271_error("firmware size is not multiple of 32 bits: %zu",
|
||||
fw->size);
|
||||
ret = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->fw_len = fw->size;
|
||||
wl->fw = vmalloc(wl->fw_len);
|
||||
|
||||
if (!wl->fw) {
|
||||
wl1271_error("could not allocate memory for the firmware");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(wl->fw, fw->data, wl->fw_len);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_fetch_nvs(struct wl1271 *wl)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
|
||||
ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
|
||||
|
||||
if (ret < 0) {
|
||||
wl1271_error("could not get nvs file: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
|
||||
if (!wl->nvs) {
|
||||
wl1271_error("could not allocate memory for the nvs file");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->nvs_len = fw->size;
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wl1271_chip_wakeup(struct wl1271 *wl)
|
||||
{
|
||||
struct wl1271_partition_set partition;
|
||||
int ret;
|
||||
|
||||
msleep(WL1271_PRE_POWER_ON_SLEEP);
|
||||
ret = wl1271_power_on(wl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msleep(WL1271_POWER_ON_SLEEP);
|
||||
|
||||
/* We don't need a real memory partition here, because we only want
|
||||
* to use the registers at this point. */
|
||||
memset(&partition, 0, sizeof(partition));
|
||||
partition.reg.start = REGISTERS_BASE;
|
||||
partition.reg.size = REGISTERS_DOWN_SIZE;
|
||||
wl1271_set_partition(wl, &partition);
|
||||
|
||||
/* ELP module wake up */
|
||||
wl1271_fw_wakeup(wl);
|
||||
|
||||
/* whal_FwCtrl_BootSm() */
|
||||
|
||||
/* 0. read chip id from CHIP_ID */
|
||||
wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
|
||||
|
||||
/* 1. check if chip id is valid */
|
||||
|
||||
switch (wl->chip.id) {
|
||||
case CHIP_ID_1271_PG10:
|
||||
wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
|
||||
wl->chip.id);
|
||||
break;
|
||||
case CHIP_ID_1271_PG20:
|
||||
wl1271_notice("chip id 0x%x (1271 PG20)",
|
||||
wl->chip.id);
|
||||
break;
|
||||
case CHIP_ID_1283_PG20:
|
||||
wl1271_notice("chip id 0x%x (1283 PG20)",
|
||||
wl->chip.id);
|
||||
break;
|
||||
case CHIP_ID_1283_PG10:
|
||||
default:
|
||||
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct wl1271_partition_set part_down = {
|
||||
.mem = {
|
||||
.start = 0x00000000,
|
||||
.size = 0x000177c0
|
||||
},
|
||||
.reg = {
|
||||
.start = REGISTERS_BASE,
|
||||
.size = 0x00008800
|
||||
},
|
||||
.mem2 = {
|
||||
.start = 0x00000000,
|
||||
.size = 0x00000000
|
||||
},
|
||||
.mem3 = {
|
||||
.start = 0x00000000,
|
||||
.size = 0x00000000
|
||||
},
|
||||
};
|
||||
|
||||
static int tester(void *data)
|
||||
{
|
||||
struct wl1271 *wl = data;
|
||||
struct sdio_func *func = wl_to_func(wl);
|
||||
struct device *pdev = &func->dev;
|
||||
int ret = 0;
|
||||
bool rx_started = 0;
|
||||
bool tx_started = 0;
|
||||
uint8_t *tx_buf, *rx_buf;
|
||||
int test_size = PAGE_SIZE;
|
||||
u32 addr = 0;
|
||||
struct wl1271_partition_set partition;
|
||||
|
||||
/* We assume chip is powered up and firmware fetched */
|
||||
|
||||
memcpy(&partition, &part_down, sizeof(partition));
|
||||
partition.mem.start = addr;
|
||||
wl1271_set_partition(wl, &partition);
|
||||
|
||||
tx_buf = kmalloc(test_size, GFP_KERNEL);
|
||||
rx_buf = kmalloc(test_size, GFP_KERNEL);
|
||||
if (!tx_buf || !rx_buf) {
|
||||
dev_err(pdev,
|
||||
"Could not allocate memory. Test will not run.\n");
|
||||
ret = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
|
||||
memset(tx_buf, 0x5a, test_size);
|
||||
|
||||
/* write something in data area so we can read it back */
|
||||
wl1271_write(wl, addr, tx_buf, test_size, false);
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
if (rx && !rx_started) {
|
||||
dev_info(pdev, "starting rx test\n");
|
||||
rx_started = 1;
|
||||
} else if (!rx && rx_started) {
|
||||
dev_info(pdev, "stopping rx test\n");
|
||||
rx_started = 0;
|
||||
}
|
||||
|
||||
if (tx && !tx_started) {
|
||||
dev_info(pdev, "starting tx test\n");
|
||||
tx_started = 1;
|
||||
} else if (!tx && tx_started) {
|
||||
dev_info(pdev, "stopping tx test\n");
|
||||
tx_started = 0;
|
||||
}
|
||||
|
||||
if (rx_started)
|
||||
wl1271_read(wl, addr, rx_buf, test_size, false);
|
||||
|
||||
if (tx_started)
|
||||
wl1271_write(wl, addr, tx_buf, test_size, false);
|
||||
|
||||
if (!rx_started && !tx_started)
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
free:
|
||||
kfree(tx_buf);
|
||||
kfree(rx_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit wl1271_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
const struct wl12xx_platform_data *wlan_data;
|
||||
struct wl1271 *wl;
|
||||
struct wl1271_test *wl_test;
|
||||
int ret = 0;
|
||||
|
||||
/* wl1271 has 2 sdio functions we handle just the wlan part */
|
||||
if (func->num != 0x02)
|
||||
return -ENODEV;
|
||||
|
||||
wl_test = kzalloc(sizeof(struct wl1271_test), GFP_KERNEL);
|
||||
if (!wl_test) {
|
||||
dev_err(&func->dev, "Could not allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wl = &wl_test->wl;
|
||||
|
||||
wl->if_priv = func;
|
||||
wl->if_ops = &sdio_ops;
|
||||
|
||||
/* Grab access to FN0 for ELP reg. */
|
||||
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
|
||||
|
||||
/* Use block mode for transferring over one block size of data */
|
||||
func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
|
||||
|
||||
wlan_data = wl12xx_get_platform_data();
|
||||
if (IS_ERR(wlan_data)) {
|
||||
ret = PTR_ERR(wlan_data);
|
||||
dev_err(&func->dev, "missing wlan platform data: %d\n", ret);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
wl->irq = wlan_data->irq;
|
||||
wl->ref_clock = wlan_data->board_ref_clock;
|
||||
wl->tcxo_clock = wlan_data->board_tcxo_clock;
|
||||
|
||||
sdio_set_drvdata(func, wl_test);
|
||||
|
||||
/* power up the device */
|
||||
ret = wl1271_chip_wakeup(wl);
|
||||
if (ret) {
|
||||
dev_err(&func->dev, "could not wake up chip\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (wl->fw == NULL) {
|
||||
ret = wl1271_fetch_firmware(wl);
|
||||
if (ret < 0) {
|
||||
dev_err(&func->dev, "firmware fetch error\n");
|
||||
goto out_off;
|
||||
}
|
||||
}
|
||||
|
||||
/* fetch NVS */
|
||||
if (wl->nvs == NULL) {
|
||||
ret = wl1271_fetch_nvs(wl);
|
||||
if (ret < 0) {
|
||||
dev_err(&func->dev, "NVS fetch error\n");
|
||||
goto out_off;
|
||||
}
|
||||
}
|
||||
|
||||
ret = wl1271_load_firmware(wl);
|
||||
if (ret < 0) {
|
||||
dev_err(&func->dev, "firmware load error: %d\n", ret);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
dev_info(&func->dev, "initialized\n");
|
||||
|
||||
/* I/O testing will be done in the tester thread */
|
||||
|
||||
wl_test->test_task = kthread_run(tester, wl, "sdio_tester");
|
||||
if (IS_ERR(wl_test->test_task)) {
|
||||
dev_err(&func->dev, "unable to create kernel thread\n");
|
||||
ret = PTR_ERR(wl_test->test_task);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_off:
|
||||
/* power off the chip */
|
||||
wl1271_power_off(wl);
|
||||
|
||||
out_free:
|
||||
kfree(wl_test);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit wl1271_remove(struct sdio_func *func)
|
||||
{
|
||||
struct wl1271_test *wl_test = sdio_get_drvdata(func);
|
||||
|
||||
/* stop the I/O test thread */
|
||||
kthread_stop(wl_test->test_task);
|
||||
|
||||
/* power off the chip */
|
||||
wl1271_power_off(&wl_test->wl);
|
||||
|
||||
vfree(wl_test->wl.fw);
|
||||
wl_test->wl.fw = NULL;
|
||||
kfree(wl_test->wl.nvs);
|
||||
wl_test->wl.nvs = NULL;
|
||||
|
||||
kfree(wl_test);
|
||||
}
|
||||
|
||||
static struct sdio_driver wl1271_sdio_driver = {
|
||||
.name = "wl12xx_sdio_test",
|
||||
.id_table = wl1271_devices,
|
||||
.probe = wl1271_probe,
|
||||
.remove = __devexit_p(wl1271_remove),
|
||||
};
|
||||
|
||||
static int __init wl1271_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sdio_register_driver(&wl1271_sdio_driver);
|
||||
if (ret < 0)
|
||||
pr_err("failed to register sdio driver: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(wl1271_init);
|
||||
|
||||
static void __exit wl1271_exit(void)
|
||||
{
|
||||
sdio_unregister_driver(&wl1271_sdio_driver);
|
||||
}
|
||||
module_exit(wl1271_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Roger Quadros <roger.quadros@nokia.com>");
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/crc7.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/wl12xx.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
@ -69,35 +70,22 @@
|
||||
|
||||
#define WSPI_MAX_NUM_OF_CHUNKS (WL1271_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE)
|
||||
|
||||
static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
|
||||
{
|
||||
return wl->if_priv;
|
||||
}
|
||||
struct wl12xx_spi_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *core;
|
||||
};
|
||||
|
||||
static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl)
|
||||
{
|
||||
return &(wl_to_spi(wl)->dev);
|
||||
}
|
||||
|
||||
static void wl1271_spi_disable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
disable_irq(wl->irq);
|
||||
}
|
||||
|
||||
static void wl1271_spi_enable_interrupts(struct wl1271 *wl)
|
||||
{
|
||||
enable_irq(wl->irq);
|
||||
}
|
||||
|
||||
static void wl1271_spi_reset(struct wl1271 *wl)
|
||||
static void wl12xx_spi_reset(struct device *child)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
u8 *cmd;
|
||||
struct spi_transfer t;
|
||||
struct spi_message m;
|
||||
|
||||
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
wl1271_error("could not allocate cmd for spi reset");
|
||||
dev_err(child->parent,
|
||||
"could not allocate cmd for spi reset\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -110,21 +98,22 @@ static void wl1271_spi_reset(struct wl1271 *wl)
|
||||
t.len = WSPI_INIT_CMD_LEN;
|
||||
spi_message_add_tail(&t, &m);
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
|
||||
wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
|
||||
kfree(cmd);
|
||||
}
|
||||
|
||||
static void wl1271_spi_init(struct wl1271 *wl)
|
||||
static void wl12xx_spi_init(struct device *child)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
|
||||
struct spi_transfer t;
|
||||
struct spi_message m;
|
||||
|
||||
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
wl1271_error("could not allocate cmd for spi init");
|
||||
dev_err(child->parent,
|
||||
"could not allocate cmd for spi init\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -165,15 +154,16 @@ static void wl1271_spi_init(struct wl1271 *wl)
|
||||
t.len = WSPI_INIT_CMD_LEN;
|
||||
spi_message_add_tail(&t, &m);
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
kfree(cmd);
|
||||
}
|
||||
|
||||
#define WL1271_BUSY_WORD_TIMEOUT 1000
|
||||
|
||||
static int wl1271_spi_read_busy(struct wl1271 *wl)
|
||||
static int wl12xx_spi_read_busy(struct device *child)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct wl1271 *wl = dev_get_drvdata(child);
|
||||
struct spi_transfer t[1];
|
||||
struct spi_message m;
|
||||
u32 *busy_buf;
|
||||
@ -194,20 +184,22 @@ static int wl1271_spi_read_busy(struct wl1271 *wl)
|
||||
t[0].len = sizeof(u32);
|
||||
t[0].cs_change = true;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
|
||||
if (*busy_buf & 0x1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The SPI bus is unresponsive, the read failed. */
|
||||
wl1271_error("SPI read busy-word timeout!\n");
|
||||
dev_err(child->parent, "SPI read busy-word timeout!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct wl1271 *wl = dev_get_drvdata(child);
|
||||
struct spi_transfer t[2];
|
||||
struct spi_message m;
|
||||
u32 *busy_buf;
|
||||
@ -243,10 +235,10 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
t[1].cs_change = true;
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
|
||||
if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
|
||||
wl1271_spi_read_busy(wl)) {
|
||||
wl12xx_spi_read_busy(child)) {
|
||||
memset(buf, 0, chunk_len);
|
||||
return;
|
||||
}
|
||||
@ -259,10 +251,7 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
t[0].cs_change = true;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
|
||||
wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
|
||||
wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, chunk_len);
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
|
||||
if (!fixed)
|
||||
addr += chunk_len;
|
||||
@ -271,9 +260,10 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
|
||||
}
|
||||
}
|
||||
|
||||
static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf,
|
||||
size_t len, bool fixed)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
|
||||
struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
|
||||
struct spi_message m;
|
||||
u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
|
||||
@ -308,9 +298,6 @@ static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
t[i].len = chunk_len;
|
||||
spi_message_add_tail(&t[i++], &m);
|
||||
|
||||
wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
|
||||
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, chunk_len);
|
||||
|
||||
if (!fixed)
|
||||
addr += chunk_len;
|
||||
buf += chunk_len;
|
||||
@ -318,72 +305,41 @@ static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
|
||||
cmd++;
|
||||
}
|
||||
|
||||
spi_sync(wl_to_spi(wl), &m);
|
||||
}
|
||||
|
||||
static irqreturn_t wl1271_hardirq(int irq, void *cookie)
|
||||
{
|
||||
struct wl1271 *wl = cookie;
|
||||
unsigned long flags;
|
||||
|
||||
wl1271_debug(DEBUG_IRQ, "IRQ");
|
||||
|
||||
/* complete the ELP completion */
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
|
||||
if (wl->elp_compl) {
|
||||
complete(wl->elp_compl);
|
||||
wl->elp_compl = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static int wl1271_spi_set_power(struct wl1271 *wl, bool enable)
|
||||
{
|
||||
if (wl->set_power)
|
||||
wl->set_power(enable);
|
||||
|
||||
return 0;
|
||||
spi_sync(to_spi_device(glue->dev), &m);
|
||||
}
|
||||
|
||||
static struct wl1271_if_operations spi_ops = {
|
||||
.read = wl1271_spi_raw_read,
|
||||
.write = wl1271_spi_raw_write,
|
||||
.reset = wl1271_spi_reset,
|
||||
.init = wl1271_spi_init,
|
||||
.power = wl1271_spi_set_power,
|
||||
.dev = wl1271_spi_wl_to_dev,
|
||||
.enable_irq = wl1271_spi_enable_interrupts,
|
||||
.disable_irq = wl1271_spi_disable_interrupts,
|
||||
.read = wl12xx_spi_raw_read,
|
||||
.write = wl12xx_spi_raw_write,
|
||||
.reset = wl12xx_spi_reset,
|
||||
.init = wl12xx_spi_init,
|
||||
.set_block_size = NULL,
|
||||
};
|
||||
|
||||
static int __devinit wl1271_probe(struct spi_device *spi)
|
||||
{
|
||||
struct wl12xx_spi_glue *glue;
|
||||
struct wl12xx_platform_data *pdata;
|
||||
struct ieee80211_hw *hw;
|
||||
struct wl1271 *wl;
|
||||
unsigned long irqflags;
|
||||
int ret;
|
||||
struct resource res[1];
|
||||
int ret = -ENOMEM;
|
||||
|
||||
pdata = spi->dev.platform_data;
|
||||
if (!pdata) {
|
||||
wl1271_error("no platform data");
|
||||
dev_err(&spi->dev, "no platform data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hw = wl1271_alloc_hw();
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
pdata->ops = &spi_ops;
|
||||
|
||||
wl = hw->priv;
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&spi->dev, "can't allocate glue\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&spi->dev, wl);
|
||||
wl->if_priv = spi;
|
||||
glue->dev = &spi->dev;
|
||||
|
||||
wl->if_ops = &spi_ops;
|
||||
spi_set_drvdata(spi, glue);
|
||||
|
||||
/* This is the only SPI value that we need to set here, the rest
|
||||
* comes from the board-peripherals file */
|
||||
@ -391,69 +347,61 @@ static int __devinit wl1271_probe(struct spi_device *spi)
|
||||
|
||||
ret = spi_setup(spi);
|
||||
if (ret < 0) {
|
||||
wl1271_error("spi_setup failed");
|
||||
goto out_free;
|
||||
dev_err(glue->dev, "spi_setup failed\n");
|
||||
goto out_free_glue;
|
||||
}
|
||||
|
||||
wl->set_power = pdata->set_power;
|
||||
if (!wl->set_power) {
|
||||
wl1271_error("set power function missing in platform data");
|
||||
ret = -ENODEV;
|
||||
goto out_free;
|
||||
glue->core = platform_device_alloc("wl12xx", -1);
|
||||
if (!glue->core) {
|
||||
dev_err(glue->dev, "can't allocate platform_device\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_free_glue;
|
||||
}
|
||||
|
||||
wl->ref_clock = pdata->board_ref_clock;
|
||||
wl->tcxo_clock = pdata->board_tcxo_clock;
|
||||
wl->platform_quirks = pdata->platform_quirks;
|
||||
glue->core->dev.parent = &spi->dev;
|
||||
|
||||
if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
|
||||
irqflags = IRQF_TRIGGER_RISING;
|
||||
else
|
||||
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
|
||||
memset(res, 0x00, sizeof(res));
|
||||
|
||||
wl->irq = spi->irq;
|
||||
if (wl->irq < 0) {
|
||||
wl1271_error("irq missing in platform data");
|
||||
ret = -ENODEV;
|
||||
goto out_free;
|
||||
res[0].start = spi->irq;
|
||||
res[0].flags = IORESOURCE_IRQ;
|
||||
res[0].name = "irq";
|
||||
|
||||
ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res));
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add resources\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
|
||||
irqflags,
|
||||
DRIVER_NAME, wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("request_irq() failed: %d", ret);
|
||||
goto out_free;
|
||||
ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't add platform data\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
disable_irq(wl->irq);
|
||||
|
||||
ret = wl1271_init_ieee80211(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
|
||||
ret = wl1271_register_hw(wl);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
ret = platform_device_add(glue->core);
|
||||
if (ret) {
|
||||
dev_err(glue->dev, "can't register platform device\n");
|
||||
goto out_dev_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_irq:
|
||||
free_irq(wl->irq, wl);
|
||||
|
||||
out_free:
|
||||
wl1271_free_hw(wl);
|
||||
out_dev_put:
|
||||
platform_device_put(glue->core);
|
||||
|
||||
out_free_glue:
|
||||
kfree(glue);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit wl1271_remove(struct spi_device *spi)
|
||||
{
|
||||
struct wl1271 *wl = dev_get_drvdata(&spi->dev);
|
||||
struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
|
||||
|
||||
wl1271_unregister_hw(wl);
|
||||
free_irq(wl->irq, wl);
|
||||
wl1271_free_hw(wl);
|
||||
platform_device_del(glue->core);
|
||||
platform_device_put(glue->core);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,8 +26,10 @@
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "acx.h"
|
||||
#include "reg.h"
|
||||
#include "ps.h"
|
||||
|
||||
#define WL1271_TM_MAX_DATA_LENGTH 1024
|
||||
|
||||
@ -87,31 +89,47 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
|
||||
return -EMSGSIZE;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
ret = wl1271_cmd_test(wl, buf, buf_len, answer);
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl1271_cmd_test(wl, buf, buf_len, answer);
|
||||
if (ret < 0) {
|
||||
wl1271_warning("testmode cmd test failed: %d", ret);
|
||||
return ret;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
if (answer) {
|
||||
len = nla_total_size(buf_len);
|
||||
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf);
|
||||
ret = cfg80211_testmode_reply(skb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_sleep:
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return ret;
|
||||
|
||||
nla_put_failure:
|
||||
kfree_skb(skb);
|
||||
return -EMSGSIZE;
|
||||
ret = -EMSGSIZE;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
|
||||
@ -128,33 +146,53 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
|
||||
|
||||
ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
if (wl->state == WL1271_STATE_OFF) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("testmode cmd interrogate failed: %d", ret);
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
|
||||
if (!skb) {
|
||||
kfree(cmd);
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd);
|
||||
ret = cfg80211_testmode_reply(skb);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
kfree(cmd);
|
||||
out_sleep:
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return ret;
|
||||
|
||||
nla_put_failure:
|
||||
kfree_skb(skb);
|
||||
return -EMSGSIZE;
|
||||
ret = -EMSGSIZE;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
|
||||
|
@ -26,22 +26,24 @@
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "wl12xx.h"
|
||||
#include "debug.h"
|
||||
#include "io.h"
|
||||
#include "reg.h"
|
||||
#include "ps.h"
|
||||
#include "tx.h"
|
||||
#include "event.h"
|
||||
|
||||
static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
|
||||
static int wl1271_set_default_wep_key(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif, u8 id)
|
||||
{
|
||||
int ret;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||
|
||||
if (is_ap)
|
||||
ret = wl12xx_cmd_set_default_wep_key(wl, id,
|
||||
wl->ap_bcast_hlid);
|
||||
wlvif->ap.bcast_hlid);
|
||||
else
|
||||
ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid);
|
||||
ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -76,7 +78,8 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
|
||||
}
|
||||
|
||||
static int wl1271_tx_update_filters(struct wl1271 *wl,
|
||||
struct sk_buff *skb)
|
||||
struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
int ret;
|
||||
@ -92,15 +95,11 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
|
||||
if (!ieee80211_is_auth(hdr->frame_control))
|
||||
return 0;
|
||||
|
||||
if (wl->dev_hlid != WL12XX_INVALID_LINK_ID)
|
||||
if (wlvif->dev_hlid != WL12XX_INVALID_LINK_ID)
|
||||
goto out;
|
||||
|
||||
wl1271_debug(DEBUG_CMD, "starting device role for roaming");
|
||||
ret = wl12xx_cmd_role_start_dev(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = wl12xx_roc(wl, wl->dev_role_id);
|
||||
ret = wl12xx_start_dev(wl, wlvif);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
out:
|
||||
@ -123,18 +122,16 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
|
||||
wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
|
||||
}
|
||||
|
||||
static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
|
||||
static void wl1271_tx_regulate_link(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u8 hlid)
|
||||
{
|
||||
bool fw_ps, single_sta;
|
||||
u8 tx_pkts;
|
||||
|
||||
/* only regulate station links */
|
||||
if (hlid < WL1271_AP_STA_HLID_START)
|
||||
if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!wl1271_is_active_sta(wl, hlid)))
|
||||
return;
|
||||
|
||||
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
|
||||
tx_pkts = wl->links[hlid].allocated_pkts;
|
||||
single_sta = (wl->active_sta_count == 1);
|
||||
@ -146,7 +143,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
|
||||
* case FW-memory congestion is not a problem.
|
||||
*/
|
||||
if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
|
||||
wl1271_ps_link_start(wl, hlid, true);
|
||||
wl12xx_ps_link_start(wl, wlvif, hlid, true);
|
||||
}
|
||||
|
||||
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
|
||||
@ -154,7 +151,8 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
|
||||
return wl->dummy_packet == skb;
|
||||
}
|
||||
|
||||
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb)
|
||||
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);
|
||||
|
||||
@ -167,49 +165,51 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb)
|
||||
} else {
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
|
||||
if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
|
||||
return wl->system_hlid;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (ieee80211_is_mgmt(hdr->frame_control))
|
||||
return wl->ap_global_hlid;
|
||||
return wlvif->ap.global_hlid;
|
||||
else
|
||||
return wl->ap_bcast_hlid;
|
||||
return wlvif->ap.bcast_hlid;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb)
|
||||
u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
if (wl12xx_is_dummy_packet(wl, skb))
|
||||
if (!wlvif || wl12xx_is_dummy_packet(wl, skb))
|
||||
return wl->system_hlid;
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS)
|
||||
return wl12xx_tx_get_hlid_ap(wl, skb);
|
||||
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
|
||||
return wl12xx_tx_get_hlid_ap(wl, wlvif, skb);
|
||||
|
||||
wl1271_tx_update_filters(wl, skb);
|
||||
wl1271_tx_update_filters(wl, wlvif, skb);
|
||||
|
||||
if ((test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
|
||||
test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) &&
|
||||
if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
|
||||
test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) &&
|
||||
!ieee80211_is_auth(hdr->frame_control) &&
|
||||
!ieee80211_is_assoc_req(hdr->frame_control))
|
||||
return wl->sta_hlid;
|
||||
return wlvif->sta.hlid;
|
||||
else
|
||||
return wl->dev_hlid;
|
||||
return wlvif->dev_hlid;
|
||||
}
|
||||
|
||||
static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
|
||||
unsigned int packet_length)
|
||||
{
|
||||
if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT)
|
||||
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
|
||||
else
|
||||
if (wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT)
|
||||
return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
|
||||
else
|
||||
return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
||||
u32 buf_offset, u8 hlid)
|
||||
static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb, u32 extra, u32 buf_offset,
|
||||
u8 hlid)
|
||||
{
|
||||
struct wl1271_tx_hw_descr *desc;
|
||||
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
|
||||
@ -217,6 +217,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
||||
u32 total_blocks;
|
||||
int id, ret = -EBUSY, ac;
|
||||
u32 spare_blocks = wl->tx_spare_blocks;
|
||||
bool is_dummy = false;
|
||||
|
||||
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
|
||||
return -EAGAIN;
|
||||
@ -231,8 +232,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
||||
len = wl12xx_calc_packet_alignment(wl, total_len);
|
||||
|
||||
/* in case of a dummy packet, use default amount of spare mem blocks */
|
||||
if (unlikely(wl12xx_is_dummy_packet(wl, skb)))
|
||||
if (unlikely(wl12xx_is_dummy_packet(wl, skb))) {
|
||||
is_dummy = true;
|
||||
spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
|
||||
}
|
||||
|
||||
total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE +
|
||||
spare_blocks;
|
||||
@ -257,8 +260,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
||||
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
wl->tx_allocated_pkts[ac]++;
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS &&
|
||||
hlid >= WL1271_AP_STA_HLID_START)
|
||||
if (!is_dummy && wlvif &&
|
||||
wlvif->bss_type == BSS_TYPE_AP_BSS &&
|
||||
test_bit(hlid, wlvif->ap.sta_hlid_map))
|
||||
wl->links[hlid].allocated_pkts++;
|
||||
|
||||
ret = 0;
|
||||
@ -273,15 +277,16 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
||||
u32 extra, struct ieee80211_tx_info *control,
|
||||
u8 hlid)
|
||||
static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb, u32 extra,
|
||||
struct ieee80211_tx_info *control, u8 hlid)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct wl1271_tx_hw_descr *desc;
|
||||
int aligned_len, ac, rate_idx;
|
||||
s64 hosttime;
|
||||
u16 tx_attr;
|
||||
u16 tx_attr = 0;
|
||||
bool is_dummy;
|
||||
|
||||
desc = (struct wl1271_tx_hw_descr *) skb->data;
|
||||
|
||||
@ -298,7 +303,8 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
||||
hosttime = (timespec_to_ns(&ts) >> 10);
|
||||
desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
|
||||
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS)
|
||||
is_dummy = wl12xx_is_dummy_packet(wl, skb);
|
||||
if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS)
|
||||
desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
|
||||
else
|
||||
desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
|
||||
@ -307,39 +313,42 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
||||
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
desc->tid = skb->priority;
|
||||
|
||||
if (wl12xx_is_dummy_packet(wl, skb)) {
|
||||
if (is_dummy) {
|
||||
/*
|
||||
* FW expects the dummy packet to have an invalid session id -
|
||||
* any session id that is different than the one set in the join
|
||||
*/
|
||||
tx_attr = ((~wl->session_counter) <<
|
||||
tx_attr = (SESSION_COUNTER_INVALID <<
|
||||
TX_HW_ATTR_OFST_SESSION_COUNTER) &
|
||||
TX_HW_ATTR_SESSION_COUNTER;
|
||||
|
||||
tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
|
||||
} else {
|
||||
} else if (wlvif) {
|
||||
/* configure the tx attributes */
|
||||
tx_attr =
|
||||
wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
|
||||
tx_attr = wlvif->session_counter <<
|
||||
TX_HW_ATTR_OFST_SESSION_COUNTER;
|
||||
}
|
||||
|
||||
desc->hlid = hlid;
|
||||
|
||||
if (wl->bss_type != BSS_TYPE_AP_BSS) {
|
||||
if (is_dummy || !wlvif)
|
||||
rate_idx = 0;
|
||||
else if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
|
||||
/* if the packets are destined for AP (have a STA entry)
|
||||
send them with AP rate policies, otherwise use default
|
||||
basic rates */
|
||||
if (control->control.sta)
|
||||
rate_idx = ACX_TX_AP_FULL_RATE;
|
||||
if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
||||
rate_idx = wlvif->sta.p2p_rate_idx;
|
||||
else if (control->control.sta)
|
||||
rate_idx = wlvif->sta.ap_rate_idx;
|
||||
else
|
||||
rate_idx = ACX_TX_BASIC_RATE;
|
||||
rate_idx = wlvif->sta.basic_rate_idx;
|
||||
} else {
|
||||
if (hlid == wl->ap_global_hlid)
|
||||
rate_idx = ACX_TX_AP_MODE_MGMT_RATE;
|
||||
else if (hlid == wl->ap_bcast_hlid)
|
||||
rate_idx = ACX_TX_AP_MODE_BCST_RATE;
|
||||
if (hlid == wlvif->ap.global_hlid)
|
||||
rate_idx = wlvif->ap.mgmt_rate_idx;
|
||||
else if (hlid == wlvif->ap.bcast_hlid)
|
||||
rate_idx = wlvif->ap.bcast_rate_idx;
|
||||
else
|
||||
rate_idx = ac;
|
||||
rate_idx = wlvif->ap.ucast_rate_idx[ac];
|
||||
}
|
||||
|
||||
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
|
||||
@ -379,20 +388,24 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
|
||||
}
|
||||
|
||||
/* caller must hold wl->mutex */
|
||||
static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
|
||||
u32 buf_offset)
|
||||
static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb, u32 buf_offset)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
u32 extra = 0;
|
||||
int ret = 0;
|
||||
u32 total_len;
|
||||
u8 hlid;
|
||||
bool is_dummy;
|
||||
|
||||
if (!skb)
|
||||
return -EINVAL;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
/* TODO: handle dummy packets on multi-vifs */
|
||||
is_dummy = wl12xx_is_dummy_packet(wl, skb);
|
||||
|
||||
if (info->control.hw_key &&
|
||||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
|
||||
extra = WL1271_TKIP_IV_SPACE;
|
||||
@ -405,29 +418,28 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
|
||||
is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
|
||||
(cipher == WLAN_CIPHER_SUITE_WEP104);
|
||||
|
||||
if (unlikely(is_wep && wl->default_key != idx)) {
|
||||
ret = wl1271_set_default_wep_key(wl, idx);
|
||||
if (unlikely(is_wep && wlvif->default_key != idx)) {
|
||||
ret = wl1271_set_default_wep_key(wl, wlvif, idx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
wl->default_key = idx;
|
||||
wlvif->default_key = idx;
|
||||
}
|
||||
}
|
||||
|
||||
hlid = wl1271_tx_get_hlid(wl, skb);
|
||||
hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
|
||||
if (hlid == WL12XX_INVALID_LINK_ID) {
|
||||
wl1271_error("invalid hlid. dropping skb 0x%p", skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid);
|
||||
ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
|
||||
wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid);
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS) {
|
||||
if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) {
|
||||
wl1271_tx_ap_update_inconnection_sta(wl, skb);
|
||||
wl1271_tx_regulate_link(wl, hlid);
|
||||
wl1271_tx_regulate_link(wl, wlvif, hlid);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -444,7 +456,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
|
||||
memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
|
||||
|
||||
/* Revert side effects in the dummy packet skb, so it can be reused */
|
||||
if (wl12xx_is_dummy_packet(wl, skb))
|
||||
if (is_dummy)
|
||||
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
|
||||
|
||||
return total_len;
|
||||
@ -522,19 +534,18 @@ static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
|
||||
return &queues[q];
|
||||
}
|
||||
|
||||
static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
|
||||
static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl,
|
||||
struct wl1271_link *lnk)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
struct sk_buff *skb;
|
||||
unsigned long flags;
|
||||
struct sk_buff_head *queue;
|
||||
|
||||
queue = wl1271_select_queue(wl, wl->tx_queue);
|
||||
queue = wl1271_select_queue(wl, lnk->tx_queue);
|
||||
if (!queue)
|
||||
goto out;
|
||||
return NULL;
|
||||
|
||||
skb = skb_dequeue(queue);
|
||||
|
||||
out:
|
||||
if (skb) {
|
||||
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
@ -545,43 +556,33 @@ out:
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
|
||||
static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
unsigned long flags;
|
||||
int i, h, start_hlid;
|
||||
struct sk_buff_head *queue;
|
||||
|
||||
/* start from the link after the last one */
|
||||
start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS;
|
||||
start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS;
|
||||
|
||||
/* dequeue according to AC, round robin on each link */
|
||||
for (i = 0; i < AP_MAX_LINKS; i++) {
|
||||
h = (start_hlid + i) % AP_MAX_LINKS;
|
||||
for (i = 0; i < WL12XX_MAX_LINKS; i++) {
|
||||
h = (start_hlid + i) % WL12XX_MAX_LINKS;
|
||||
|
||||
/* only consider connected stations */
|
||||
if (h >= WL1271_AP_STA_HLID_START &&
|
||||
!test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map))
|
||||
if (!test_bit(h, wlvif->links_map))
|
||||
continue;
|
||||
|
||||
queue = wl1271_select_queue(wl, wl->links[h].tx_queue);
|
||||
if (!queue)
|
||||
skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]);
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
skb = skb_dequeue(queue);
|
||||
if (skb)
|
||||
break;
|
||||
wlvif->last_tx_hlid = h;
|
||||
break;
|
||||
}
|
||||
|
||||
if (skb) {
|
||||
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
wl->last_tx_hlid = h;
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
wl->tx_queue_count[q]--;
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
} else {
|
||||
wl->last_tx_hlid = 0;
|
||||
}
|
||||
if (!skb)
|
||||
wlvif->last_tx_hlid = 0;
|
||||
|
||||
return skb;
|
||||
}
|
||||
@ -589,12 +590,32 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
|
||||
static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct wl12xx_vif *wlvif = wl->last_wlvif;
|
||||
struct sk_buff *skb = NULL;
|
||||
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS)
|
||||
skb = wl1271_ap_skb_dequeue(wl);
|
||||
else
|
||||
skb = wl1271_sta_skb_dequeue(wl);
|
||||
if (wlvif) {
|
||||
wl12xx_for_each_wlvif_continue(wl, wlvif) {
|
||||
skb = wl12xx_vif_skb_dequeue(wl, wlvif);
|
||||
if (skb) {
|
||||
wl->last_wlvif = wlvif;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* do another pass */
|
||||
if (!skb) {
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
skb = wl12xx_vif_skb_dequeue(wl, wlvif);
|
||||
if (skb) {
|
||||
wl->last_wlvif = wlvif;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skb)
|
||||
skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
|
||||
|
||||
if (!skb &&
|
||||
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
|
||||
@ -610,21 +631,21 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
|
||||
return skb;
|
||||
}
|
||||
|
||||
static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
|
||||
static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
unsigned long flags;
|
||||
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
|
||||
|
||||
if (wl12xx_is_dummy_packet(wl, skb)) {
|
||||
set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
|
||||
} else if (wl->bss_type == BSS_TYPE_AP_BSS) {
|
||||
u8 hlid = wl1271_tx_get_hlid(wl, skb);
|
||||
} else {
|
||||
u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
|
||||
skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
|
||||
|
||||
/* make sure we dequeue the same packet next time */
|
||||
wl->last_tx_hlid = (hlid + AP_MAX_LINKS - 1) % AP_MAX_LINKS;
|
||||
} else {
|
||||
skb_queue_head(&wl->tx_queue[q], skb);
|
||||
wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) %
|
||||
WL12XX_MAX_LINKS;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
@ -639,29 +660,71 @@ static bool wl1271_tx_is_data_present(struct sk_buff *skb)
|
||||
return ieee80211_is_data_present(hdr->frame_control);
|
||||
}
|
||||
|
||||
void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
u32 timeout;
|
||||
u8 hlid;
|
||||
|
||||
if (!wl->conf.rx_streaming.interval)
|
||||
return;
|
||||
|
||||
if (!wl->conf.rx_streaming.always &&
|
||||
!test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))
|
||||
return;
|
||||
|
||||
timeout = wl->conf.rx_streaming.duration;
|
||||
wl12xx_for_each_wlvif_sta(wl, wlvif) {
|
||||
bool found = false;
|
||||
for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) {
|
||||
if (test_bit(hlid, wlvif->links_map)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
/* enable rx streaming */
|
||||
if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
|
||||
ieee80211_queue_work(wl->hw,
|
||||
&wlvif->rx_streaming_enable_work);
|
||||
|
||||
mod_timer(&wlvif->rx_streaming_timer,
|
||||
jiffies + msecs_to_jiffies(timeout));
|
||||
}
|
||||
}
|
||||
|
||||
void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||
{
|
||||
struct wl12xx_vif *wlvif;
|
||||
struct sk_buff *skb;
|
||||
struct wl1271_tx_hw_descr *desc;
|
||||
u32 buf_offset = 0;
|
||||
bool sent_packets = false;
|
||||
bool had_data = false;
|
||||
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
|
||||
unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
|
||||
int ret;
|
||||
|
||||
if (unlikely(wl->state == WL1271_STATE_OFF))
|
||||
return;
|
||||
|
||||
while ((skb = wl1271_skb_dequeue(wl))) {
|
||||
if (wl1271_tx_is_data_present(skb))
|
||||
had_data = true;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
bool has_data = false;
|
||||
|
||||
ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
|
||||
wlvif = NULL;
|
||||
if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif)
|
||||
wlvif = wl12xx_vif_to_data(info->control.vif);
|
||||
|
||||
has_data = wlvif && wl1271_tx_is_data_present(skb);
|
||||
ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset);
|
||||
if (ret == -EAGAIN) {
|
||||
/*
|
||||
* Aggregation buffer is full.
|
||||
* Flush buffer and try again.
|
||||
*/
|
||||
wl1271_skb_queue_head(wl, skb);
|
||||
wl1271_skb_queue_head(wl, wlvif, skb);
|
||||
wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
|
||||
buf_offset, true);
|
||||
sent_packets = true;
|
||||
@ -672,7 +735,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||
* Firmware buffer is full.
|
||||
* Queue back last skb, and stop aggregating.
|
||||
*/
|
||||
wl1271_skb_queue_head(wl, skb);
|
||||
wl1271_skb_queue_head(wl, wlvif, skb);
|
||||
/* No work left, avoid scheduling redundant tx work */
|
||||
set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
|
||||
goto out_ack;
|
||||
@ -682,6 +745,10 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
|
||||
}
|
||||
buf_offset += ret;
|
||||
wl->tx_packets_count++;
|
||||
if (has_data) {
|
||||
desc = (struct wl1271_tx_hw_descr *) skb->data;
|
||||
__set_bit(desc->hlid, active_hlids);
|
||||
}
|
||||
}
|
||||
|
||||
out_ack:
|
||||
@ -701,19 +768,7 @@ out_ack:
|
||||
|
||||
wl1271_handle_tx_low_watermark(wl);
|
||||
}
|
||||
if (!is_ap && wl->conf.rx_streaming.interval && had_data &&
|
||||
(wl->conf.rx_streaming.always ||
|
||||
test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) {
|
||||
u32 timeout = wl->conf.rx_streaming.duration;
|
||||
|
||||
/* enable rx streaming */
|
||||
if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
|
||||
ieee80211_queue_work(wl->hw,
|
||||
&wl->rx_streaming_enable_work);
|
||||
|
||||
mod_timer(&wl->rx_streaming_timer,
|
||||
jiffies + msecs_to_jiffies(timeout));
|
||||
}
|
||||
wl12xx_rearm_rx_streaming(wl, active_hlids);
|
||||
}
|
||||
|
||||
void wl1271_tx_work(struct work_struct *work)
|
||||
@ -737,6 +792,8 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
||||
struct wl1271_tx_hw_res_descr *result)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_vif *vif;
|
||||
struct wl12xx_vif *wlvif;
|
||||
struct sk_buff *skb;
|
||||
int id = result->id;
|
||||
int rate = -1;
|
||||
@ -756,11 +813,16 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
||||
return;
|
||||
}
|
||||
|
||||
/* info->control is valid as long as we don't update info->status */
|
||||
vif = info->control.vif;
|
||||
wlvif = wl12xx_vif_to_data(vif);
|
||||
|
||||
/* update the TX status info */
|
||||
if (result->status == TX_SUCCESS) {
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
rate = wl1271_rate_to_idx(result->rate_class_index, wl->band);
|
||||
rate = wl1271_rate_to_idx(result->rate_class_index,
|
||||
wlvif->band);
|
||||
retries = result->ack_failures;
|
||||
} else if (result->status == TX_RETRY_EXCEEDED) {
|
||||
wl->stats.excessive_retries++;
|
||||
@ -783,14 +845,14 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
||||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP ||
|
||||
info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) {
|
||||
u8 fw_lsb = result->tx_security_sequence_number_lsb;
|
||||
u8 cur_lsb = wl->tx_security_last_seq_lsb;
|
||||
u8 cur_lsb = wlvif->tx_security_last_seq_lsb;
|
||||
|
||||
/*
|
||||
* update security sequence number, taking care of potential
|
||||
* wrap-around
|
||||
*/
|
||||
wl->tx_security_seq += (fw_lsb - cur_lsb + 256) % 256;
|
||||
wl->tx_security_last_seq_lsb = fw_lsb;
|
||||
wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff;
|
||||
wlvif->tx_security_last_seq_lsb = fw_lsb;
|
||||
}
|
||||
|
||||
/* remove private header from packet */
|
||||
@ -886,40 +948,31 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
|
||||
}
|
||||
|
||||
/* caller must hold wl->mutex and TX must be stopped */
|
||||
void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
|
||||
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* TX failure */
|
||||
for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
|
||||
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
|
||||
wl1271_free_sta(wl, wlvif, i);
|
||||
else
|
||||
wlvif->sta.ba_rx_bitmap = 0;
|
||||
|
||||
wl1271_tx_reset_link_queues(wl, i);
|
||||
wl->links[i].allocated_pkts = 0;
|
||||
wl->links[i].prev_freed_pkts = 0;
|
||||
}
|
||||
wlvif->last_tx_hlid = 0;
|
||||
|
||||
}
|
||||
/* caller must hold wl->mutex and TX must be stopped */
|
||||
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
|
||||
{
|
||||
int i;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *info;
|
||||
|
||||
/* TX failure */
|
||||
if (wl->bss_type == BSS_TYPE_AP_BSS) {
|
||||
for (i = 0; i < AP_MAX_LINKS; i++) {
|
||||
wl1271_free_sta(wl, i);
|
||||
wl1271_tx_reset_link_queues(wl, i);
|
||||
wl->links[i].allocated_pkts = 0;
|
||||
wl->links[i].prev_freed_pkts = 0;
|
||||
}
|
||||
|
||||
wl->last_tx_hlid = 0;
|
||||
} else {
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
|
||||
wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
|
||||
skb);
|
||||
|
||||
if (!wl12xx_is_dummy_packet(wl, skb)) {
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
info->status.rates[0].idx = -1;
|
||||
info->status.rates[0].count = 0;
|
||||
ieee80211_tx_status_ni(wl->hw, skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wl->ba_rx_bitmap = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++)
|
||||
wl->tx_queue_count[i] = 0;
|
||||
|
||||
|
@ -206,18 +206,23 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl)
|
||||
void wl1271_tx_work(struct work_struct *work);
|
||||
void wl1271_tx_work_locked(struct wl1271 *wl);
|
||||
void wl1271_tx_complete(struct wl1271 *wl);
|
||||
void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
|
||||
void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
|
||||
void wl1271_tx_flush(struct wl1271 *wl);
|
||||
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
|
||||
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
|
||||
enum ieee80211_band rate_band);
|
||||
u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set);
|
||||
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb);
|
||||
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb);
|
||||
u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
struct sk_buff *skb);
|
||||
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
|
||||
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
|
||||
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
|
||||
void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
|
||||
|
||||
/* from main.c */
|
||||
void wl1271_free_sta(struct wl1271 *wl, u8 hlid);
|
||||
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
|
||||
|
||||
#endif
|
||||
|
@ -35,9 +35,6 @@
|
||||
#include "conf.h"
|
||||
#include "ini.h"
|
||||
|
||||
#define DRIVER_NAME "wl1271"
|
||||
#define DRIVER_PREFIX DRIVER_NAME ": "
|
||||
|
||||
/*
|
||||
* FW versions support BA 11n
|
||||
* versions marks x.x.x.50-60.x
|
||||
@ -45,73 +42,6 @@
|
||||
#define WL12XX_BA_SUPPORT_FW_COST_VER2_START 50
|
||||
#define WL12XX_BA_SUPPORT_FW_COST_VER2_END 60
|
||||
|
||||
enum {
|
||||
DEBUG_NONE = 0,
|
||||
DEBUG_IRQ = BIT(0),
|
||||
DEBUG_SPI = BIT(1),
|
||||
DEBUG_BOOT = BIT(2),
|
||||
DEBUG_MAILBOX = BIT(3),
|
||||
DEBUG_TESTMODE = BIT(4),
|
||||
DEBUG_EVENT = BIT(5),
|
||||
DEBUG_TX = BIT(6),
|
||||
DEBUG_RX = BIT(7),
|
||||
DEBUG_SCAN = BIT(8),
|
||||
DEBUG_CRYPT = BIT(9),
|
||||
DEBUG_PSM = BIT(10),
|
||||
DEBUG_MAC80211 = BIT(11),
|
||||
DEBUG_CMD = BIT(12),
|
||||
DEBUG_ACX = BIT(13),
|
||||
DEBUG_SDIO = BIT(14),
|
||||
DEBUG_FILTERS = BIT(15),
|
||||
DEBUG_ADHOC = BIT(16),
|
||||
DEBUG_AP = BIT(17),
|
||||
DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP),
|
||||
DEBUG_ALL = ~0,
|
||||
};
|
||||
|
||||
extern u32 wl12xx_debug_level;
|
||||
|
||||
#define DEBUG_DUMP_LIMIT 1024
|
||||
|
||||
#define wl1271_error(fmt, arg...) \
|
||||
pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_warning(fmt, arg...) \
|
||||
pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_notice(fmt, arg...) \
|
||||
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_info(fmt, arg...) \
|
||||
pr_info(DRIVER_PREFIX fmt "\n", ##arg)
|
||||
|
||||
#define wl1271_debug(level, fmt, arg...) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \
|
||||
} while (0)
|
||||
|
||||
/* TODO: use pr_debug_hex_dump when it will be available */
|
||||
#define wl1271_dump(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
0); \
|
||||
} while (0)
|
||||
|
||||
#define wl1271_dump_ascii(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
true); \
|
||||
} while (0)
|
||||
|
||||
#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin"
|
||||
#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"
|
||||
|
||||
@ -142,15 +72,11 @@ extern u32 wl12xx_debug_level;
|
||||
#define WL12XX_INVALID_ROLE_ID 0xff
|
||||
#define WL12XX_INVALID_LINK_ID 0xff
|
||||
|
||||
#define WL12XX_MAX_RATE_POLICIES 16
|
||||
|
||||
/* Defined by FW as 0. Will not be freed or allocated. */
|
||||
#define WL12XX_SYSTEM_HLID 0
|
||||
|
||||
/*
|
||||
* TODO: we currently don't support multirole. remove
|
||||
* this constant from the code when we do.
|
||||
*/
|
||||
#define WL1271_AP_STA_HLID_START 3
|
||||
|
||||
/*
|
||||
* When in AP-mode, we allow (at least) this number of packets
|
||||
* to be transmitted to FW for a STA in PS-mode. Only when packets are
|
||||
@ -236,13 +162,6 @@ struct wl1271_stats {
|
||||
|
||||
#define AP_MAX_STATIONS 8
|
||||
|
||||
/* Broadcast and Global links + system link + links to stations */
|
||||
/*
|
||||
* TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all
|
||||
* the places that use this.
|
||||
*/
|
||||
#define AP_MAX_LINKS (AP_MAX_STATIONS + WL1271_AP_STA_HLID_START)
|
||||
|
||||
/* FW status registers */
|
||||
struct wl12xx_fw_status {
|
||||
__le32 intr;
|
||||
@ -299,17 +218,14 @@ struct wl1271_scan {
|
||||
};
|
||||
|
||||
struct wl1271_if_operations {
|
||||
void (*read)(struct wl1271 *wl, int addr, void *buf, size_t len,
|
||||
void (*read)(struct device *child, int addr, void *buf, size_t len,
|
||||
bool fixed);
|
||||
void (*write)(struct wl1271 *wl, int addr, void *buf, size_t len,
|
||||
void (*write)(struct device *child, int addr, void *buf, size_t len,
|
||||
bool fixed);
|
||||
void (*reset)(struct wl1271 *wl);
|
||||
void (*init)(struct wl1271 *wl);
|
||||
int (*power)(struct wl1271 *wl, bool enable);
|
||||
struct device* (*dev)(struct wl1271 *wl);
|
||||
void (*enable_irq)(struct wl1271 *wl);
|
||||
void (*disable_irq)(struct wl1271 *wl);
|
||||
void (*set_block_size) (struct wl1271 *wl, unsigned int blksz);
|
||||
void (*reset)(struct device *child);
|
||||
void (*init)(struct device *child);
|
||||
int (*power)(struct device *child, bool enable);
|
||||
void (*set_block_size) (struct device *child, unsigned int blksz);
|
||||
};
|
||||
|
||||
#define MAX_NUM_KEYS 14
|
||||
@ -326,29 +242,33 @@ struct wl1271_ap_key {
|
||||
};
|
||||
|
||||
enum wl12xx_flags {
|
||||
WL1271_FLAG_STA_ASSOCIATED,
|
||||
WL1271_FLAG_IBSS_JOINED,
|
||||
WL1271_FLAG_GPIO_POWER,
|
||||
WL1271_FLAG_TX_QUEUE_STOPPED,
|
||||
WL1271_FLAG_TX_PENDING,
|
||||
WL1271_FLAG_IN_ELP,
|
||||
WL1271_FLAG_ELP_REQUESTED,
|
||||
WL1271_FLAG_PSM,
|
||||
WL1271_FLAG_PSM_REQUESTED,
|
||||
WL1271_FLAG_IRQ_RUNNING,
|
||||
WL1271_FLAG_IDLE,
|
||||
WL1271_FLAG_PSPOLL_FAILURE,
|
||||
WL1271_FLAG_STA_STATE_SENT,
|
||||
WL1271_FLAG_FW_TX_BUSY,
|
||||
WL1271_FLAG_AP_STARTED,
|
||||
WL1271_FLAG_IF_INITIALIZED,
|
||||
WL1271_FLAG_DUMMY_PACKET_PENDING,
|
||||
WL1271_FLAG_SUSPENDED,
|
||||
WL1271_FLAG_PENDING_WORK,
|
||||
WL1271_FLAG_SOFT_GEMINI,
|
||||
WL1271_FLAG_RX_STREAMING_STARTED,
|
||||
WL1271_FLAG_RECOVERY_IN_PROGRESS,
|
||||
WL1271_FLAG_CS_PROGRESS,
|
||||
};
|
||||
|
||||
enum wl12xx_vif_flags {
|
||||
WLVIF_FLAG_INITIALIZED,
|
||||
WLVIF_FLAG_STA_ASSOCIATED,
|
||||
WLVIF_FLAG_IBSS_JOINED,
|
||||
WLVIF_FLAG_AP_STARTED,
|
||||
WLVIF_FLAG_PSM,
|
||||
WLVIF_FLAG_PSM_REQUESTED,
|
||||
WLVIF_FLAG_STA_STATE_SENT,
|
||||
WLVIF_FLAG_RX_STREAMING_STARTED,
|
||||
WLVIF_FLAG_PSPOLL_FAILURE,
|
||||
WLVIF_FLAG_CS_PROGRESS,
|
||||
WLVIF_FLAG_AP_PROBE_RESP_SET,
|
||||
};
|
||||
|
||||
struct wl1271_link {
|
||||
@ -366,10 +286,11 @@ struct wl1271_link {
|
||||
};
|
||||
|
||||
struct wl1271 {
|
||||
struct platform_device *plat_dev;
|
||||
struct ieee80211_hw *hw;
|
||||
bool mac80211_registered;
|
||||
|
||||
struct device *dev;
|
||||
|
||||
void *if_priv;
|
||||
|
||||
struct wl1271_if_operations *if_ops;
|
||||
@ -399,25 +320,20 @@ struct wl1271 {
|
||||
|
||||
s8 hw_pg_ver;
|
||||
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 bss_type;
|
||||
u8 set_bss_type;
|
||||
u8 p2p; /* we are using p2p role */
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
|
||||
u8 ssid_len;
|
||||
int channel;
|
||||
u8 role_id;
|
||||
u8 dev_role_id;
|
||||
u8 system_hlid;
|
||||
u8 sta_hlid;
|
||||
u8 dev_hlid;
|
||||
u8 ap_global_hlid;
|
||||
u8 ap_bcast_hlid;
|
||||
|
||||
unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
|
||||
unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
|
||||
unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)];
|
||||
unsigned long rate_policies_map[
|
||||
BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)];
|
||||
|
||||
struct list_head wlvif_list;
|
||||
|
||||
u8 sta_count;
|
||||
u8 ap_count;
|
||||
|
||||
struct wl1271_acx_mem_map *target_mem_map;
|
||||
|
||||
@ -440,11 +356,7 @@ struct wl1271 {
|
||||
/* Time-offset between host and chipset clocks */
|
||||
s64 time_offset;
|
||||
|
||||
/* Session counter for the chipset */
|
||||
int session_counter;
|
||||
|
||||
/* Frames scheduled for transmission, not handled yet */
|
||||
struct sk_buff_head tx_queue[NUM_TX_QUEUES];
|
||||
int tx_queue_count[NUM_TX_QUEUES];
|
||||
long stopped_queues_map;
|
||||
|
||||
@ -462,17 +374,6 @@ struct wl1271 {
|
||||
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
|
||||
int tx_frames_cnt;
|
||||
|
||||
/*
|
||||
* Security sequence number
|
||||
* bits 0-15: lower 16 bits part of sequence number
|
||||
* bits 16-47: higher 32 bits part of sequence number
|
||||
* bits 48-63: not in use
|
||||
*/
|
||||
u64 tx_security_seq;
|
||||
|
||||
/* 8 bits of the last sequence number in use */
|
||||
u8 tx_security_last_seq_lsb;
|
||||
|
||||
/* FW Rx counter */
|
||||
u32 rx_counter;
|
||||
|
||||
@ -507,59 +408,21 @@ struct wl1271 {
|
||||
u32 mbox_ptr[2];
|
||||
|
||||
/* Are we currently scanning */
|
||||
struct ieee80211_vif *scan_vif;
|
||||
struct wl1271_scan scan;
|
||||
struct delayed_work scan_complete_work;
|
||||
|
||||
bool sched_scanning;
|
||||
|
||||
/* probe-req template for the current AP */
|
||||
struct sk_buff *probereq;
|
||||
|
||||
/* Our association ID */
|
||||
u16 aid;
|
||||
|
||||
/*
|
||||
* currently configured rate set:
|
||||
* bits 0-15 - 802.11abg rates
|
||||
* bits 16-23 - 802.11n MCS index mask
|
||||
* support only 1 stream, thus only 8 bits for the MCS rates (0-7).
|
||||
*/
|
||||
u32 basic_rate_set;
|
||||
u32 basic_rate;
|
||||
u32 rate_set;
|
||||
u32 bitrate_masks[IEEE80211_NUM_BANDS];
|
||||
|
||||
/* The current band */
|
||||
enum ieee80211_band band;
|
||||
|
||||
/* Beaconing interval (needed for ad-hoc) */
|
||||
u32 beacon_int;
|
||||
|
||||
/* Default key (for WEP) */
|
||||
u32 default_key;
|
||||
|
||||
/* Rx Streaming */
|
||||
struct work_struct rx_streaming_enable_work;
|
||||
struct work_struct rx_streaming_disable_work;
|
||||
struct timer_list rx_streaming_timer;
|
||||
|
||||
struct completion *elp_compl;
|
||||
struct completion *ps_compl;
|
||||
struct delayed_work elp_work;
|
||||
struct delayed_work pspoll_work;
|
||||
|
||||
/* counter for ps-poll delivery failures */
|
||||
int ps_poll_failures;
|
||||
|
||||
/* retry counter for PSM entries */
|
||||
u8 psm_entry_retry;
|
||||
|
||||
/* in dBm */
|
||||
int power_level;
|
||||
|
||||
int rssi_thold;
|
||||
int last_rssi_event;
|
||||
|
||||
struct wl1271_stats stats;
|
||||
|
||||
__le32 buffer_32;
|
||||
@ -583,20 +446,9 @@ struct wl1271 {
|
||||
/* Most recently reported noise in dBm */
|
||||
s8 noise;
|
||||
|
||||
/* map for HLIDs of associated stations - when operating in AP mode */
|
||||
unsigned long ap_hlid_map[BITS_TO_LONGS(AP_MAX_STATIONS)];
|
||||
|
||||
/* recoreded keys for AP-mode - set here before AP startup */
|
||||
struct wl1271_ap_key *recorded_ap_keys[MAX_NUM_KEYS];
|
||||
|
||||
/* bands supported by this instance of wl12xx */
|
||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||
|
||||
/* RX BA constraint value */
|
||||
bool ba_support;
|
||||
u8 ba_rx_bitmap;
|
||||
bool ba_allowed;
|
||||
|
||||
int tcxo_clock;
|
||||
|
||||
/*
|
||||
@ -610,10 +462,7 @@ struct wl1271 {
|
||||
* AP-mode - links indexed by HLID. The global and broadcast links
|
||||
* are always active.
|
||||
*/
|
||||
struct wl1271_link links[AP_MAX_LINKS];
|
||||
|
||||
/* the hlid of the link where the last transmitted skb came from */
|
||||
int last_tx_hlid;
|
||||
struct wl1271_link links[WL12XX_MAX_LINKS];
|
||||
|
||||
/* AP-mode - a bitmap of links currently in PS mode according to FW */
|
||||
u32 ap_fw_ps_map;
|
||||
@ -632,21 +481,173 @@ struct wl1271 {
|
||||
|
||||
/* AP-mode - number of currently connected stations */
|
||||
int active_sta_count;
|
||||
|
||||
/* last wlvif we transmitted from */
|
||||
struct wl12xx_vif *last_wlvif;
|
||||
};
|
||||
|
||||
struct wl1271_station {
|
||||
u8 hlid;
|
||||
};
|
||||
|
||||
struct wl12xx_vif {
|
||||
struct wl1271 *wl;
|
||||
struct list_head list;
|
||||
unsigned long flags;
|
||||
u8 bss_type;
|
||||
u8 p2p; /* we are using p2p role */
|
||||
u8 role_id;
|
||||
|
||||
/* sta/ibss specific */
|
||||
u8 dev_role_id;
|
||||
u8 dev_hlid;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8 hlid;
|
||||
u8 ba_rx_bitmap;
|
||||
|
||||
u8 basic_rate_idx;
|
||||
u8 ap_rate_idx;
|
||||
u8 p2p_rate_idx;
|
||||
} sta;
|
||||
struct {
|
||||
u8 global_hlid;
|
||||
u8 bcast_hlid;
|
||||
|
||||
/* HLIDs bitmap of associated stations */
|
||||
unsigned long sta_hlid_map[BITS_TO_LONGS(
|
||||
WL12XX_MAX_LINKS)];
|
||||
|
||||
/* recoreded keys - set here before AP startup */
|
||||
struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS];
|
||||
|
||||
u8 mgmt_rate_idx;
|
||||
u8 bcast_rate_idx;
|
||||
u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT];
|
||||
} ap;
|
||||
};
|
||||
|
||||
/* the hlid of the last transmitted skb */
|
||||
int last_tx_hlid;
|
||||
|
||||
unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
|
||||
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
|
||||
u8 ssid_len;
|
||||
|
||||
/* The current band */
|
||||
enum ieee80211_band band;
|
||||
int channel;
|
||||
|
||||
u32 bitrate_masks[IEEE80211_NUM_BANDS];
|
||||
u32 basic_rate_set;
|
||||
|
||||
/*
|
||||
* currently configured rate set:
|
||||
* bits 0-15 - 802.11abg rates
|
||||
* bits 16-23 - 802.11n MCS index mask
|
||||
* support only 1 stream, thus only 8 bits for the MCS rates (0-7).
|
||||
*/
|
||||
u32 basic_rate;
|
||||
u32 rate_set;
|
||||
|
||||
/* probe-req template for the current AP */
|
||||
struct sk_buff *probereq;
|
||||
|
||||
/* Beaconing interval (needed for ad-hoc) */
|
||||
u32 beacon_int;
|
||||
|
||||
/* Default key (for WEP) */
|
||||
u32 default_key;
|
||||
|
||||
/* Our association ID */
|
||||
u16 aid;
|
||||
|
||||
/* Session counter for the chipset */
|
||||
int session_counter;
|
||||
|
||||
struct completion *ps_compl;
|
||||
struct delayed_work pspoll_work;
|
||||
|
||||
/* counter for ps-poll delivery failures */
|
||||
int ps_poll_failures;
|
||||
|
||||
/* retry counter for PSM entries */
|
||||
u8 psm_entry_retry;
|
||||
|
||||
/* in dBm */
|
||||
int power_level;
|
||||
|
||||
int rssi_thold;
|
||||
int last_rssi_event;
|
||||
|
||||
/* RX BA constraint value */
|
||||
bool ba_support;
|
||||
bool ba_allowed;
|
||||
|
||||
/* Rx Streaming */
|
||||
struct work_struct rx_streaming_enable_work;
|
||||
struct work_struct rx_streaming_disable_work;
|
||||
struct timer_list rx_streaming_timer;
|
||||
|
||||
/*
|
||||
* This struct must be last!
|
||||
* data that has to be saved acrossed reconfigs (e.g. recovery)
|
||||
* should be declared in this struct.
|
||||
*/
|
||||
struct {
|
||||
u8 persistent[0];
|
||||
/*
|
||||
* Security sequence number
|
||||
* bits 0-15: lower 16 bits part of sequence number
|
||||
* bits 16-47: higher 32 bits part of sequence number
|
||||
* bits 48-63: not in use
|
||||
*/
|
||||
u64 tx_security_seq;
|
||||
|
||||
/* 8 bits of the last sequence number in use */
|
||||
u8 tx_security_last_seq_lsb;
|
||||
};
|
||||
};
|
||||
|
||||
static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif)
|
||||
{
|
||||
return (struct wl12xx_vif *)vif->drv_priv;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif)
|
||||
{
|
||||
return container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
|
||||
}
|
||||
|
||||
#define wl12xx_for_each_wlvif(wl, wlvif) \
|
||||
list_for_each_entry(wlvif, &wl->wlvif_list, list)
|
||||
|
||||
#define wl12xx_for_each_wlvif_continue(wl, wlvif) \
|
||||
list_for_each_entry_continue(wlvif, &wl->wlvif_list, list)
|
||||
|
||||
#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type) \
|
||||
wl12xx_for_each_wlvif(wl, wlvif) \
|
||||
if (wlvif->bss_type == _bss_type)
|
||||
|
||||
#define wl12xx_for_each_wlvif_sta(wl, wlvif) \
|
||||
wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS)
|
||||
|
||||
#define wl12xx_for_each_wlvif_ap(wl, wlvif) \
|
||||
wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS)
|
||||
|
||||
int wl1271_plt_start(struct wl1271 *wl);
|
||||
int wl1271_plt_stop(struct wl1271 *wl);
|
||||
int wl1271_recalc_rx_streaming(struct wl1271 *wl);
|
||||
int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif);
|
||||
void wl12xx_queue_recovery_work(struct wl1271 *wl);
|
||||
size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
|
||||
|
||||
#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
|
||||
|
||||
#define SESSION_COUNTER_MAX 7 /* maximum value for the session counter */
|
||||
#define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */
|
||||
#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */
|
||||
|
||||
#define WL1271_DEFAULT_POWER_LEVEL 0
|
||||
|
||||
@ -669,8 +670,8 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
|
||||
/* Each RX/TX transaction requires an end-of-transaction transfer */
|
||||
#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0)
|
||||
|
||||
/* WL128X requires aggregated packets to be aligned to the SDIO block size */
|
||||
#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2)
|
||||
/* wl127x and SPI don't support SDIO block size alignment */
|
||||
#define WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT BIT(2)
|
||||
|
||||
/* Older firmwares did not implement the FW logger over bus feature */
|
||||
#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4)
|
||||
|
@ -116,11 +116,6 @@ struct wl12xx_ps_poll_template {
|
||||
u8 ta[ETH_ALEN];
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_qos_null_data_template {
|
||||
struct ieee80211_header header;
|
||||
__le16 qos_ctl;
|
||||
} __packed;
|
||||
|
||||
struct wl12xx_arp_rsp_template {
|
||||
struct ieee80211_hdr_3addr hdr;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/wl12xx.h>
|
||||
|
||||
static const struct wl12xx_platform_data *platform_data;
|
||||
static struct wl12xx_platform_data *platform_data;
|
||||
|
||||
int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
|
||||
{
|
||||
@ -18,7 +18,7 @@ int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct wl12xx_platform_data *wl12xx_get_platform_data(void)
|
||||
struct wl12xx_platform_data *wl12xx_get_platform_data(void)
|
||||
{
|
||||
if (!platform_data)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
@ -1694,6 +1694,23 @@ static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_is_public_action - check if frame is a public action frame
|
||||
* @hdr: the frame
|
||||
* @len: length of the frame
|
||||
*/
|
||||
static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr,
|
||||
size_t len)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (void *)hdr;
|
||||
|
||||
if (len < IEEE80211_MIN_ACTION_SIZE)
|
||||
return false;
|
||||
if (!ieee80211_is_action(hdr->frame_control))
|
||||
return false;
|
||||
return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_fhss_chan_to_freq - get channel frequency
|
||||
* @channel: the FHSS channel
|
||||
|
@ -2785,9 +2785,11 @@ enum nl80211_ap_sme_features {
|
||||
* @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
|
||||
* TX status to the socket error queue when requested with the
|
||||
* socket option.
|
||||
* @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
|
||||
*/
|
||||
enum nl80211_feature_flags {
|
||||
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
|
||||
NL80211_FEATURE_HT_IBSS = 1 << 1,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -54,6 +54,9 @@ struct wl12xx_platform_data {
|
||||
int board_ref_clock;
|
||||
int board_tcxo_clock;
|
||||
unsigned long platform_quirks;
|
||||
bool pwr_in_suspend;
|
||||
|
||||
struct wl1271_if_operations *ops;
|
||||
};
|
||||
|
||||
/* Platform does not support level trigger interrupts */
|
||||
@ -73,6 +76,6 @@ int wl12xx_set_platform_data(const struct wl12xx_platform_data *data)
|
||||
|
||||
#endif
|
||||
|
||||
const struct wl12xx_platform_data *wl12xx_get_platform_data(void);
|
||||
struct wl12xx_platform_data *wl12xx_get_platform_data(void);
|
||||
|
||||
#endif
|
||||
|
@ -36,6 +36,11 @@
|
||||
#define PF_BLUETOOTH AF_BLUETOOTH
|
||||
#endif
|
||||
|
||||
/* Bluetooth versions */
|
||||
#define BLUETOOTH_VER_1_1 1
|
||||
#define BLUETOOTH_VER_1_2 2
|
||||
#define BLUETOOTH_VER_2_0 3
|
||||
|
||||
/* Reserv for core and drivers use */
|
||||
#define BT_SKB_RESERVE 8
|
||||
|
||||
|
@ -88,6 +88,14 @@ enum {
|
||||
HCI_RESET,
|
||||
};
|
||||
|
||||
/*
|
||||
* BR/EDR and/or LE controller flags: the flags defined here should represent
|
||||
* states from the controller.
|
||||
*/
|
||||
enum {
|
||||
HCI_LE_SCAN,
|
||||
};
|
||||
|
||||
/* HCI ioctl defines */
|
||||
#define HCIDEVUP _IOW('H', 201, int)
|
||||
#define HCIDEVDOWN _IOW('H', 202, int)
|
||||
@ -453,6 +461,14 @@ struct hci_rp_user_confirm_reply {
|
||||
|
||||
#define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d
|
||||
|
||||
#define HCI_OP_USER_PASSKEY_REPLY 0x042e
|
||||
struct hci_cp_user_passkey_reply {
|
||||
bdaddr_t bdaddr;
|
||||
__le32 passkey;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_USER_PASSKEY_NEG_REPLY 0x042f
|
||||
|
||||
#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430
|
||||
struct hci_cp_remote_oob_data_reply {
|
||||
bdaddr_t bdaddr;
|
||||
@ -669,6 +685,12 @@ struct hci_rp_read_local_oob_data {
|
||||
|
||||
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
|
||||
|
||||
#define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66
|
||||
struct hci_rp_read_flow_control_mode {
|
||||
__u8 status;
|
||||
__u8 mode;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
|
||||
struct hci_cp_write_le_host_supported {
|
||||
__u8 le;
|
||||
@ -760,6 +782,15 @@ struct hci_rp_le_read_buffer_size {
|
||||
__u8 le_max_pkt;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
|
||||
struct hci_cp_le_set_scan_param {
|
||||
__u8 type;
|
||||
__le16 interval;
|
||||
__le16 window;
|
||||
__u8 own_address_type;
|
||||
__u8 filter_policy;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
|
||||
struct hci_cp_le_set_scan_enable {
|
||||
__u8 enable;
|
||||
@ -1076,6 +1107,11 @@ struct hci_ev_user_confirm_req {
|
||||
__le32 passkey;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_USER_PASSKEY_REQUEST 0x34
|
||||
struct hci_ev_user_passkey_req {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35
|
||||
struct hci_ev_remote_oob_data_request {
|
||||
bdaddr_t bdaddr;
|
||||
@ -1331,4 +1367,6 @@ struct hci_inquiry_req {
|
||||
};
|
||||
#define IREQ_CACHE_FLUSH 0x0001
|
||||
|
||||
extern int enable_hs;
|
||||
|
||||
#endif /* __HCI_H */
|
||||
|
@ -170,6 +170,8 @@ struct hci_dev {
|
||||
__u32 amp_max_flush_to;
|
||||
__u32 amp_be_flush_to;
|
||||
|
||||
__u8 flow_ctl_mode;
|
||||
|
||||
unsigned int auto_accept_delay;
|
||||
|
||||
unsigned long quirks;
|
||||
@ -250,6 +252,8 @@ struct hci_dev {
|
||||
|
||||
struct module *owner;
|
||||
|
||||
unsigned long dev_flags;
|
||||
|
||||
int (*open)(struct hci_dev *hdev);
|
||||
int (*close)(struct hci_dev *hdev);
|
||||
int (*flush)(struct hci_dev *hdev);
|
||||
@ -917,11 +921,13 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
|
||||
int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
|
||||
int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
|
||||
u8 persistent);
|
||||
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int mgmt_disconnect_failed(struct hci_dev *hdev);
|
||||
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
|
||||
u8 status);
|
||||
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type);
|
||||
int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type);
|
||||
int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 status);
|
||||
int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
|
||||
int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
@ -933,14 +939,20 @@ int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
|
||||
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
|
||||
u8 *randomizer, u8 status);
|
||||
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
|
||||
u8 *dev_class, s8 rssi, u8 *eir);
|
||||
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir);
|
||||
int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
|
||||
int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status);
|
||||
int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status);
|
||||
int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status);
|
||||
int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
|
||||
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
|
@ -792,7 +792,6 @@ static inline __u8 __ctrl_size(struct l2cap_chan *chan)
|
||||
}
|
||||
|
||||
extern int disable_ertm;
|
||||
extern int enable_hs;
|
||||
|
||||
int l2cap_init_sockets(void);
|
||||
void l2cap_cleanup_sockets(void);
|
||||
@ -810,5 +809,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan);
|
||||
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
u32 priority);
|
||||
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
|
||||
int l2cap_chan_check_security(struct l2cap_chan *chan);
|
||||
|
||||
#endif /* __L2CAP_H */
|
||||
|
@ -23,6 +23,23 @@
|
||||
|
||||
#define MGMT_INDEX_NONE 0xFFFF
|
||||
|
||||
#define MGMT_STATUS_SUCCESS 0x00
|
||||
#define MGMT_STATUS_UNKNOWN_COMMAND 0x01
|
||||
#define MGMT_STATUS_NOT_CONNECTED 0x02
|
||||
#define MGMT_STATUS_FAILED 0x03
|
||||
#define MGMT_STATUS_CONNECT_FAILED 0x04
|
||||
#define MGMT_STATUS_AUTH_FAILED 0x05
|
||||
#define MGMT_STATUS_NOT_PAIRED 0x06
|
||||
#define MGMT_STATUS_NO_RESOURCES 0x07
|
||||
#define MGMT_STATUS_TIMEOUT 0x08
|
||||
#define MGMT_STATUS_ALREADY_CONNECTED 0x09
|
||||
#define MGMT_STATUS_BUSY 0x0a
|
||||
#define MGMT_STATUS_REJECTED 0x0b
|
||||
#define MGMT_STATUS_NOT_SUPPORTED 0x0c
|
||||
#define MGMT_STATUS_INVALID_PARAMS 0x0d
|
||||
#define MGMT_STATUS_DISCONNECTED 0x0e
|
||||
#define MGMT_STATUS_NOT_POWERED 0x0f
|
||||
|
||||
struct mgmt_hdr {
|
||||
__le16 opcode;
|
||||
__le16 index;
|
||||
@ -119,6 +136,10 @@ struct mgmt_cp_remove_keys {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 disconnect;
|
||||
} __packed;
|
||||
struct mgmt_rp_remove_keys {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
};
|
||||
|
||||
#define MGMT_OP_DISCONNECT 0x000F
|
||||
struct mgmt_cp_disconnect {
|
||||
@ -126,11 +147,12 @@ struct mgmt_cp_disconnect {
|
||||
} __packed;
|
||||
struct mgmt_rp_disconnect {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_ADDR_BREDR 0x00
|
||||
#define MGMT_ADDR_LE 0x01
|
||||
#define MGMT_ADDR_BREDR_LE 0x02
|
||||
#define MGMT_ADDR_LE_PUBLIC 0x01
|
||||
#define MGMT_ADDR_LE_RANDOM 0x02
|
||||
#define MGMT_ADDR_INVALID 0xff
|
||||
|
||||
struct mgmt_addr_info {
|
||||
@ -167,11 +189,11 @@ struct mgmt_cp_set_io_capability {
|
||||
|
||||
#define MGMT_OP_PAIR_DEVICE 0x0014
|
||||
struct mgmt_cp_pair_device {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 io_cap;
|
||||
} __packed;
|
||||
struct mgmt_rp_pair_device {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
@ -210,6 +232,9 @@ struct mgmt_cp_remove_remote_oob_data {
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_START_DISCOVERY 0x001B
|
||||
struct mgmt_cp_start_discovery {
|
||||
__u8 type;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_STOP_DISCOVERY 0x001C
|
||||
|
||||
@ -228,6 +253,17 @@ struct mgmt_cp_set_fast_connectable {
|
||||
__u8 enable;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_REPLY 0x0020
|
||||
struct mgmt_cp_user_passkey_reply {
|
||||
bdaddr_t bdaddr;
|
||||
__le32 passkey;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x0021
|
||||
struct mgmt_cp_user_passkey_neg_reply {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
__le16 opcode;
|
||||
@ -322,3 +358,8 @@ struct mgmt_ev_device_blocked {
|
||||
struct mgmt_ev_device_unblocked {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_USER_PASSKEY_REQUEST 0x0017
|
||||
struct mgmt_ev_user_passkey_request {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
@ -1149,6 +1149,7 @@ struct cfg80211_ibss_params {
|
||||
u8 *ssid;
|
||||
u8 *bssid;
|
||||
struct ieee80211_channel *channel;
|
||||
enum nl80211_channel_type channel_type;
|
||||
u8 *ie;
|
||||
u8 ssid_len, ie_len;
|
||||
u16 beacon_interval;
|
||||
@ -3267,6 +3268,16 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
|
||||
const u8 *frame, size_t len,
|
||||
int freq, gfp_t gfp);
|
||||
|
||||
/*
|
||||
* cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
|
||||
* @wiphy: the wiphy
|
||||
* @chan: main channel
|
||||
* @channel_type: HT mode
|
||||
*/
|
||||
int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type);
|
||||
|
||||
/* Logging, debugging and troubleshooting/diagnostic helpers. */
|
||||
|
||||
/* wiphy_printk helpers, similar to dev_printk */
|
||||
|
@ -77,17 +77,12 @@ static struct bnep_session *__bnep_get_session(u8 *dst)
|
||||
|
||||
static void __bnep_link_session(struct bnep_session *s)
|
||||
{
|
||||
/* It's safe to call __module_get() here because sessions are added
|
||||
by the socket layer which has to hold the reference to this module.
|
||||
*/
|
||||
__module_get(THIS_MODULE);
|
||||
list_add(&s->list, &bnep_session_list);
|
||||
}
|
||||
|
||||
static void __bnep_unlink_session(struct bnep_session *s)
|
||||
{
|
||||
list_del(&s->list);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static int bnep_send(struct bnep_session *s, void *data, size_t len)
|
||||
@ -528,6 +523,7 @@ static int bnep_session(void *arg)
|
||||
|
||||
up_write(&bnep_session_sem);
|
||||
free_netdev(dev);
|
||||
module_put_and_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -614,9 +610,11 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
|
||||
|
||||
__bnep_link_session(s);
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
|
||||
if (IS_ERR(s->task)) {
|
||||
/* Session thread start failed, gotta cleanup. */
|
||||
module_put(THIS_MODULE);
|
||||
unregister_netdev(dev);
|
||||
__bnep_unlink_session(s);
|
||||
err = PTR_ERR(s->task);
|
||||
|
@ -65,14 +65,12 @@ static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
|
||||
|
||||
static void __cmtp_link_session(struct cmtp_session *session)
|
||||
{
|
||||
__module_get(THIS_MODULE);
|
||||
list_add(&session->list, &cmtp_session_list);
|
||||
}
|
||||
|
||||
static void __cmtp_unlink_session(struct cmtp_session *session)
|
||||
{
|
||||
list_del(&session->list);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
|
||||
@ -325,6 +323,7 @@ static int cmtp_session(void *arg)
|
||||
up_write(&cmtp_session_sem);
|
||||
|
||||
kfree(session);
|
||||
module_put_and_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -374,9 +373,11 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
|
||||
|
||||
__cmtp_link_session(session);
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
|
||||
session->num);
|
||||
if (IS_ERR(session->task)) {
|
||||
module_put(THIS_MODULE);
|
||||
err = PTR_ERR(session->task);
|
||||
goto unlink;
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn)
|
||||
|
||||
BT_DBG("%p", conn);
|
||||
|
||||
if (conn->hdev->hci_ver < 2)
|
||||
if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2)
|
||||
return;
|
||||
|
||||
bacpy(&cp.bdaddr, &conn->dst);
|
||||
|
@ -54,6 +54,8 @@
|
||||
|
||||
#define AUTO_OFF_TIMEOUT 2000
|
||||
|
||||
int enable_hs;
|
||||
|
||||
static void hci_cmd_task(unsigned long arg);
|
||||
static void hci_rx_task(unsigned long arg);
|
||||
static void hci_tx_task(unsigned long arg);
|
||||
@ -228,18 +230,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
|
||||
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
|
||||
|
||||
#if 0
|
||||
/* Host buffer size */
|
||||
{
|
||||
struct hci_cp_host_buffer_size cp;
|
||||
cp.acl_mtu = cpu_to_le16(HCI_MAX_ACL_SIZE);
|
||||
cp.sco_mtu = HCI_MAX_SCO_SIZE;
|
||||
cp.acl_max_pkt = cpu_to_le16(0xffff);
|
||||
cp.sco_max_pkt = cpu_to_le16(0xffff);
|
||||
hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read BD Address */
|
||||
hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
|
||||
|
||||
@ -521,8 +511,9 @@ int hci_dev_open(__u16 dev)
|
||||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
||||
set_bit(HCI_RAW, &hdev->flags);
|
||||
|
||||
/* Treat all non BR/EDR controllers as raw devices for now */
|
||||
if (hdev->dev_type != HCI_BREDR)
|
||||
/* Treat all non BR/EDR controllers as raw devices if
|
||||
enable_hs is not set */
|
||||
if (hdev->dev_type != HCI_BREDR && !enable_hs)
|
||||
set_bit(HCI_RAW, &hdev->flags);
|
||||
|
||||
if (hdev->open(hdev)) {
|
||||
@ -1336,14 +1327,12 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||
{
|
||||
struct bdaddr_list *entry;
|
||||
|
||||
if (bacmp(bdaddr, BDADDR_ANY) == 0) {
|
||||
if (bacmp(bdaddr, BDADDR_ANY) == 0)
|
||||
return hci_blacklist_clear(hdev);
|
||||
}
|
||||
|
||||
entry = hci_blacklist_lookup(hdev, bdaddr);
|
||||
if (!entry) {
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
@ -1451,12 +1440,13 @@ int hci_register_dev(struct hci_dev *hdev)
|
||||
|
||||
sprintf(hdev->name, "hci%d", id);
|
||||
hdev->id = id;
|
||||
list_add(&hdev->list, head);
|
||||
list_add_tail(&hdev->list, head);
|
||||
|
||||
atomic_set(&hdev->refcnt, 1);
|
||||
spin_lock_init(&hdev->lock);
|
||||
|
||||
hdev->flags = 0;
|
||||
hdev->dev_flags = 0;
|
||||
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
|
||||
hdev->esco_type = (ESCO_HV1);
|
||||
hdev->link_mode = (HCI_LM_ACCEPT);
|
||||
@ -2614,3 +2604,6 @@ int hci_cancel_inquiry(struct hci_dev *hdev)
|
||||
|
||||
return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
|
||||
}
|
||||
|
||||
module_param(enable_hs, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_hs, "Enable High Speed");
|
||||
|
@ -55,8 +55,12 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, status);
|
||||
|
||||
if (status)
|
||||
if (status) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_stop_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
clear_bit(HCI_INQUIRY, &hdev->flags);
|
||||
|
||||
@ -190,6 +194,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
clear_bit(HCI_RESET, &hdev->flags);
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_RESET, status);
|
||||
|
||||
hdev->dev_flags = 0;
|
||||
}
|
||||
|
||||
static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
@ -494,7 +500,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
|
||||
|
||||
/* CSR 1.1 dongles does not accept any bitfield so don't try to set
|
||||
* any event mask for pre 1.2 devices */
|
||||
if (hdev->lmp_ver <= 1)
|
||||
if (hdev->hci_ver < BLUETOOTH_VER_1_2)
|
||||
return;
|
||||
|
||||
events[4] |= 0x01; /* Flow Specification Complete */
|
||||
@ -558,7 +564,7 @@ static void hci_setup(struct hci_dev *hdev)
|
||||
{
|
||||
hci_setup_event_mask(hdev);
|
||||
|
||||
if (hdev->lmp_ver > 1)
|
||||
if (hdev->hci_ver > BLUETOOTH_VER_1_1)
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
|
||||
|
||||
if (hdev->features[6] & LMP_SIMPLE_PAIR) {
|
||||
@ -713,6 +719,21 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
|
||||
hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
|
||||
}
|
||||
|
||||
static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||
|
||||
if (rp->status)
|
||||
return;
|
||||
|
||||
hdev->flow_ctl_mode = rp->mode;
|
||||
|
||||
hci_req_complete(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, rp->status);
|
||||
}
|
||||
|
||||
static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_buffer_size *rp = (void *) skb->data;
|
||||
@ -927,6 +948,37 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr,
|
||||
rp->status);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
|
||||
rp->status);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@ -940,6 +992,13 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, status);
|
||||
}
|
||||
|
||||
static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@ -956,12 +1015,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
||||
return;
|
||||
|
||||
if (cp->enable == 0x01) {
|
||||
set_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||
|
||||
del_timer(&hdev->adv_timer);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_adv_entries_clear(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
} else if (cp->enable == 0x00) {
|
||||
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
||||
|
||||
mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
@ -1014,7 +1077,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
||||
hci_conn_check_pending(hdev);
|
||||
hci_dev_lock(hdev);
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_inquiry_failed(hdev, status);
|
||||
mgmt_start_discovery_failed(hdev, status);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
@ -1437,7 +1500,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
|
||||
data.rssi = 0x00;
|
||||
data.ssp_mode = 0x00;
|
||||
hci_inquiry_cache_update(hdev, &data);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, 0, NULL);
|
||||
}
|
||||
|
||||
@ -1472,7 +1535,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
||||
conn->state = BT_CONFIG;
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
mgmt_connected(hdev, &ev->bdaddr, conn->type);
|
||||
mgmt_connected(hdev, &ev->bdaddr, conn->type,
|
||||
conn->dst_type);
|
||||
} else
|
||||
conn->state = BT_CONNECTED;
|
||||
|
||||
@ -1494,7 +1558,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
||||
}
|
||||
|
||||
/* Set packet type for incoming connection */
|
||||
if (!conn->out && hdev->hci_ver < 3) {
|
||||
if (!conn->out && hdev->hci_ver < BLUETOOTH_VER_2_0) {
|
||||
struct hci_cp_change_conn_ptype cp;
|
||||
cp.handle = ev->handle;
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
@ -1505,7 +1569,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
||||
conn->state = BT_CLOSED;
|
||||
if (conn->type == ACL_LINK)
|
||||
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
||||
ev->status);
|
||||
conn->dst_type, ev->status);
|
||||
}
|
||||
|
||||
if (conn->type == ACL_LINK)
|
||||
@ -1604,26 +1668,27 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
|
||||
|
||||
BT_DBG("%s status %d", hdev->name, ev->status);
|
||||
|
||||
if (ev->status) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_disconnect_failed(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
conn->state = BT_CLOSED;
|
||||
if (ev->status == 0)
|
||||
conn->state = BT_CLOSED;
|
||||
|
||||
if (conn->type == ACL_LINK || conn->type == LE_LINK)
|
||||
mgmt_disconnected(hdev, &conn->dst, conn->type);
|
||||
if (conn->type == ACL_LINK || conn->type == LE_LINK) {
|
||||
if (ev->status != 0)
|
||||
mgmt_disconnect_failed(hdev, &conn->dst, ev->status);
|
||||
else
|
||||
mgmt_disconnected(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type);
|
||||
}
|
||||
|
||||
hci_proto_disconn_cfm(conn, ev->reason);
|
||||
hci_conn_del(conn);
|
||||
if (ev->status == 0) {
|
||||
hci_proto_disconn_cfm(conn, ev->reason);
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
@ -1961,6 +2026,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
||||
hci_cc_write_ca_timeout(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_READ_FLOW_CONTROL_MODE:
|
||||
hci_cc_read_flow_control_mode(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_READ_LOCAL_AMP_INFO:
|
||||
hci_cc_read_local_amp_info(hdev, skb);
|
||||
break;
|
||||
@ -2009,6 +2078,17 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
||||
hci_cc_user_confirm_neg_reply(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_USER_PASSKEY_REPLY:
|
||||
hci_cc_user_passkey_reply(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_USER_PASSKEY_NEG_REPLY:
|
||||
hci_cc_user_passkey_neg_reply(hdev, skb);
|
||||
|
||||
case HCI_OP_LE_SET_SCAN_PARAM:
|
||||
hci_cc_le_set_scan_param(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_SET_SCAN_ENABLE:
|
||||
hci_cc_le_set_scan_enable(hdev, skb);
|
||||
break;
|
||||
@ -2096,7 +2176,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
case HCI_OP_DISCONNECT:
|
||||
if (ev->status != 0)
|
||||
mgmt_disconnect_failed(hdev);
|
||||
mgmt_disconnect_failed(hdev, NULL, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_CREATE_CONN:
|
||||
@ -2444,7 +2524,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
||||
data.rssi = info->rssi;
|
||||
data.ssp_mode = 0x00;
|
||||
hci_inquiry_cache_update(hdev, &data);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, info->rssi,
|
||||
NULL);
|
||||
}
|
||||
@ -2461,7 +2541,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
||||
data.rssi = info->rssi;
|
||||
data.ssp_mode = 0x00;
|
||||
hci_inquiry_cache_update(hdev, &data);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, info->rssi,
|
||||
NULL);
|
||||
}
|
||||
@ -2604,7 +2684,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
|
||||
data.rssi = info->rssi;
|
||||
data.ssp_mode = 0x01;
|
||||
hci_inquiry_cache_update(hdev, &data);
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
||||
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
||||
info->dev_class, info->rssi, info->data);
|
||||
}
|
||||
|
||||
@ -2768,6 +2848,21 @@ unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_user_passkey_req *ev = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_user_passkey_request(hdev, &ev->bdaddr);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
|
||||
@ -2868,14 +2963,15 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
|
||||
}
|
||||
|
||||
if (ev->status) {
|
||||
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, ev->status);
|
||||
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
||||
conn->dst_type, ev->status);
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
conn->state = BT_CLOSED;
|
||||
hci_conn_del(conn);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
mgmt_connected(hdev, &ev->bdaddr, conn->type);
|
||||
mgmt_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type);
|
||||
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
conn->handle = __le16_to_cpu(ev->handle);
|
||||
@ -3106,6 +3202,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_user_confirm_request_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_USER_PASSKEY_REQUEST:
|
||||
hci_user_passkey_request_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_EV_SIMPLE_PAIR_COMPLETE:
|
||||
hci_simple_pair_complete_evt(hdev, skb);
|
||||
break;
|
||||
|
@ -57,7 +57,6 @@
|
||||
#include <net/bluetooth/smp.h>
|
||||
|
||||
int disable_ertm;
|
||||
int enable_hs;
|
||||
|
||||
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
|
||||
static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
|
||||
@ -97,7 +96,6 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16
|
||||
return c;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
|
||||
@ -154,12 +152,9 @@ static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
|
||||
|
||||
list_for_each_entry(c, &chan_list, global_l) {
|
||||
if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
|
||||
goto found;
|
||||
return c;
|
||||
}
|
||||
|
||||
c = NULL;
|
||||
found:
|
||||
return c;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
|
||||
@ -234,8 +229,37 @@ static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
|
||||
chan_put(chan);
|
||||
}
|
||||
|
||||
static char *state_to_string(int state)
|
||||
{
|
||||
switch(state) {
|
||||
case BT_CONNECTED:
|
||||
return "BT_CONNECTED";
|
||||
case BT_OPEN:
|
||||
return "BT_OPEN";
|
||||
case BT_BOUND:
|
||||
return "BT_BOUND";
|
||||
case BT_LISTEN:
|
||||
return "BT_LISTEN";
|
||||
case BT_CONNECT:
|
||||
return "BT_CONNECT";
|
||||
case BT_CONNECT2:
|
||||
return "BT_CONNECT2";
|
||||
case BT_CONFIG:
|
||||
return "BT_CONFIG";
|
||||
case BT_DISCONN:
|
||||
return "BT_DISCONN";
|
||||
case BT_CLOSED:
|
||||
return "BT_CLOSED";
|
||||
}
|
||||
|
||||
return "invalid state";
|
||||
}
|
||||
|
||||
static void l2cap_state_change(struct l2cap_chan *chan, int state)
|
||||
{
|
||||
BT_DBG("%p %s -> %s", chan, state_to_string(chan->state),
|
||||
state_to_string(state));
|
||||
|
||||
chan->state = state;
|
||||
chan->ops->state_change(chan->data, state);
|
||||
}
|
||||
@ -518,7 +542,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
|
||||
}
|
||||
|
||||
/* Service level security */
|
||||
static inline int l2cap_check_security(struct l2cap_chan *chan)
|
||||
int l2cap_chan_check_security(struct l2cap_chan *chan)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
__u8 auth_type;
|
||||
@ -664,7 +688,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
|
||||
if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
|
||||
return;
|
||||
|
||||
if (l2cap_check_security(chan) &&
|
||||
if (l2cap_chan_check_security(chan) &&
|
||||
__l2cap_no_conn_pending(chan)) {
|
||||
struct l2cap_conn_req req;
|
||||
req.scid = cpu_to_le16(chan->scid);
|
||||
@ -754,7 +778,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
||||
if (chan->state == BT_CONNECT) {
|
||||
struct l2cap_conn_req req;
|
||||
|
||||
if (!l2cap_check_security(chan) ||
|
||||
if (!l2cap_chan_check_security(chan) ||
|
||||
!__l2cap_no_conn_pending(chan)) {
|
||||
bh_unlock_sock(sk);
|
||||
continue;
|
||||
@ -787,7 +811,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
||||
rsp.scid = cpu_to_le16(chan->dcid);
|
||||
rsp.dcid = cpu_to_le16(chan->scid);
|
||||
|
||||
if (l2cap_check_security(chan)) {
|
||||
if (l2cap_chan_check_security(chan)) {
|
||||
if (bt_sk(sk)->defer_setup) {
|
||||
struct sock *parent = bt_sk(sk)->parent;
|
||||
rsp.result = cpu_to_le16(L2CAP_CR_PEND);
|
||||
@ -1181,7 +1205,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan)
|
||||
if (hcon->state == BT_CONNECTED) {
|
||||
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
|
||||
__clear_chan_timer(chan);
|
||||
if (l2cap_check_security(chan))
|
||||
if (l2cap_chan_check_security(chan))
|
||||
l2cap_state_change(chan, BT_CONNECTED);
|
||||
} else
|
||||
l2cap_do_start(chan);
|
||||
@ -1318,14 +1342,12 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
do {
|
||||
if (bt_cb(skb)->tx_seq == tx_seq)
|
||||
break;
|
||||
|
||||
while (bt_cb(skb)->tx_seq != tx_seq) {
|
||||
if (skb_queue_is_last(&chan->tx_q, skb))
|
||||
return;
|
||||
|
||||
} while ((skb = skb_queue_next(&chan->tx_q, skb)));
|
||||
skb = skb_queue_next(&chan->tx_q, skb);
|
||||
}
|
||||
|
||||
if (chan->remote_max_tx &&
|
||||
bt_cb(skb)->retries == chan->remote_max_tx) {
|
||||
@ -1906,7 +1928,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
|
||||
{
|
||||
struct l2cap_conf_efs efs;
|
||||
|
||||
switch(chan->mode) {
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_ERTM:
|
||||
efs.id = chan->local_id;
|
||||
efs.stype = chan->local_stype;
|
||||
@ -2606,7 +2628,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
|
||||
chan->ident = cmd->ident;
|
||||
|
||||
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
|
||||
if (l2cap_check_security(chan)) {
|
||||
if (l2cap_chan_check_security(chan)) {
|
||||
if (bt_sk(sk)->defer_setup) {
|
||||
l2cap_state_change(chan, BT_CONNECT2);
|
||||
result = L2CAP_CR_PEND;
|
||||
@ -3019,7 +3041,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
|
||||
|
||||
/* don't delete l2cap channel if sk is owned by user */
|
||||
if (sock_owned_by_user(sk)) {
|
||||
l2cap_state_change(chan,BT_DISCONN);
|
||||
l2cap_state_change(chan, BT_DISCONN);
|
||||
__clear_chan_timer(chan);
|
||||
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
|
||||
bh_unlock_sock(sk);
|
||||
@ -3562,14 +3584,10 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
|
||||
bt_cb(skb)->sar = sar;
|
||||
|
||||
next_skb = skb_peek(&chan->srej_q);
|
||||
if (!next_skb) {
|
||||
__skb_queue_tail(&chan->srej_q, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
|
||||
|
||||
do {
|
||||
while (next_skb) {
|
||||
if (bt_cb(next_skb)->tx_seq == tx_seq)
|
||||
return -EINVAL;
|
||||
|
||||
@ -3582,9 +3600,10 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
|
||||
}
|
||||
|
||||
if (skb_queue_is_last(&chan->srej_q, next_skb))
|
||||
break;
|
||||
|
||||
} while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
|
||||
next_skb = NULL;
|
||||
else
|
||||
next_skb = skb_queue_next(&chan->srej_q, next_skb);
|
||||
}
|
||||
|
||||
__skb_queue_tail(&chan->srej_q, skb);
|
||||
|
||||
@ -3788,7 +3807,7 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
||||
}
|
||||
}
|
||||
|
||||
static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
||||
static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
||||
{
|
||||
struct srej_list *new;
|
||||
u32 control;
|
||||
@ -3799,6 +3818,9 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
||||
l2cap_send_sframe(chan, control);
|
||||
|
||||
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
new->tx_seq = chan->expected_tx_seq;
|
||||
|
||||
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
|
||||
@ -3807,6 +3829,8 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
|
||||
}
|
||||
|
||||
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
|
||||
@ -3877,7 +3901,12 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
l2cap_send_srejframe(chan, tx_seq);
|
||||
|
||||
err = l2cap_send_srejframe(chan, tx_seq);
|
||||
if (err < 0) {
|
||||
l2cap_send_disconn_req(chan->conn, chan, -err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
expected_tx_seq_offset = __seq_offset(chan,
|
||||
@ -3899,7 +3928,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
|
||||
|
||||
set_bit(CONN_SEND_PBIT, &chan->conn_state);
|
||||
|
||||
l2cap_send_srejframe(chan, tx_seq);
|
||||
err = l2cap_send_srejframe(chan, tx_seq);
|
||||
if (err < 0) {
|
||||
l2cap_send_disconn_req(chan->conn, chan, -err);
|
||||
return err;
|
||||
}
|
||||
|
||||
__clear_ack_timer(chan);
|
||||
}
|
||||
@ -3928,11 +3961,12 @@ expected:
|
||||
l2cap_retransmit_frames(chan);
|
||||
}
|
||||
|
||||
__set_ack_timer(chan);
|
||||
|
||||
chan->num_acked = (chan->num_acked + 1) % num_to_ack;
|
||||
if (chan->num_acked == num_to_ack - 1)
|
||||
l2cap_send_ack(chan);
|
||||
else
|
||||
__set_ack_timer(chan);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -4768,6 +4802,3 @@ void l2cap_exit(void)
|
||||
|
||||
module_param(disable_ertm, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
|
||||
|
||||
module_param(enable_hs, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_hs, "Enable High Speed");
|
||||
|
@ -626,8 +626,13 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
||||
|
||||
chan->sec_level = sec.level;
|
||||
|
||||
if (!chan->conn)
|
||||
break;
|
||||
|
||||
conn = chan->conn;
|
||||
if (conn && chan->scid == L2CAP_CID_LE_DATA) {
|
||||
|
||||
/*change security for LE channels */
|
||||
if (chan->scid == L2CAP_CID_LE_DATA) {
|
||||
if (!conn->hcon->out) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
@ -635,9 +640,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
||||
|
||||
if (smp_conn_security(conn, sec.level))
|
||||
break;
|
||||
|
||||
err = 0;
|
||||
sk->sk_state = BT_CONFIG;
|
||||
|
||||
/* or for ACL link, under defer_setup time */
|
||||
} else if (sk->sk_state == BT_CONNECT2 &&
|
||||
bt_sk(sk)->defer_setup) {
|
||||
err = l2cap_chan_check_security(chan);
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -232,6 +232,18 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
|
||||
{
|
||||
if (send)
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
|
||||
&reason);
|
||||
|
||||
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
|
||||
mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason);
|
||||
del_timer(&conn->security_timer);
|
||||
smp_chan_destroy(conn);
|
||||
}
|
||||
|
||||
static void confirm_work(struct work_struct *work)
|
||||
{
|
||||
struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
|
||||
@ -270,8 +282,7 @@ static void confirm_work(struct work_struct *work)
|
||||
return;
|
||||
|
||||
error:
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
|
||||
smp_chan_destroy(conn);
|
||||
smp_failure(conn, reason, 1);
|
||||
}
|
||||
|
||||
static void random_work(struct work_struct *work)
|
||||
@ -354,8 +365,7 @@ static void random_work(struct work_struct *work)
|
||||
return;
|
||||
|
||||
error:
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
|
||||
smp_chan_destroy(conn);
|
||||
smp_failure(conn, reason, 1);
|
||||
}
|
||||
|
||||
static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
@ -379,7 +389,15 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
|
||||
void smp_chan_destroy(struct l2cap_conn *conn)
|
||||
{
|
||||
kfree(conn->smp_chan);
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
|
||||
|
||||
if (smp->tfm)
|
||||
crypto_free_blkcipher(smp->tfm);
|
||||
|
||||
kfree(smp);
|
||||
conn->smp_chan = NULL;
|
||||
hci_conn_put(conn->hcon);
|
||||
}
|
||||
|
||||
@ -647,6 +665,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
break;
|
||||
|
||||
case SMP_CMD_PAIRING_FAIL:
|
||||
smp_failure(conn, skb->data[0], 0);
|
||||
reason = 0;
|
||||
err = -EPERM;
|
||||
break;
|
||||
@ -692,8 +711,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
done:
|
||||
if (reason)
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
|
||||
&reason);
|
||||
smp_failure(conn, reason, 1);
|
||||
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
|
@ -185,6 +185,8 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
|
||||
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
|
||||
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
@ -83,6 +83,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
|
||||
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
|
||||
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
@ -419,7 +421,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
||||
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
sdata->vif.type != NL80211_IFTYPE_AP &&
|
||||
sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
|
||||
@ -430,6 +433,27 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 802.11n-2009 11.5.1.1: If the initiating STA is an HT STA, is a
|
||||
* member of an IBSS, and has no other existing Block Ack agreement
|
||||
* with the recipient STA, then the initiating STA shall transmit a
|
||||
* Probe Request frame to the recipient STA and shall not transmit an
|
||||
* ADDBA Request frame unless it receives a Probe Response frame
|
||||
* from the recipient within dot11ADDBAFailureTimeout.
|
||||
*
|
||||
* The probe request mechanism for ADDBA is currently not implemented,
|
||||
* but we only build up Block Ack session with HT STAs. This information
|
||||
* is set when we receive a bss info from a probe response or a beacon.
|
||||
*/
|
||||
if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
!sta->sta.ht_cap.ht_supported) {
|
||||
#ifdef CONFIG_MAC80211_HT_DEBUG
|
||||
printk(KERN_DEBUG "BA request denied - IBSS STA %pM"
|
||||
"does not advertise HT support\n", pubsta->addr);
|
||||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
/* we have tried too many times, receiver does not want A-MPDU */
|
||||
|
@ -47,7 +47,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
int i;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION) {
|
||||
WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION);
|
||||
/* AP interfaces call this code when adding new stations,
|
||||
* so just silently ignore non station interfaces.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
@ -282,6 +284,8 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
|
||||
memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
|
||||
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
|
@ -77,6 +77,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_bss *bss;
|
||||
u32 bss_change;
|
||||
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
lockdep_assert_held(&ifibss->mtx);
|
||||
|
||||
@ -105,8 +106,16 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
|
||||
|
||||
local->oper_channel = chan;
|
||||
WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
|
||||
channel_type = ifibss->channel_type;
|
||||
if (channel_type > NL80211_CHAN_HT20 &&
|
||||
!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
|
||||
channel_type = NL80211_CHAN_HT20;
|
||||
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
|
||||
/* can only fail due to HT40+/- mismatch */
|
||||
channel_type = NL80211_CHAN_HT20;
|
||||
WARN_ON(!ieee80211_set_channel_type(local, sdata,
|
||||
NL80211_CHAN_HT20));
|
||||
}
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
||||
|
||||
sband = local->hw.wiphy->bands[chan->band];
|
||||
@ -172,6 +181,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
memcpy(skb_put(skb, ifibss->ie_len),
|
||||
ifibss->ie, ifibss->ie_len);
|
||||
|
||||
/* add HT capability and information IEs */
|
||||
if (channel_type && sband->ht_cap.ht_supported) {
|
||||
pos = skb_put(skb, 4 +
|
||||
sizeof(struct ieee80211_ht_cap) +
|
||||
sizeof(struct ieee80211_ht_info));
|
||||
pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
|
||||
sband->ht_cap.cap);
|
||||
pos = ieee80211_ie_build_ht_info(pos,
|
||||
&sband->ht_cap,
|
||||
chan,
|
||||
channel_type);
|
||||
}
|
||||
|
||||
if (local->hw.queues >= 4) {
|
||||
pos = skb_put(skb, 9);
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
@ -195,6 +217,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
bss_change |= BSS_CHANGED_BEACON;
|
||||
bss_change |= BSS_CHANGED_BEACON_ENABLED;
|
||||
bss_change |= BSS_CHANGED_BASIC_RATES;
|
||||
bss_change |= BSS_CHANGED_HT;
|
||||
bss_change |= BSS_CHANGED_IBSS;
|
||||
sdata->vif.bss_conf.ibss_joined = true;
|
||||
ieee80211_bss_info_change_notify(sdata, bss_change);
|
||||
@ -268,6 +291,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
u64 beacon_timestamp, rx_timestamp;
|
||||
u32 supp_rates = 0;
|
||||
enum ieee80211_band band = rx_status->band;
|
||||
struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
|
||||
bool rates_updated = false;
|
||||
|
||||
if (elems->ds_params && elems->ds_params_len == 1)
|
||||
freq = ieee80211_channel_to_frequency(elems->ds_params[0],
|
||||
@ -307,7 +332,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
prev_rates,
|
||||
sta->sta.supp_rates[band]);
|
||||
#endif
|
||||
rate_control_rate_init(sta);
|
||||
rates_updated = true;
|
||||
}
|
||||
} else
|
||||
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
|
||||
@ -318,6 +343,39 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
if (sta && elems->wmm_info)
|
||||
set_sta_flag(sta, WLAN_STA_WME);
|
||||
|
||||
if (sta && elems->ht_info_elem && elems->ht_cap_elem &&
|
||||
sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
|
||||
/* we both use HT */
|
||||
struct ieee80211_sta_ht_cap sta_ht_cap_new;
|
||||
enum nl80211_channel_type channel_type =
|
||||
ieee80211_ht_info_to_channel_type(
|
||||
elems->ht_info_elem);
|
||||
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
elems->ht_cap_elem,
|
||||
&sta_ht_cap_new);
|
||||
|
||||
/*
|
||||
* fall back to HT20 if we don't use or use
|
||||
* the other extension channel
|
||||
*/
|
||||
if ((channel_type == NL80211_CHAN_HT40MINUS ||
|
||||
channel_type == NL80211_CHAN_HT40PLUS) &&
|
||||
channel_type != sdata->u.ibss.channel_type)
|
||||
sta_ht_cap_new.cap &=
|
||||
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
|
||||
if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new,
|
||||
sizeof(sta_ht_cap_new))) {
|
||||
memcpy(&sta->sta.ht_cap, &sta_ht_cap_new,
|
||||
sizeof(sta_ht_cap_new));
|
||||
rates_updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (sta && rates_updated)
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@ -896,12 +954,18 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_ibss_params *params)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u32 changed = 0;
|
||||
|
||||
skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
|
||||
36 /* bitrates */ +
|
||||
34 /* SSID */ +
|
||||
3 /* DS params */ +
|
||||
4 /* IBSS params */ +
|
||||
sizeof(struct ieee80211_hdr_3addr) +
|
||||
12 /* struct ieee80211_mgmt.u.beacon */ +
|
||||
2 + IEEE80211_MAX_SSID_LEN /* max SSID */ +
|
||||
2 + 8 /* max Supported Rates */ +
|
||||
3 /* max DS params */ +
|
||||
4 /* IBSS params */ +
|
||||
2 + (IEEE80211_MAX_SUPP_RATES - 8) +
|
||||
2 + sizeof(struct ieee80211_ht_cap) +
|
||||
2 + sizeof(struct ieee80211_ht_info) +
|
||||
params->ie_len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
@ -922,13 +986,15 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
|
||||
|
||||
sdata->u.ibss.channel = params->channel;
|
||||
sdata->u.ibss.channel_type = params->channel_type;
|
||||
sdata->u.ibss.fixed_channel = params->channel_fixed;
|
||||
|
||||
/* fix ourselves to that channel now already */
|
||||
if (params->channel_fixed) {
|
||||
sdata->local->oper_channel = params->channel;
|
||||
WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
|
||||
NL80211_CHAN_NO_HT));
|
||||
if (!ieee80211_set_channel_type(sdata->local, sdata,
|
||||
params->channel_type))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params->ie) {
|
||||
@ -951,6 +1017,23 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
/*
|
||||
* 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is
|
||||
* reserved, but an HT STA shall protect HT transmissions as though
|
||||
* the HT Protection field were set to non-HT mixed mode.
|
||||
*
|
||||
* In an IBSS, the RIFS Mode field of the HT Operation element is
|
||||
* also reserved, but an HT STA shall operate as though this field
|
||||
* were set to 1.
|
||||
*/
|
||||
|
||||
sdata->vif.bss_conf.ht_operation_mode |=
|
||||
IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED
|
||||
| IEEE80211_HT_PARAM_RIFS_MODE;
|
||||
|
||||
changed |= BSS_CHANGED_HT;
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
|
||||
return 0;
|
||||
|
@ -474,6 +474,7 @@ struct ieee80211_if_ibss {
|
||||
u8 ssid_len, ie_len;
|
||||
u8 *ie;
|
||||
struct ieee80211_channel *channel;
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
unsigned long ibss_join_req;
|
||||
/* probe response/beacon for IBSS */
|
||||
|
@ -570,7 +570,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
WIPHY_FLAG_OFFCHAN_TX |
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||
|
||||
wiphy->features = NL80211_FEATURE_SK_TX_STATUS;
|
||||
wiphy->features = NL80211_FEATURE_SK_TX_STATUS |
|
||||
NL80211_FEATURE_HT_IBSS;
|
||||
|
||||
if (!ops->set_key)
|
||||
wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
|
||||
|
@ -2237,7 +2237,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
|
||||
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
sdata->vif.type != NL80211_IFTYPE_AP &&
|
||||
sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
||||
break;
|
||||
|
||||
/* verify action_code is present */
|
||||
@ -2796,10 +2797,17 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||
return 0;
|
||||
} else if (!ieee80211_bssid_match(bssid,
|
||||
sdata->vif.addr)) {
|
||||
/*
|
||||
* Accept public action frames even when the
|
||||
* BSSID doesn't match, this is used for P2P
|
||||
* and location updates. Note that mac80211
|
||||
* itself never looks at these frames.
|
||||
*/
|
||||
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
|
||||
!ieee80211_is_beacon(hdr->frame_control) &&
|
||||
!(ieee80211_is_action(hdr->frame_control) &&
|
||||
sdata->vif.p2p))
|
||||
ieee80211_is_public_action(hdr, skb->len))
|
||||
return 1;
|
||||
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
|
||||
!ieee80211_is_beacon(hdr->frame_control))
|
||||
return 0;
|
||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
}
|
||||
|
@ -1332,8 +1332,11 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
||||
if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
|
||||
CALL_TXH(ieee80211_tx_h_rate_ctrl);
|
||||
|
||||
if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION))
|
||||
if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
|
||||
__skb_queue_tail(&tx->skbs, tx->skb);
|
||||
tx->skb = NULL;
|
||||
goto txh_done;
|
||||
}
|
||||
|
||||
CALL_TXH(ieee80211_tx_h_michael_mic_add);
|
||||
CALL_TXH(ieee80211_tx_h_sequence);
|
||||
|
@ -1587,6 +1587,11 @@ u8 *ieee80211_ie_build_ht_info(u8 *pos,
|
||||
}
|
||||
if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
|
||||
ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
|
||||
|
||||
/*
|
||||
* Note: According to 802.11n-2009 9.13.3.1, HT Protection field and
|
||||
* RIFS Mode are reserved in IBSS mode, therefore keep them at 0
|
||||
*/
|
||||
ht_info->operation_mode = 0x0000;
|
||||
ht_info->stbc_param = 0x0000;
|
||||
|
||||
|
@ -121,15 +121,16 @@ config CFG80211_WEXT
|
||||
|
||||
config WIRELESS_EXT_SYSFS
|
||||
bool "Wireless extensions sysfs files"
|
||||
default y
|
||||
depends on WEXT_CORE && SYSFS
|
||||
help
|
||||
This option enables the deprecated wireless statistics
|
||||
files in /sys/class/net/*/wireless/. The same information
|
||||
is available via the ioctls as well.
|
||||
|
||||
Say Y if you have programs using it, like old versions of
|
||||
hal.
|
||||
Say N. If you know you have ancient tools requiring it,
|
||||
like very old versions of hal (prior to 0.5.12 release),
|
||||
say Y and update the tools as soon as possible as this
|
||||
option will be removed soon.
|
||||
|
||||
config LIB80211
|
||||
tristate "Common routines for IEEE802.11 drivers"
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "core.h"
|
||||
|
||||
@ -44,9 +45,9 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
|
||||
return chan;
|
||||
}
|
||||
|
||||
static bool can_beacon_sec_chan(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct ieee80211_channel *sec_chan;
|
||||
int diff;
|
||||
@ -75,6 +76,7 @@ static bool can_beacon_sec_chan(struct wiphy *wiphy,
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
|
||||
|
||||
int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, int freq,
|
||||
@ -109,8 +111,8 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
|
||||
switch (channel_type) {
|
||||
case NL80211_CHAN_HT40PLUS:
|
||||
case NL80211_CHAN_HT40MINUS:
|
||||
if (!can_beacon_sec_chan(&rdev->wiphy, chan,
|
||||
channel_type)) {
|
||||
if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan,
|
||||
channel_type)) {
|
||||
printk(KERN_DEBUG
|
||||
"cfg80211: Secondary channel not "
|
||||
"allowed to initiate communication\n");
|
||||
|
@ -4682,13 +4682,41 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
|
||||
ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
||||
}
|
||||
|
||||
ibss.channel = ieee80211_get_channel(wiphy,
|
||||
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
channel_type = nla_get_u32(
|
||||
info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
|
||||
if (channel_type != NL80211_CHAN_NO_HT &&
|
||||
channel_type != NL80211_CHAN_HT20 &&
|
||||
channel_type != NL80211_CHAN_HT40MINUS &&
|
||||
channel_type != NL80211_CHAN_HT40PLUS)
|
||||
return -EINVAL;
|
||||
|
||||
if (channel_type != NL80211_CHAN_NO_HT &&
|
||||
!(wiphy->features & NL80211_FEATURE_HT_IBSS))
|
||||
return -EINVAL;
|
||||
|
||||
ibss.channel_type = channel_type;
|
||||
} else {
|
||||
ibss.channel_type = NL80211_CHAN_NO_HT;
|
||||
}
|
||||
|
||||
ibss.channel = rdev_freq_to_chan(rdev,
|
||||
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
|
||||
ibss.channel_type);
|
||||
if (!ibss.channel ||
|
||||
ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
|
||||
ibss.channel->flags & IEEE80211_CHAN_DISABLED)
|
||||
return -EINVAL;
|
||||
|
||||
/* Both channels should be able to initiate communication */
|
||||
if ((ibss.channel_type == NL80211_CHAN_HT40PLUS ||
|
||||
ibss.channel_type == NL80211_CHAN_HT40MINUS) &&
|
||||
!cfg80211_can_beacon_sec_chan(&rdev->wiphy, ibss.channel,
|
||||
ibss.channel_type))
|
||||
return -EINVAL;
|
||||
|
||||
ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
|
||||
ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user