mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-09 11:00:52 +00:00
wireless-drivers-next patches for 4.13
The first pull request for 4.13. We have a new driver qtnfmac, but also rsi driver got a support for new firmware and supporting ath10k SDIO devices was started. Major changes: ath10k * add initial SDIO support (still work in progress) rsi * new loading for the new firmware version rtlwifi * final patches for the new btcoex support rt2x00 * add device ID for Epson WN7512BEP qtnfmac * new driver for Quantenna QSR10G chipsets -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJZPpCkAAoJEG4XJFUm622bUTMH/ipenw7p7otrhw9qtSBcqBRJ hS+1i2J+VXDXptFng0ziPWVv6mvhANvBszuOmiNMOgqjx2HrVknwlKUKViklHN3p E1PE3/A3bRpzBjMk4j8r/Z7VJK3rDa4WSi/AMJtqV9noNm5FfiOrCk7rXm2MLBns x1Wyr/7OX12hiB4SCoOuOZqS/TvHlNCW71BoyRruq01N2MA1iSonLCYJbovgi7Ds 9acAY90PF8jLC+o7wxYkwuRqWncNhnKOsVNhc/6DKH91zB+C5sw2NGfD3WMfot/Z 9uC5nBWNadoLGi636y+9evIRgNAFCczCZZSUeY7jMWiVn7XyFy8zoc4fv2ZSBto= =6md1 -----END PGP SIGNATURE----- Merge tag 'wireless-drivers-next-for-davem-2017-06-12' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next Kalle Valo says: ==================== wireless-drivers-next patches for 4.13 The first pull request for 4.13. We have a new driver qtnfmac, but also rsi driver got a support for new firmware and supporting ath10k SDIO devices was started. Major changes: ath10k * add initial SDIO support (still work in progress) rsi * new loading for the new firmware version rtlwifi * final patches for the new btcoex support rt2x00 * add device ID for Epson WN7512BEP qtnfmac * new driver for Quantenna QSR10G chipsets ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
63a2f310d0
@ -10634,6 +10634,14 @@ L: qemu-devel@nongnu.org
|
||||
S: Maintained
|
||||
F: drivers/firmware/qemu_fw_cfg.c
|
||||
|
||||
QUANTENNA QTNFMAC WIRELESS DRIVER
|
||||
M: Igor Mitsyanko <imitsyanko@quantenna.com>
|
||||
M: Avinash Patil <avinashp@quantenna.com>
|
||||
M: Sergey Matyukevich <smatyukevich@quantenna.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/quantenna
|
||||
|
||||
RADOS BLOCK DEVICE (RBD)
|
||||
M: Ilya Dryomov <idryomov@gmail.com>
|
||||
M: Sage Weil <sage@redhat.com>
|
||||
|
@ -45,6 +45,7 @@ source "drivers/net/wireless/rsi/Kconfig"
|
||||
source "drivers/net/wireless/st/Kconfig"
|
||||
source "drivers/net/wireless/ti/Kconfig"
|
||||
source "drivers/net/wireless/zydas/Kconfig"
|
||||
source "drivers/net/wireless/quantenna/Kconfig"
|
||||
|
||||
config PCMCIA_RAYCS
|
||||
tristate "Aviator/Raytheon 2.4GHz wireless support"
|
||||
|
@ -17,6 +17,7 @@ obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/
|
||||
obj-$(CONFIG_WLAN_VENDOR_ST) += st/
|
||||
obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
|
||||
obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
|
||||
obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/
|
||||
|
||||
# 16-bit wireless PCMCIA client drivers
|
||||
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
|
||||
|
@ -22,6 +22,13 @@ config ATH10K_AHB
|
||||
---help---
|
||||
This module adds support for AHB bus
|
||||
|
||||
config ATH10K_SDIO
|
||||
tristate "Atheros ath10k SDIO support (EXPERIMENTAL)"
|
||||
depends on ATH10K && MMC
|
||||
---help---
|
||||
This module adds experimental support for SDIO/MMC bus. Currently
|
||||
work in progress and will not fully work.
|
||||
|
||||
config ATH10K_DEBUG
|
||||
bool "Atheros ath10k debugging"
|
||||
depends on ATH10K
|
||||
|
@ -27,5 +27,8 @@ ath10k_pci-y += pci.o \
|
||||
|
||||
ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o
|
||||
|
||||
obj-$(CONFIG_ATH10K_SDIO) += ath10k_sdio.o
|
||||
ath10k_sdio-y += sdio.o
|
||||
|
||||
# for tracing framework to find trace.h
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
@ -97,6 +97,77 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TARGET_VERSION_SENTINAL 0xffffffffu
|
||||
|
||||
int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
|
||||
u32 resplen, ver_len;
|
||||
__le32 tmp;
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info SDIO\n");
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
|
||||
|
||||
/* Step 1: Read 4 bytes of the target info and check if it is
|
||||
* the special sentinal version word or the first word in the
|
||||
* version response.
|
||||
*/
|
||||
resplen = sizeof(u32);
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &tmp, &resplen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to read from device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Some SDIO boards have a special sentinal byte before the real
|
||||
* version response.
|
||||
*/
|
||||
if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) {
|
||||
/* Step 1b: Read the version length */
|
||||
resplen = sizeof(u32);
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, &tmp,
|
||||
&resplen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to read from device\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ver_len = __le32_to_cpu(tmp);
|
||||
|
||||
/* Step 2: Check the target info length */
|
||||
if (ver_len != sizeof(resp.get_target_info)) {
|
||||
ath10k_warn(ar, "Unexpected target info len: %u. Expected: %zu\n",
|
||||
ver_len, sizeof(resp.get_target_info));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Step 3: Read the rest of the version response */
|
||||
resplen = sizeof(resp.get_target_info) - sizeof(u32);
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0,
|
||||
&resp.get_target_info.version,
|
||||
&resplen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to read from device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
target_info->version = __le32_to_cpu(resp.get_target_info.version);
|
||||
target_info->type = __le32_to_cpu(resp.get_target_info.type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_read_memory(struct ath10k *ar,
|
||||
u32 address, void *buffer, u32 length)
|
||||
{
|
||||
|
@ -198,6 +198,8 @@ void ath10k_bmi_start(struct ath10k *ar);
|
||||
int ath10k_bmi_done(struct ath10k *ar);
|
||||
int ath10k_bmi_get_target_info(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info);
|
||||
int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info);
|
||||
int ath10k_bmi_read_memory(struct ath10k *ar, u32 address,
|
||||
void *buffer, u32 length);
|
||||
int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
|
||||
|
@ -389,6 +389,21 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
|
||||
complete(&ar->target_suspend);
|
||||
}
|
||||
|
||||
static void ath10k_init_sdio(struct ath10k *ar)
|
||||
{
|
||||
u32 param = 0;
|
||||
|
||||
ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256);
|
||||
ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99);
|
||||
ath10k_bmi_read32(ar, hi_acs_flags, ¶m);
|
||||
|
||||
param |= (HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET |
|
||||
HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET |
|
||||
HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE);
|
||||
|
||||
ath10k_bmi_write32(ar, hi_acs_flags, param);
|
||||
}
|
||||
|
||||
static int ath10k_init_configure_target(struct ath10k *ar)
|
||||
{
|
||||
u32 param_host;
|
||||
@ -1395,7 +1410,18 @@ err:
|
||||
static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name,
|
||||
size_t fw_name_len, int fw_api)
|
||||
{
|
||||
scnprintf(fw_name, fw_name_len, "%s-%d.bin", ATH10K_FW_FILE_BASE, fw_api);
|
||||
switch (ar->hif.bus) {
|
||||
case ATH10K_BUS_SDIO:
|
||||
scnprintf(fw_name, fw_name_len, "%s-%s-%d.bin",
|
||||
ATH10K_FW_FILE_BASE, ath10k_bus_str(ar->hif.bus),
|
||||
fw_api);
|
||||
break;
|
||||
case ATH10K_BUS_PCI:
|
||||
case ATH10K_BUS_AHB:
|
||||
scnprintf(fw_name, fw_name_len, "%s-%d.bin",
|
||||
ATH10K_FW_FILE_BASE, fw_api);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
|
||||
@ -1953,6 +1979,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
|
||||
if (status)
|
||||
goto err;
|
||||
|
||||
if (ar->hif.bus == ATH10K_BUS_SDIO)
|
||||
ath10k_init_sdio(ar);
|
||||
|
||||
ar->htc.htc_ops.target_send_suspend_complete =
|
||||
ath10k_send_suspend_complete;
|
||||
|
||||
@ -2200,7 +2229,10 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
|
||||
}
|
||||
|
||||
memset(&target_info, 0, sizeof(target_info));
|
||||
ret = ath10k_bmi_get_target_info(ar, &target_info);
|
||||
if (ar->hif.bus == ATH10K_BUS_SDIO)
|
||||
ret = ath10k_bmi_get_target_info_sdio(ar, &target_info);
|
||||
else
|
||||
ret = ath10k_bmi_get_target_info(ar, &target_info);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "could not get target info (%d)\n", ret);
|
||||
goto err_power_down;
|
||||
|
@ -91,6 +91,7 @@ struct ath10k;
|
||||
enum ath10k_bus {
|
||||
ATH10K_BUS_PCI,
|
||||
ATH10K_BUS_AHB,
|
||||
ATH10K_BUS_SDIO,
|
||||
};
|
||||
|
||||
static inline const char *ath10k_bus_str(enum ath10k_bus bus)
|
||||
@ -100,6 +101,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
|
||||
return "pci";
|
||||
case ATH10K_BUS_AHB:
|
||||
return "ahb";
|
||||
case ATH10K_BUS_SDIO:
|
||||
return "sdio";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
|
@ -625,17 +625,21 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char buf[32];
|
||||
char buf[32] = {0};
|
||||
ssize_t rc;
|
||||
int ret;
|
||||
|
||||
simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
|
||||
/* filter partial writes and invalid commands */
|
||||
if (*ppos != 0 || count >= sizeof(buf) || count == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* make sure that buf is null terminated */
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* drop the possible '\n' from the end */
|
||||
if (buf[count - 1] == '\n')
|
||||
buf[count - 1] = 0;
|
||||
if (buf[*ppos - 1] == '\n')
|
||||
buf[*ppos - 1] = '\0';
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
|
@ -38,6 +38,8 @@ enum ath10k_debug_mask {
|
||||
ATH10K_DBG_WMI_PRINT = 0x00002000,
|
||||
ATH10K_DBG_PCI_PS = 0x00004000,
|
||||
ATH10K_DBG_AHB = 0x00008000,
|
||||
ATH10K_DBG_SDIO = 0x00010000,
|
||||
ATH10K_DBG_SDIO_DUMP = 0x00020000,
|
||||
ATH10K_DBG_ANY = 0xffffffff,
|
||||
};
|
||||
|
||||
|
@ -57,8 +57,8 @@ static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc,
|
||||
skb_pull(skb, sizeof(struct ath10k_htc_hdr));
|
||||
}
|
||||
|
||||
static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
|
||||
struct sk_buff *skb)
|
||||
void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ath10k *ar = ep->htc->ar;
|
||||
|
||||
@ -75,6 +75,7 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
|
||||
|
||||
ep->ep_ops.ep_tx_complete(ep->htc->ar, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_htc_notify_tx_completion);
|
||||
|
||||
static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
|
||||
struct sk_buff *skb)
|
||||
@ -230,12 +231,79 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
}
|
||||
|
||||
static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
|
||||
u8 *buffer,
|
||||
int length,
|
||||
enum ath10k_htc_ep_id src_eid)
|
||||
static int
|
||||
ath10k_htc_process_lookahead(struct ath10k_htc *htc,
|
||||
const struct ath10k_htc_lookahead_report *report,
|
||||
int len,
|
||||
enum ath10k_htc_ep_id eid,
|
||||
void *next_lookaheads,
|
||||
int *next_lookaheads_len)
|
||||
{
|
||||
struct ath10k *ar = htc->ar;
|
||||
|
||||
/* Invalid lookahead flags are actually transmitted by
|
||||
* the target in the HTC control message.
|
||||
* Since this will happen at every boot we silently ignore
|
||||
* the lookahead in this case
|
||||
*/
|
||||
if (report->pre_valid != ((~report->post_valid) & 0xFF))
|
||||
return 0;
|
||||
|
||||
if (next_lookaheads && next_lookaheads_len) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"htc rx lookahead found pre_valid 0x%x post_valid 0x%x\n",
|
||||
report->pre_valid, report->post_valid);
|
||||
|
||||
/* look ahead bytes are valid, copy them over */
|
||||
memcpy((u8 *)next_lookaheads, report->lookahead, 4);
|
||||
|
||||
*next_lookaheads_len = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath10k_htc_process_lookahead_bundle(struct ath10k_htc *htc,
|
||||
const struct ath10k_htc_lookahead_bundle *report,
|
||||
int len,
|
||||
enum ath10k_htc_ep_id eid,
|
||||
void *next_lookaheads,
|
||||
int *next_lookaheads_len)
|
||||
{
|
||||
struct ath10k *ar = htc->ar;
|
||||
int bundle_cnt = len / sizeof(*report);
|
||||
|
||||
if (!bundle_cnt || (bundle_cnt > HTC_HOST_MAX_MSG_PER_BUNDLE)) {
|
||||
ath10k_warn(ar, "Invalid lookahead bundle count: %d\n",
|
||||
bundle_cnt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (next_lookaheads && next_lookaheads_len) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bundle_cnt; i++) {
|
||||
memcpy(((u8 *)next_lookaheads) + 4 * i,
|
||||
report->lookahead, 4);
|
||||
report++;
|
||||
}
|
||||
|
||||
*next_lookaheads_len = bundle_cnt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htc_process_trailer(struct ath10k_htc *htc,
|
||||
u8 *buffer,
|
||||
int length,
|
||||
enum ath10k_htc_ep_id src_eid,
|
||||
void *next_lookaheads,
|
||||
int *next_lookaheads_len)
|
||||
{
|
||||
struct ath10k_htc_lookahead_bundle *bundle;
|
||||
struct ath10k *ar = htc->ar;
|
||||
int status = 0;
|
||||
struct ath10k_htc_record *record;
|
||||
u8 *orig_buffer;
|
||||
@ -274,6 +342,29 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
|
||||
record->hdr.len,
|
||||
src_eid);
|
||||
break;
|
||||
case ATH10K_HTC_RECORD_LOOKAHEAD:
|
||||
len = sizeof(struct ath10k_htc_lookahead_report);
|
||||
if (record->hdr.len < len) {
|
||||
ath10k_warn(ar, "Lookahead report too long\n");
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
status = ath10k_htc_process_lookahead(htc,
|
||||
record->lookahead_report,
|
||||
record->hdr.len,
|
||||
src_eid,
|
||||
next_lookaheads,
|
||||
next_lookaheads_len);
|
||||
break;
|
||||
case ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE:
|
||||
bundle = record->lookahead_bundle;
|
||||
status = ath10k_htc_process_lookahead_bundle(htc,
|
||||
bundle,
|
||||
record->hdr.len,
|
||||
src_eid,
|
||||
next_lookaheads,
|
||||
next_lookaheads_len);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "Unhandled record: id:%d length:%d\n",
|
||||
record->hdr.id, record->hdr.len);
|
||||
@ -294,6 +385,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_htc_process_trailer);
|
||||
|
||||
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
@ -360,7 +452,8 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
trailer += payload_len;
|
||||
trailer -= trailer_len;
|
||||
status = ath10k_htc_process_trailer(htc, trailer,
|
||||
trailer_len, hdr->eid);
|
||||
trailer_len, hdr->eid,
|
||||
NULL, NULL);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
@ -371,42 +464,6 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||
/* zero length packet with trailer data, just drop these */
|
||||
goto out;
|
||||
|
||||
if (eid == ATH10K_HTC_EP_0) {
|
||||
struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data;
|
||||
|
||||
switch (__le16_to_cpu(msg->hdr.message_id)) {
|
||||
case ATH10K_HTC_MSG_READY_ID:
|
||||
case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID:
|
||||
/* handle HTC control message */
|
||||
if (completion_done(&htc->ctl_resp)) {
|
||||
/*
|
||||
* this is a fatal error, target should not be
|
||||
* sending unsolicited messages on the ep 0
|
||||
*/
|
||||
ath10k_warn(ar, "HTC rx ctrl still processing\n");
|
||||
complete(&htc->ctl_resp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
htc->control_resp_len =
|
||||
min_t(int, skb->len,
|
||||
ATH10K_HTC_MAX_CTRL_MSG_LEN);
|
||||
|
||||
memcpy(htc->control_resp_buffer, skb->data,
|
||||
htc->control_resp_len);
|
||||
|
||||
complete(&htc->ctl_resp);
|
||||
break;
|
||||
case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE:
|
||||
htc->htc_ops.target_send_suspend_complete(ar);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n");
|
||||
break;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %pK\n",
|
||||
eid, skb);
|
||||
ep->ep_ops.ep_rx_complete(ar, skb);
|
||||
@ -421,10 +478,40 @@ EXPORT_SYMBOL(ath10k_htc_rx_completion_handler);
|
||||
static void ath10k_htc_control_rx_complete(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
/* This is unexpected. FW is not supposed to send regular rx on this
|
||||
* endpoint.
|
||||
*/
|
||||
ath10k_warn(ar, "unexpected htc rx\n");
|
||||
struct ath10k_htc *htc = &ar->htc;
|
||||
struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data;
|
||||
|
||||
switch (__le16_to_cpu(msg->hdr.message_id)) {
|
||||
case ATH10K_HTC_MSG_READY_ID:
|
||||
case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID:
|
||||
/* handle HTC control message */
|
||||
if (completion_done(&htc->ctl_resp)) {
|
||||
/* this is a fatal error, target should not be
|
||||
* sending unsolicited messages on the ep 0
|
||||
*/
|
||||
ath10k_warn(ar, "HTC rx ctrl still processing\n");
|
||||
complete(&htc->ctl_resp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
htc->control_resp_len =
|
||||
min_t(int, skb->len,
|
||||
ATH10K_HTC_MAX_CTRL_MSG_LEN);
|
||||
|
||||
memcpy(htc->control_resp_buffer, skb->data,
|
||||
htc->control_resp_len);
|
||||
|
||||
complete(&htc->ctl_resp);
|
||||
break;
|
||||
case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE:
|
||||
htc->htc_ops.target_send_suspend_complete(ar);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n");
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
@ -497,12 +584,8 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
|
||||
struct ath10k *ar = htc->ar;
|
||||
int i, status = 0;
|
||||
unsigned long time_left;
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
struct ath10k_htc_svc_conn_resp conn_resp;
|
||||
struct ath10k_htc_msg *msg;
|
||||
u16 message_id;
|
||||
u16 credit_count;
|
||||
u16 credit_size;
|
||||
|
||||
time_left = wait_for_completion_timeout(&htc->ctl_resp,
|
||||
ATH10K_HTC_WAIT_TIMEOUT_HZ);
|
||||
@ -539,16 +622,14 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
|
||||
|
||||
msg = (struct ath10k_htc_msg *)htc->control_resp_buffer;
|
||||
message_id = __le16_to_cpu(msg->hdr.message_id);
|
||||
credit_count = __le16_to_cpu(msg->ready.credit_count);
|
||||
credit_size = __le16_to_cpu(msg->ready.credit_size);
|
||||
|
||||
if (message_id != ATH10K_HTC_MSG_READY_ID) {
|
||||
ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id);
|
||||
return -ECOMM;
|
||||
}
|
||||
|
||||
htc->total_transmit_credits = credit_count;
|
||||
htc->target_credit_size = credit_size;
|
||||
htc->total_transmit_credits = __le16_to_cpu(msg->ready.credit_count);
|
||||
htc->target_credit_size = __le16_to_cpu(msg->ready.credit_size);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"Target ready! transmit resources: %d size:%d\n",
|
||||
@ -561,20 +642,17 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
|
||||
return -ECOMM;
|
||||
}
|
||||
|
||||
/* setup our pseudo HTC control endpoint connection */
|
||||
memset(&conn_req, 0, sizeof(conn_req));
|
||||
memset(&conn_resp, 0, sizeof(conn_resp));
|
||||
conn_req.ep_ops.ep_tx_complete = ath10k_htc_control_tx_complete;
|
||||
conn_req.ep_ops.ep_rx_complete = ath10k_htc_control_rx_complete;
|
||||
conn_req.max_send_queue_depth = ATH10K_NUM_CONTROL_TX_BUFFERS;
|
||||
conn_req.service_id = ATH10K_HTC_SVC_ID_RSVD_CTRL;
|
||||
|
||||
/* connect fake service */
|
||||
status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);
|
||||
if (status) {
|
||||
ath10k_err(ar, "could not connect to htc service (%d)\n",
|
||||
status);
|
||||
return status;
|
||||
/* The only way to determine if the ready message is an extended
|
||||
* message is from the size.
|
||||
*/
|
||||
if (htc->control_resp_len >=
|
||||
sizeof(msg->hdr) + sizeof(msg->ready_ext)) {
|
||||
htc->max_msgs_per_htc_bundle =
|
||||
min_t(u8, msg->ready_ext.max_msgs_per_htc_bundle,
|
||||
HTC_HOST_MAX_MSG_PER_BUNDLE);
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC,
|
||||
"Extended ready message. RX bundle size: %d\n",
|
||||
htc->max_msgs_per_htc_bundle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -772,6 +850,13 @@ int ath10k_htc_start(struct ath10k_htc *htc)
|
||||
msg->hdr.message_id =
|
||||
__cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID);
|
||||
|
||||
if (ar->hif.bus == ATH10K_BUS_SDIO) {
|
||||
/* Extra setup params used by SDIO */
|
||||
msg->setup_complete_ext.flags =
|
||||
__cpu_to_le32(ATH10K_HTC_SETUP_COMPLETE_FLAGS_RX_BNDL_EN);
|
||||
msg->setup_complete_ext.max_msgs_per_bundled_recv =
|
||||
htc->max_msgs_per_htc_bundle;
|
||||
}
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
|
||||
|
||||
status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
|
||||
@ -786,8 +871,10 @@ int ath10k_htc_start(struct ath10k_htc *htc)
|
||||
/* registered target arrival callback from the HIF layer */
|
||||
int ath10k_htc_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_htc_ep *ep = NULL;
|
||||
int status;
|
||||
struct ath10k_htc *htc = &ar->htc;
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
struct ath10k_htc_svc_conn_resp conn_resp;
|
||||
|
||||
spin_lock_init(&htc->tx_lock);
|
||||
|
||||
@ -795,10 +882,21 @@ int ath10k_htc_init(struct ath10k *ar)
|
||||
|
||||
htc->ar = ar;
|
||||
|
||||
/* Get HIF default pipe for HTC message exchange */
|
||||
ep = &htc->endpoint[ATH10K_HTC_EP_0];
|
||||
/* setup our pseudo HTC control endpoint connection */
|
||||
memset(&conn_req, 0, sizeof(conn_req));
|
||||
memset(&conn_resp, 0, sizeof(conn_resp));
|
||||
conn_req.ep_ops.ep_tx_complete = ath10k_htc_control_tx_complete;
|
||||
conn_req.ep_ops.ep_rx_complete = ath10k_htc_control_rx_complete;
|
||||
conn_req.max_send_queue_depth = ATH10K_NUM_CONTROL_TX_BUFFERS;
|
||||
conn_req.service_id = ATH10K_HTC_SVC_ID_RSVD_CTRL;
|
||||
|
||||
ath10k_hif_get_default_pipe(ar, &ep->ul_pipe_id, &ep->dl_pipe_id);
|
||||
/* connect fake service */
|
||||
status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);
|
||||
if (status) {
|
||||
ath10k_err(ar, "could not connect to htc service (%d)\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
init_completion(&htc->ctl_resp);
|
||||
|
||||
|
@ -50,6 +50,8 @@ struct ath10k;
|
||||
* 4-byte aligned.
|
||||
*/
|
||||
|
||||
#define HTC_HOST_MAX_MSG_PER_BUNDLE 8
|
||||
|
||||
enum ath10k_htc_tx_flags {
|
||||
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
|
||||
ATH10K_HTC_FLAG_SEND_BUNDLE = 0x02
|
||||
@ -110,6 +112,10 @@ enum ath10k_htc_conn_svc_status {
|
||||
ATH10K_HTC_CONN_SVC_STATUS_NO_MORE_EP = 4
|
||||
};
|
||||
|
||||
enum ath10k_htc_setup_complete_flags {
|
||||
ATH10K_HTC_SETUP_COMPLETE_FLAGS_RX_BNDL_EN = 1
|
||||
};
|
||||
|
||||
struct ath10k_ath10k_htc_msg_hdr {
|
||||
__le16 message_id; /* @enum htc_message_id */
|
||||
} __packed;
|
||||
@ -174,8 +180,10 @@ struct ath10k_htc_msg {
|
||||
} __packed __aligned(4);
|
||||
|
||||
enum ath10k_ath10k_htc_record_id {
|
||||
ATH10K_HTC_RECORD_NULL = 0,
|
||||
ATH10K_HTC_RECORD_CREDITS = 1
|
||||
ATH10K_HTC_RECORD_NULL = 0,
|
||||
ATH10K_HTC_RECORD_CREDITS = 1,
|
||||
ATH10K_HTC_RECORD_LOOKAHEAD = 2,
|
||||
ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE = 3,
|
||||
};
|
||||
|
||||
struct ath10k_ath10k_htc_record_hdr {
|
||||
@ -192,10 +200,28 @@ struct ath10k_htc_credit_report {
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_lookahead_report {
|
||||
u8 pre_valid;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
u8 pad2;
|
||||
u8 lookahead[4];
|
||||
u8 post_valid;
|
||||
u8 pad3;
|
||||
u8 pad4;
|
||||
u8 pad5;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_lookahead_bundle {
|
||||
u8 lookahead[4];
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_record {
|
||||
struct ath10k_ath10k_htc_record_hdr hdr;
|
||||
union {
|
||||
struct ath10k_htc_credit_report credit_report[0];
|
||||
struct ath10k_htc_lookahead_report lookahead_report[0];
|
||||
struct ath10k_htc_lookahead_bundle lookahead_bundle[0];
|
||||
u8 pauload[0];
|
||||
};
|
||||
} __packed __aligned(4);
|
||||
@ -338,6 +364,7 @@ struct ath10k_htc {
|
||||
|
||||
int total_transmit_credits;
|
||||
int target_credit_size;
|
||||
u8 max_msgs_per_htc_bundle;
|
||||
};
|
||||
|
||||
int ath10k_htc_init(struct ath10k *ar);
|
||||
@ -351,5 +378,13 @@ int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
|
||||
struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
|
||||
void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
|
||||
struct sk_buff *skb);
|
||||
int ath10k_htc_process_trailer(struct ath10k_htc *htc,
|
||||
u8 *buffer,
|
||||
int length,
|
||||
enum ath10k_htc_ep_id src_eid,
|
||||
void *next_lookaheads,
|
||||
int *next_lookaheads_len);
|
||||
|
||||
#endif
|
||||
|
@ -863,6 +863,59 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
|
||||
#define QCA9887_EEPROM_ADDR_LO_MASK 0x00ff0000
|
||||
#define QCA9887_EEPROM_ADDR_LO_LSB 16
|
||||
|
||||
#define MBOX_RESET_CONTROL_ADDRESS 0x00000000
|
||||
#define MBOX_HOST_INT_STATUS_ADDRESS 0x00000800
|
||||
#define MBOX_HOST_INT_STATUS_ERROR_LSB 7
|
||||
#define MBOX_HOST_INT_STATUS_ERROR_MASK 0x00000080
|
||||
#define MBOX_HOST_INT_STATUS_CPU_LSB 6
|
||||
#define MBOX_HOST_INT_STATUS_CPU_MASK 0x00000040
|
||||
#define MBOX_HOST_INT_STATUS_COUNTER_LSB 4
|
||||
#define MBOX_HOST_INT_STATUS_COUNTER_MASK 0x00000010
|
||||
#define MBOX_CPU_INT_STATUS_ADDRESS 0x00000801
|
||||
#define MBOX_ERROR_INT_STATUS_ADDRESS 0x00000802
|
||||
#define MBOX_ERROR_INT_STATUS_WAKEUP_LSB 2
|
||||
#define MBOX_ERROR_INT_STATUS_WAKEUP_MASK 0x00000004
|
||||
#define MBOX_ERROR_INT_STATUS_RX_UNDERFLOW_LSB 1
|
||||
#define MBOX_ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00000002
|
||||
#define MBOX_ERROR_INT_STATUS_TX_OVERFLOW_LSB 0
|
||||
#define MBOX_ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00000001
|
||||
#define MBOX_COUNTER_INT_STATUS_ADDRESS 0x00000803
|
||||
#define MBOX_COUNTER_INT_STATUS_COUNTER_LSB 0
|
||||
#define MBOX_COUNTER_INT_STATUS_COUNTER_MASK 0x000000ff
|
||||
#define MBOX_RX_LOOKAHEAD_VALID_ADDRESS 0x00000805
|
||||
#define MBOX_INT_STATUS_ENABLE_ADDRESS 0x00000828
|
||||
#define MBOX_INT_STATUS_ENABLE_ERROR_LSB 7
|
||||
#define MBOX_INT_STATUS_ENABLE_ERROR_MASK 0x00000080
|
||||
#define MBOX_INT_STATUS_ENABLE_CPU_LSB 6
|
||||
#define MBOX_INT_STATUS_ENABLE_CPU_MASK 0x00000040
|
||||
#define MBOX_INT_STATUS_ENABLE_INT_LSB 5
|
||||
#define MBOX_INT_STATUS_ENABLE_INT_MASK 0x00000020
|
||||
#define MBOX_INT_STATUS_ENABLE_COUNTER_LSB 4
|
||||
#define MBOX_INT_STATUS_ENABLE_COUNTER_MASK 0x00000010
|
||||
#define MBOX_INT_STATUS_ENABLE_MBOX_DATA_LSB 0
|
||||
#define MBOX_INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f
|
||||
#define MBOX_CPU_INT_STATUS_ENABLE_ADDRESS 0x00000819
|
||||
#define MBOX_CPU_INT_STATUS_ENABLE_BIT_LSB 0
|
||||
#define MBOX_CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff
|
||||
#define MBOX_ERROR_STATUS_ENABLE_ADDRESS 0x0000081a
|
||||
#define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1
|
||||
#define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002
|
||||
#define MBOX_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 0
|
||||
#define MBOX_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00000001
|
||||
#define MBOX_COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000081b
|
||||
#define MBOX_COUNTER_INT_STATUS_ENABLE_BIT_LSB 0
|
||||
#define MBOX_COUNTER_INT_STATUS_ENABLE_BIT_MASK 0x000000ff
|
||||
#define MBOX_COUNT_ADDRESS 0x00000820
|
||||
#define MBOX_COUNT_DEC_ADDRESS 0x00000840
|
||||
#define MBOX_WINDOW_DATA_ADDRESS 0x00000874
|
||||
#define MBOX_WINDOW_WRITE_ADDR_ADDRESS 0x00000878
|
||||
#define MBOX_WINDOW_READ_ADDR_ADDRESS 0x0000087c
|
||||
#define MBOX_CPU_DBG_SEL_ADDRESS 0x00000883
|
||||
#define MBOX_CPU_DBG_ADDRESS 0x00000884
|
||||
#define MBOX_RTC_BASE_ADDRESS 0x00000000
|
||||
#define MBOX_GPIO_BASE_ADDRESS 0x00005000
|
||||
#define MBOX_MBOX_BASE_ADDRESS 0x00008000
|
||||
|
||||
#define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB)
|
||||
|
||||
/* Register definitions for first generation ath10k cards. These cards include
|
||||
|
2113
drivers/net/wireless/ath/ath10k/sdio.c
Normal file
2113
drivers/net/wireless/ath/ath10k/sdio.c
Normal file
File diff suppressed because it is too large
Load Diff
229
drivers/net/wireless/ath/ath10k/sdio.h
Normal file
229
drivers/net/wireless/ath/ath10k/sdio.h
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _SDIO_H_
|
||||
#define _SDIO_H_
|
||||
|
||||
#define ATH10K_HIF_MBOX_BLOCK_SIZE 256
|
||||
|
||||
#define QCA_MANUFACTURER_ID_BASE GENMASK(11, 8)
|
||||
#define QCA_MANUFACTURER_ID_AR6005_BASE 0x5
|
||||
#define QCA_MANUFACTURER_ID_QCA9377_BASE 0x7
|
||||
#define QCA_SDIO_ID_AR6005_BASE 0x500
|
||||
#define QCA_SDIO_ID_QCA9377_BASE 0x700
|
||||
#define QCA_MANUFACTURER_ID_REV_MASK 0x00FF
|
||||
#define QCA_MANUFACTURER_CODE 0x271 /* Qualcomm/Atheros */
|
||||
|
||||
#define ATH10K_SDIO_MAX_BUFFER_SIZE 4096 /*Unsure of this constant*/
|
||||
|
||||
/* Mailbox address in SDIO address space */
|
||||
#define ATH10K_HIF_MBOX_BASE_ADDR 0x1000
|
||||
#define ATH10K_HIF_MBOX_WIDTH 0x800
|
||||
|
||||
#define ATH10K_HIF_MBOX_TOT_WIDTH \
|
||||
(ATH10K_HIF_MBOX_NUM_MAX * ATH10K_HIF_MBOX_WIDTH)
|
||||
|
||||
#define ATH10K_HIF_MBOX0_EXT_BASE_ADDR 0x5000
|
||||
#define ATH10K_HIF_MBOX0_EXT_WIDTH (36 * 1024)
|
||||
#define ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0 (56 * 1024)
|
||||
#define ATH10K_HIF_MBOX1_EXT_WIDTH (36 * 1024)
|
||||
#define ATH10K_HIF_MBOX_DUMMY_SPACE_SIZE (2 * 1024)
|
||||
|
||||
#define ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH \
|
||||
(ATH10K_SDIO_MAX_BUFFER_SIZE - sizeof(struct ath10k_htc_hdr))
|
||||
|
||||
#define ATH10K_HIF_MBOX_NUM_MAX 4
|
||||
#define ATH10K_SDIO_BUS_REQUEST_MAX_NUM 64
|
||||
|
||||
#define ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ (100 * HZ)
|
||||
|
||||
/* HTC runs over mailbox 0 */
|
||||
#define ATH10K_HTC_MAILBOX 0
|
||||
#define ATH10K_HTC_MAILBOX_MASK BIT(ATH10K_HTC_MAILBOX)
|
||||
|
||||
/* GMBOX addresses */
|
||||
#define ATH10K_HIF_GMBOX_BASE_ADDR 0x7000
|
||||
#define ATH10K_HIF_GMBOX_WIDTH 0x4000
|
||||
|
||||
/* Modified versions of the sdio.h macros.
|
||||
* The macros in sdio.h can't be used easily with the FIELD_{PREP|GET}
|
||||
* macros in bitfield.h, so we define our own macros here.
|
||||
*/
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_MASK \
|
||||
(SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT)
|
||||
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_TYPE_B 0
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_TYPE_A 1
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_TYPE_C 2
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_TYPE_D 3
|
||||
|
||||
/* SDIO CCCR register definitions */
|
||||
#define CCCR_SDIO_IRQ_MODE_REG 0xF0
|
||||
#define CCCR_SDIO_IRQ_MODE_REG_SDIO3 0x16
|
||||
|
||||
#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR 0xF2
|
||||
|
||||
#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A 0x02
|
||||
#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C 0x04
|
||||
#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D 0x08
|
||||
|
||||
#define CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS 0xF0
|
||||
#define CCCR_SDIO_ASYNC_INT_DELAY_MASK 0xC0
|
||||
|
||||
/* mode to enable special 4-bit interrupt assertion without clock */
|
||||
#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ BIT(0)
|
||||
#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_SDIO3 BIT(1)
|
||||
|
||||
#define ATH10K_SDIO_TARGET_DEBUG_INTR_MASK 0x01
|
||||
|
||||
/* The theoretical maximum number of RX messages that can be fetched
|
||||
* from the mbox interrupt handler in one loop is derived in the following
|
||||
* way:
|
||||
*
|
||||
* Let's assume that each packet in a bundle of the maximum bundle size
|
||||
* (HTC_HOST_MAX_MSG_PER_BUNDLE) has the HTC header bundle count set
|
||||
* to the maximum value (HTC_HOST_MAX_MSG_PER_BUNDLE).
|
||||
*
|
||||
* in this case the driver must allocate
|
||||
* (HTC_HOST_MAX_MSG_PER_BUNDLE * HTC_HOST_MAX_MSG_PER_BUNDLE) skb's.
|
||||
*/
|
||||
#define ATH10K_SDIO_MAX_RX_MSGS \
|
||||
(HTC_HOST_MAX_MSG_PER_BUNDLE * HTC_HOST_MAX_MSG_PER_BUNDLE)
|
||||
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868u
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000
|
||||
|
||||
struct ath10k_sdio_bus_request {
|
||||
struct list_head list;
|
||||
|
||||
/* sdio address */
|
||||
u32 address;
|
||||
|
||||
struct sk_buff *skb;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
int status;
|
||||
/* Specifies if the current request is an HTC message.
|
||||
* If not, the eid is not applicable an the TX completion handler
|
||||
* associated with the endpoint will not be invoked.
|
||||
*/
|
||||
bool htc_msg;
|
||||
/* Completion that (if set) will be invoked for non HTC requests
|
||||
* (htc_msg == false) when the request has been processed.
|
||||
*/
|
||||
struct completion *comp;
|
||||
};
|
||||
|
||||
struct ath10k_sdio_rx_data {
|
||||
struct sk_buff *skb;
|
||||
size_t alloc_len;
|
||||
size_t act_len;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
bool part_of_bundle;
|
||||
bool last_in_bundle;
|
||||
bool trailer_only;
|
||||
int status;
|
||||
};
|
||||
|
||||
struct ath10k_sdio_irq_proc_regs {
|
||||
u8 host_int_status;
|
||||
u8 cpu_int_status;
|
||||
u8 error_int_status;
|
||||
u8 counter_int_status;
|
||||
u8 mbox_frame;
|
||||
u8 rx_lookahead_valid;
|
||||
u8 host_int_status2;
|
||||
u8 gmbox_rx_avail;
|
||||
__le32 rx_lookahead[2];
|
||||
__le32 rx_gmbox_lookahead_alias[2];
|
||||
};
|
||||
|
||||
struct ath10k_sdio_irq_enable_regs {
|
||||
u8 int_status_en;
|
||||
u8 cpu_int_status_en;
|
||||
u8 err_int_status_en;
|
||||
u8 cntr_int_status_en;
|
||||
};
|
||||
|
||||
struct ath10k_sdio_irq_data {
|
||||
/* protects irq_proc_reg and irq_en_reg below.
|
||||
* We use a mutex here and not a spinlock since we will have the
|
||||
* mutex locked while calling the sdio_memcpy_ functions.
|
||||
* These function require non atomic context, and hence, spinlocks
|
||||
* can be held while calling these functions.
|
||||
*/
|
||||
struct mutex mtx;
|
||||
struct ath10k_sdio_irq_proc_regs *irq_proc_reg;
|
||||
struct ath10k_sdio_irq_enable_regs *irq_en_reg;
|
||||
};
|
||||
|
||||
struct ath10k_mbox_ext_info {
|
||||
u32 htc_ext_addr;
|
||||
u32 htc_ext_sz;
|
||||
};
|
||||
|
||||
struct ath10k_mbox_info {
|
||||
u32 htc_addr;
|
||||
struct ath10k_mbox_ext_info ext_info[2];
|
||||
u32 block_size;
|
||||
u32 block_mask;
|
||||
u32 gmbox_addr;
|
||||
u32 gmbox_sz;
|
||||
};
|
||||
|
||||
struct ath10k_sdio {
|
||||
struct sdio_func *func;
|
||||
|
||||
struct ath10k_mbox_info mbox_info;
|
||||
bool swap_mbox;
|
||||
u32 mbox_addr[ATH10K_HTC_EP_COUNT];
|
||||
u32 mbox_size[ATH10K_HTC_EP_COUNT];
|
||||
|
||||
/* available bus requests */
|
||||
struct ath10k_sdio_bus_request bus_req[ATH10K_SDIO_BUS_REQUEST_MAX_NUM];
|
||||
/* free list of bus requests */
|
||||
struct list_head bus_req_freeq;
|
||||
/* protects access to bus_req_freeq */
|
||||
spinlock_t lock;
|
||||
|
||||
struct ath10k_sdio_rx_data rx_pkts[ATH10K_SDIO_MAX_RX_MSGS];
|
||||
size_t n_rx_pkts;
|
||||
|
||||
struct ath10k *ar;
|
||||
struct ath10k_sdio_irq_data irq_data;
|
||||
|
||||
/* temporary buffer for BMI requests */
|
||||
u8 *bmi_buf;
|
||||
|
||||
wait_queue_head_t irq_wq;
|
||||
|
||||
bool is_disabled;
|
||||
|
||||
struct workqueue_struct *workqueue;
|
||||
struct work_struct wr_async_work;
|
||||
struct list_head wr_asyncq;
|
||||
/* protects access to wr_asyncq */
|
||||
spinlock_t wr_async_lock;
|
||||
};
|
||||
|
||||
static inline struct ath10k_sdio *ath10k_sdio_priv(struct ath10k *ar)
|
||||
{
|
||||
return (struct ath10k_sdio *)ar->drv_priv;
|
||||
}
|
||||
|
||||
#endif
|
@ -205,6 +205,24 @@ struct host_interest {
|
||||
*/
|
||||
/* Bit 1 - unused */
|
||||
u32 hi_fw_swap; /* 0x104 */
|
||||
|
||||
/* global arenas pointer address, used by host driver debug */
|
||||
u32 hi_dynamic_mem_arenas_addr; /* 0x108 */
|
||||
|
||||
/* allocated bytes of DRAM use by allocated */
|
||||
u32 hi_dynamic_mem_allocated; /* 0x10C */
|
||||
|
||||
/* remaining bytes of DRAM */
|
||||
u32 hi_dynamic_mem_remaining; /* 0x110 */
|
||||
|
||||
/* memory track count, configured by host */
|
||||
u32 hi_dynamic_mem_track_max; /* 0x114 */
|
||||
|
||||
/* minidump buffer */
|
||||
u32 hi_minidump; /* 0x118 */
|
||||
|
||||
/* bdata's sig and key addr */
|
||||
u32 hi_bd_sig_key; /* 0x11c */
|
||||
} __packed;
|
||||
|
||||
#define HI_ITEM(item) offsetof(struct host_interest, item)
|
||||
@ -319,6 +337,12 @@ struct host_interest {
|
||||
#define HI_ACS_FLAGS_USE_WWAN (1 << 1)
|
||||
/* Use test VAP */
|
||||
#define HI_ACS_FLAGS_TEST_VAP (1 << 2)
|
||||
/* SDIO/mailbox ACS flag definitions */
|
||||
#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET (1 << 0)
|
||||
#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET (1 << 1)
|
||||
#define HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE (1 << 2)
|
||||
#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK (1 << 16)
|
||||
#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK (1 << 17)
|
||||
|
||||
/*
|
||||
* CONSOLE FLAGS
|
||||
|
@ -137,6 +137,13 @@ static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION,
|
||||
ar->normal_mode_fw.fw_file.wmi_op_version);
|
||||
if (ret) {
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return cfg80211_testmode_reply(skb);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ enum ath10k_tm_attr {
|
||||
ATH10K_TM_ATTR_WMI_CMDID = 3,
|
||||
ATH10K_TM_ATTR_VERSION_MAJOR = 4,
|
||||
ATH10K_TM_ATTR_VERSION_MINOR = 5,
|
||||
ATH10K_TM_ATTR_WMI_OP_VERSION = 6,
|
||||
|
||||
/* keep last */
|
||||
__ATH10K_TM_ATTR_AFTER_LAST,
|
||||
|
@ -938,7 +938,10 @@ static int open_file_eeprom(struct inode *inode, struct file *file)
|
||||
}
|
||||
|
||||
for (i = 0; i < eesize; ++i) {
|
||||
AR5K_EEPROM_READ(i, val);
|
||||
if (!ath5k_hw_nvram_read(ah, i, &val)) {
|
||||
ret = -EIO;
|
||||
goto freebuf;
|
||||
}
|
||||
buf[i] = val;
|
||||
}
|
||||
|
||||
|
@ -399,15 +399,10 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
csum_dest = skb->csum_offset + csum_start;
|
||||
}
|
||||
|
||||
if (skb_headroom(skb) < dev->needed_headroom) {
|
||||
struct sk_buff *tmp_skb = skb;
|
||||
|
||||
skb = skb_realloc_headroom(skb, dev->needed_headroom);
|
||||
kfree_skb(tmp_skb);
|
||||
if (skb == NULL) {
|
||||
dev->stats.tx_dropped++;
|
||||
return 0;
|
||||
}
|
||||
if (skb_cow_head(skb, dev->needed_headroom)) {
|
||||
dev->stats.tx_dropped++;
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ath6kl_wmi_dix_2_dot3(ar->wmi, skb)) {
|
||||
|
@ -369,7 +369,7 @@ void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
|
||||
{
|
||||
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
|
||||
|
||||
if (reg->power_limit != new_txpow)
|
||||
if (ah->curchan && reg->power_limit != new_txpow)
|
||||
ath9k_hw_set_txpowerlimit(ah, new_txpow, false);
|
||||
|
||||
/* read back in case value is clamped */
|
||||
|
@ -143,7 +143,7 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
|
||||
|
||||
if (ah->eeprom_blob)
|
||||
ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data);
|
||||
else if (pdata && !pdata->use_eeprom && pdata->eeprom_data)
|
||||
else if (pdata && !pdata->use_eeprom)
|
||||
ret = ath9k_hw_nvram_read_pdata(pdata, off, data);
|
||||
else
|
||||
ret = common->bus_ops->eeprom_read(common, off, data);
|
||||
|
@ -153,7 +153,7 @@ static int ath9k_tx99_init(struct ath_softc *sc)
|
||||
sc->tx99_power,
|
||||
sc->tx99_power / 2);
|
||||
|
||||
/* We leave the harware awake as it will be chugging on */
|
||||
/* We leave the hardware awake as it will be chugging on */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -795,15 +795,11 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
struct cfg80211_mgmt_tx_params params;
|
||||
int rc;
|
||||
void *frame = kmalloc(len, GFP_KERNEL);
|
||||
void *frame;
|
||||
|
||||
if (!frame)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(frame, buf, len)) {
|
||||
kfree(frame);
|
||||
return -EIO;
|
||||
}
|
||||
frame = memdup_user(buf, len);
|
||||
if (IS_ERR(frame))
|
||||
return PTR_ERR(frame);
|
||||
|
||||
params.buf = frame;
|
||||
params.len = len;
|
||||
|
@ -71,8 +71,18 @@ MODULE_FIRMWARE("b43/ucode11.fw");
|
||||
MODULE_FIRMWARE("b43/ucode13.fw");
|
||||
MODULE_FIRMWARE("b43/ucode14.fw");
|
||||
MODULE_FIRMWARE("b43/ucode15.fw");
|
||||
MODULE_FIRMWARE("b43/ucode16_lp.fw");
|
||||
MODULE_FIRMWARE("b43/ucode16_mimo.fw");
|
||||
MODULE_FIRMWARE("b43/ucode24_lcn.fw");
|
||||
MODULE_FIRMWARE("b43/ucode25_lcn.fw");
|
||||
MODULE_FIRMWARE("b43/ucode25_mimo.fw");
|
||||
MODULE_FIRMWARE("b43/ucode26_mimo.fw");
|
||||
MODULE_FIRMWARE("b43/ucode29_mimo.fw");
|
||||
MODULE_FIRMWARE("b43/ucode33_lcn40.fw");
|
||||
MODULE_FIRMWARE("b43/ucode30_mimo.fw");
|
||||
MODULE_FIRMWARE("b43/ucode5.fw");
|
||||
MODULE_FIRMWARE("b43/ucode40.fw");
|
||||
MODULE_FIRMWARE("b43/ucode42.fw");
|
||||
MODULE_FIRMWARE("b43/ucode9.fw");
|
||||
|
||||
static int modparam_bad_frames_preempt;
|
||||
|
@ -380,9 +380,7 @@ int brcmf_btcoex_attach(struct brcmf_cfg80211_info *cfg)
|
||||
/* Set up timer for BT */
|
||||
btci->timer_on = false;
|
||||
btci->timeout = BRCMF_BTCOEX_OPPR_WIN_TIME;
|
||||
init_timer(&btci->timer);
|
||||
btci->timer.data = (ulong)btci;
|
||||
btci->timer.function = brcmf_btcoex_timerfunc;
|
||||
setup_timer(&btci->timer, brcmf_btcoex_timerfunc, (ulong)btci);
|
||||
btci->cfg = cfg;
|
||||
btci->saved_regs_part1 = false;
|
||||
btci->saved_regs_part2 = false;
|
||||
|
@ -4674,9 +4674,6 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
|
||||
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
|
||||
if (err < 0)
|
||||
brcmf_err("setting AP mode failed %d\n", err);
|
||||
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
|
||||
if (err < 0)
|
||||
brcmf_err("setting INFRA mode failed %d\n", err);
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
|
||||
brcmf_fil_iovar_int_set(ifp, "mbss", 0);
|
||||
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
|
||||
@ -6378,16 +6375,6 @@ err:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
|
||||
{
|
||||
/* scheduled scan settings */
|
||||
wiphy->max_sched_scan_reqs = 1;
|
||||
wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
|
||||
wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
|
||||
wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
|
||||
wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static const struct wiphy_wowlan_support brcmf_wowlan_support = {
|
||||
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
|
||||
@ -6434,6 +6421,7 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
||||
const struct ieee80211_iface_combination *combo;
|
||||
struct ieee80211_supported_band *band;
|
||||
u16 max_interfaces = 0;
|
||||
bool gscan;
|
||||
__le32 bandlist[3];
|
||||
u32 n_bands;
|
||||
int err, i;
|
||||
@ -6483,9 +6471,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
||||
wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
|
||||
wiphy->mgmt_stypes = brcmf_txrx_stypes;
|
||||
wiphy->max_remain_on_channel_duration = 5000;
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
|
||||
brcmf_wiphy_pno_params(wiphy);
|
||||
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
|
||||
gscan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_GSCAN);
|
||||
brcmf_pno_wiphy_params(wiphy, gscan);
|
||||
}
|
||||
/* vendor commands/events support */
|
||||
wiphy->vendor_commands = brcmf_vendor_cmds;
|
||||
wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "fwil_types.h"
|
||||
#include "p2p.h"
|
||||
|
||||
#define BRCMF_SCAN_IE_LEN_MAX 2048
|
||||
|
||||
#define WL_NUM_SCAN_MAX 10
|
||||
#define WL_TLV_INFO_MAX 1024
|
||||
#define WL_BSS_INFO_MAX 2048
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "feature.h"
|
||||
#include "common.h"
|
||||
|
||||
#define BRCMF_FW_UNSUPPORTED 23
|
||||
|
||||
/*
|
||||
* expand feature list to array of feature strings.
|
||||
@ -113,6 +114,22 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
|
||||
}
|
||||
}
|
||||
|
||||
static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
|
||||
enum brcmf_feat_id id, char *name,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = brcmf_fil_iovar_data_set(ifp, name, data, len);
|
||||
if (err != -BRCMF_FW_UNSUPPORTED) {
|
||||
brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
|
||||
ifp->drvr->feat_flags |= BIT(id);
|
||||
} else {
|
||||
brcmf_dbg(TRACE, "%s feature check failed: %d\n",
|
||||
brcmf_feat_names[id], err);
|
||||
}
|
||||
}
|
||||
|
||||
static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
|
||||
{
|
||||
char caps[256];
|
||||
@ -136,11 +153,14 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
|
||||
{
|
||||
struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
|
||||
struct brcmf_pno_macaddr_le pfn_mac;
|
||||
struct brcmf_gscan_config gscan_cfg;
|
||||
u32 wowl_cap;
|
||||
s32 err;
|
||||
|
||||
brcmf_feat_firmware_capabilities(ifp);
|
||||
|
||||
memset(&gscan_cfg, 0, sizeof(gscan_cfg));
|
||||
brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN, "pfn_gscan_cfg",
|
||||
&gscan_cfg, sizeof(gscan_cfg));
|
||||
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
|
||||
if (drvr->bus_if->wowl_supported)
|
||||
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
|
||||
|
@ -31,6 +31,7 @@
|
||||
* WOWL_GTK: (WOWL) GTK rekeying offload
|
||||
* WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL.
|
||||
* MFP: 802.11w Management Frame Protection.
|
||||
* GSCAN: enhanced scan offload feature.
|
||||
*/
|
||||
#define BRCMF_FEAT_LIST \
|
||||
BRCMF_FEAT_DEF(MBSS) \
|
||||
@ -44,7 +45,8 @@
|
||||
BRCMF_FEAT_DEF(WOWL_ND) \
|
||||
BRCMF_FEAT_DEF(WOWL_GTK) \
|
||||
BRCMF_FEAT_DEF(WOWL_ARP_ND) \
|
||||
BRCMF_FEAT_DEF(MFP)
|
||||
BRCMF_FEAT_DEF(MFP) \
|
||||
BRCMF_FEAT_DEF(GSCAN)
|
||||
|
||||
/*
|
||||
* Quirks:
|
||||
|
@ -835,4 +835,63 @@ struct brcmf_gtk_keyinfo_le {
|
||||
u8 replay_counter[BRCMF_RSN_REPLAY_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_gscan_bucket_config - configuration data for channel bucket.
|
||||
*
|
||||
* @bucket_end_index: !unknown!
|
||||
* @bucket_freq_multiple: !unknown!
|
||||
* @flag: !unknown!
|
||||
* @reserved: !unknown!
|
||||
* @repeat: !unknown!
|
||||
* @max_freq_multiple: !unknown!
|
||||
*/
|
||||
struct brcmf_gscan_bucket_config {
|
||||
u8 bucket_end_index;
|
||||
u8 bucket_freq_multiple;
|
||||
u8 flag;
|
||||
u8 reserved;
|
||||
__le16 repeat;
|
||||
__le16 max_freq_multiple;
|
||||
};
|
||||
|
||||
/* version supported which must match firmware */
|
||||
#define BRCMF_GSCAN_CFG_VERSION 1
|
||||
|
||||
/**
|
||||
* enum brcmf_gscan_cfg_flags - bit values for gscan flags.
|
||||
*
|
||||
* @BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS: send probe responses/beacons to host.
|
||||
* @BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY: indicated only flags member is changed.
|
||||
*/
|
||||
enum brcmf_gscan_cfg_flags {
|
||||
BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS = BIT(0),
|
||||
BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY = BIT(7),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct brcmf_gscan_config - configuration data for gscan.
|
||||
*
|
||||
* @version: version of the api to match firmware.
|
||||
* @flags: flags according %enum brcmf_gscan_cfg_flags.
|
||||
* @buffer_threshold: percentage threshold of buffer to generate an event.
|
||||
* @swc_nbssid_threshold: number of BSSIDs with significant change that
|
||||
* will generate an event.
|
||||
* @swc_rssi_window_size: size of rssi cache buffer (max=8).
|
||||
* @count_of_channel_buckets: number of array members in @bucket.
|
||||
* @retry_threshold: !unknown!
|
||||
* @lost_ap_window: !unknown!
|
||||
* @bucket: array of channel buckets.
|
||||
*/
|
||||
struct brcmf_gscan_config {
|
||||
__le16 version;
|
||||
u8 flags;
|
||||
u8 buffer_threshold;
|
||||
u8 swc_nbssid_threshold;
|
||||
u8 swc_rssi_window_size;
|
||||
u8 count_of_channel_buckets;
|
||||
u8 retry_threshold;
|
||||
__le16 lost_ap_window;
|
||||
struct brcmf_gscan_bucket_config bucket[1];
|
||||
};
|
||||
|
||||
#endif /* FWIL_TYPES_H_ */
|
||||
|
@ -239,3 +239,13 @@ int brcmf_pno_start_sched_scan(struct brcmf_if *ifp,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan)
|
||||
{
|
||||
/* scheduled scan settings */
|
||||
wiphy->max_sched_scan_reqs = gscan ? 2 : 1;
|
||||
wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
|
||||
wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
|
||||
wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
|
||||
wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
|
||||
}
|
||||
|
||||
|
@ -37,4 +37,12 @@ int brcmf_pno_clean(struct brcmf_if *ifp);
|
||||
int brcmf_pno_start_sched_scan(struct brcmf_if *ifp,
|
||||
struct cfg80211_sched_scan_request *req);
|
||||
|
||||
/**
|
||||
* brcmf_pno_wiphy_params - fill scheduled scan parameters in wiphy instance.
|
||||
*
|
||||
* @wiphy: wiphy instance to be used.
|
||||
* @gscan: indicates whether the device has support for g-scan feature.
|
||||
*/
|
||||
void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan);
|
||||
|
||||
#endif /* _BRCMF_PNO_H */
|
||||
|
@ -5147,6 +5147,8 @@ set_ch_out:
|
||||
|
||||
if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) {
|
||||
il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS);
|
||||
if (!il->power_data.ps_disabled)
|
||||
IL_WARN_ONCE("Enabling power save might cause firmware crashes\n");
|
||||
ret = il_power_update_mode(il, false);
|
||||
if (ret)
|
||||
D_MAC80211("Error setting sleep level\n");
|
||||
|
@ -45,6 +45,7 @@ struct il_tx_queue;
|
||||
|
||||
#define IL_ERR(f, a...) dev_err(&il->pci_dev->dev, f, ## a)
|
||||
#define IL_WARN(f, a...) dev_warn(&il->pci_dev->dev, f, ## a)
|
||||
#define IL_WARN_ONCE(f, a...) dev_warn_once(&il->pci_dev->dev, f, ## a)
|
||||
#define IL_INFO(f, a...) dev_info(&il->pci_dev->dev, f, ## a)
|
||||
|
||||
#define RX_QUEUE_SIZE 256
|
||||
|
@ -190,7 +190,7 @@ static inline void __hostap_cmd_queue_free(local_info_t *local,
|
||||
}
|
||||
}
|
||||
|
||||
if (atomic_dec_and_test(&entry->usecnt) && entry->del_req)
|
||||
if (refcount_dec_and_test(&entry->usecnt) && entry->del_req)
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
@ -228,7 +228,7 @@ static void prism2_clear_cmd_queue(local_info_t *local)
|
||||
spin_lock_irqsave(&local->cmdlock, flags);
|
||||
list_for_each_safe(ptr, n, &local->cmd_queue) {
|
||||
entry = list_entry(ptr, struct hostap_cmd_queue, list);
|
||||
atomic_inc(&entry->usecnt);
|
||||
refcount_inc(&entry->usecnt);
|
||||
printk(KERN_DEBUG "%s: removed pending cmd_queue entry "
|
||||
"(type=%d, cmd=0x%04x, param0=0x%04x)\n",
|
||||
local->dev->name, entry->type, entry->cmd,
|
||||
@ -350,7 +350,7 @@ static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0,
|
||||
if (entry == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
atomic_set(&entry->usecnt, 1);
|
||||
refcount_set(&entry->usecnt, 1);
|
||||
entry->type = CMD_SLEEP;
|
||||
entry->cmd = cmd;
|
||||
entry->param0 = param0;
|
||||
@ -516,7 +516,7 @@ static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0,
|
||||
if (entry == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
atomic_set(&entry->usecnt, 1);
|
||||
refcount_set(&entry->usecnt, 1);
|
||||
entry->type = CMD_CALLBACK;
|
||||
entry->cmd = cmd;
|
||||
entry->param0 = param0;
|
||||
@ -666,7 +666,7 @@ static void prism2_cmd_ev(struct net_device *dev)
|
||||
if (!list_empty(&local->cmd_queue)) {
|
||||
entry = list_entry(local->cmd_queue.next,
|
||||
struct hostap_cmd_queue, list);
|
||||
atomic_inc(&entry->usecnt);
|
||||
refcount_inc(&entry->usecnt);
|
||||
list_del_init(&entry->list);
|
||||
local->cmd_queue_len--;
|
||||
|
||||
@ -718,7 +718,7 @@ static void prism2_cmd_ev(struct net_device *dev)
|
||||
entry = NULL;
|
||||
}
|
||||
if (entry)
|
||||
atomic_inc(&entry->usecnt);
|
||||
refcount_inc(&entry->usecnt);
|
||||
}
|
||||
spin_unlock(&local->cmdlock);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <net/lib80211.h>
|
||||
@ -557,7 +558,7 @@ struct hostap_cmd_queue {
|
||||
u16 resp0, res;
|
||||
volatile int issued, issuing;
|
||||
|
||||
atomic_t usecnt;
|
||||
refcount_t usecnt;
|
||||
int del_req;
|
||||
};
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
#include "mic.h"
|
||||
#include "orinoco.h"
|
||||
@ -268,7 +269,7 @@ enum ezusb_state {
|
||||
|
||||
struct request_context {
|
||||
struct list_head list;
|
||||
atomic_t refcount;
|
||||
refcount_t refcount;
|
||||
struct completion done; /* Signals that CTX is dead */
|
||||
int killed;
|
||||
struct urb *outurb; /* OUT for req pkt */
|
||||
@ -298,7 +299,7 @@ static inline u8 ezusb_reply_inc(u8 count)
|
||||
|
||||
static void ezusb_request_context_put(struct request_context *ctx)
|
||||
{
|
||||
if (!atomic_dec_and_test(&ctx->refcount))
|
||||
if (!refcount_dec_and_test(&ctx->refcount))
|
||||
return;
|
||||
|
||||
WARN_ON(!ctx->done.done);
|
||||
@ -328,7 +329,7 @@ static void ezusb_request_timerfn(u_long _ctx)
|
||||
} else {
|
||||
ctx->state = EZUSB_CTX_RESP_TIMEOUT;
|
||||
dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n");
|
||||
atomic_inc(&ctx->refcount);
|
||||
refcount_inc(&ctx->refcount);
|
||||
ctx->killed = 1;
|
||||
ezusb_ctx_complete(ctx);
|
||||
ezusb_request_context_put(ctx);
|
||||
@ -361,7 +362,7 @@ static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
|
||||
ctx->out_rid = out_rid;
|
||||
ctx->in_rid = in_rid;
|
||||
|
||||
atomic_set(&ctx->refcount, 1);
|
||||
refcount_set(&ctx->refcount, 1);
|
||||
init_completion(&ctx->done);
|
||||
|
||||
setup_timer(&ctx->timer, ezusb_request_timerfn, (u_long)ctx);
|
||||
@ -469,7 +470,7 @@ static void ezusb_req_queue_run(struct ezusb_priv *upriv)
|
||||
list_move_tail(&ctx->list, &upriv->req_active);
|
||||
|
||||
if (ctx->state == EZUSB_CTX_QUEUED) {
|
||||
atomic_inc(&ctx->refcount);
|
||||
refcount_inc(&ctx->refcount);
|
||||
result = usb_submit_urb(ctx->outurb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
ctx->state = EZUSB_CTX_REQSUBMIT_FAIL;
|
||||
@ -507,7 +508,7 @@ static void ezusb_req_enqueue_run(struct ezusb_priv *upriv,
|
||||
spin_unlock_irqrestore(&upriv->req_lock, flags);
|
||||
goto done;
|
||||
}
|
||||
atomic_inc(&ctx->refcount);
|
||||
refcount_inc(&ctx->refcount);
|
||||
list_add_tail(&ctx->list, &upriv->req_pending);
|
||||
spin_unlock_irqrestore(&upriv->req_lock, flags);
|
||||
|
||||
@ -1477,7 +1478,7 @@ static inline void ezusb_delete(struct ezusb_priv *upriv)
|
||||
int err;
|
||||
|
||||
ctx = list_entry(item, struct request_context, list);
|
||||
atomic_inc(&ctx->refcount);
|
||||
refcount_inc(&ctx->refcount);
|
||||
|
||||
ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
|
||||
err = usb_unlink_urb(ctx->outurb);
|
||||
|
@ -176,8 +176,9 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
||||
* keeping a extra list for uploaded keys.
|
||||
*/
|
||||
|
||||
priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
|
||||
priv->rx_keycache_size), GFP_KERNEL);
|
||||
priv->used_rxkeys = kcalloc(BITS_TO_LONGS(priv->rx_keycache_size),
|
||||
sizeof(long),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!priv->used_rxkeys)
|
||||
return -ENOMEM;
|
||||
|
@ -443,17 +443,12 @@ static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
int ret = -ENOTSUPP;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
|
||||
chandef->chan->center_freq,
|
||||
cfg80211_get_chandef_type(chandef));
|
||||
|
||||
if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
|
||||
goto out;
|
||||
|
||||
ret = lbs_set_channel(priv, chandef->chan->hw_value);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -464,16 +459,12 @@ static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
int ret = -ENOTSUPP;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
|
||||
netdev_name(netdev), channel->center_freq);
|
||||
|
||||
if (netdev != priv->mesh_dev)
|
||||
goto out;
|
||||
|
||||
ret = lbs_mesh_set_channel(priv, channel->hw_value);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -512,8 +503,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
||||
int i;
|
||||
int ret = -EILSEQ;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
bsssize = get_unaligned_le16(&scanresp->bssdescriptsize);
|
||||
|
||||
lbs_deb_scan("scan response: %d BSSs (%d bytes); resp size %d bytes\n",
|
||||
@ -665,7 +654,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -693,11 +681,9 @@ static void lbs_scan_worker(struct work_struct *work)
|
||||
int last_channel;
|
||||
int running, carrier;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SCAN);
|
||||
|
||||
scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL);
|
||||
if (scan_cmd == NULL)
|
||||
goto out_no_scan_cmd;
|
||||
return;
|
||||
|
||||
/* prepare fixed part of scan command */
|
||||
scan_cmd->bsstype = CMD_BSS_TYPE_ANY;
|
||||
@ -766,16 +752,11 @@ static void lbs_scan_worker(struct work_struct *work)
|
||||
lbs_deb_scan("scan: waking up waiters\n");
|
||||
wake_up_all(&priv->scan_q);
|
||||
}
|
||||
|
||||
out_no_scan_cmd:
|
||||
lbs_deb_leave(LBS_DEB_SCAN);
|
||||
}
|
||||
|
||||
static void _internal_start_scan(struct lbs_private *priv, bool internal,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n",
|
||||
request->n_ssids, request->n_channels, request->ie_len);
|
||||
|
||||
@ -785,8 +766,6 @@ static void _internal_start_scan(struct lbs_private *priv, bool internal,
|
||||
|
||||
queue_delayed_work(priv->work_thread, &priv->scan_work,
|
||||
msecs_to_jiffies(50));
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -815,8 +794,6 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
if (priv->scan_req || delayed_work_pending(&priv->scan_work)) {
|
||||
/* old scan request not yet processed */
|
||||
ret = -EAGAIN;
|
||||
@ -829,7 +806,6 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
|
||||
ret = -EIO;
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -843,18 +819,12 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
|
||||
void lbs_send_disconnect_notification(struct lbs_private *priv,
|
||||
bool locally_generated)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated,
|
||||
GFP_KERNEL);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
}
|
||||
|
||||
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
cfg80211_michael_mic_failure(priv->dev,
|
||||
priv->assoc_bss,
|
||||
event == MACREG_INT_CODE_MIC_ERR_MULTICAST ?
|
||||
@ -863,8 +833,6 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
|
||||
-1,
|
||||
NULL,
|
||||
GFP_KERNEL);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
}
|
||||
|
||||
|
||||
@ -883,8 +851,6 @@ static int lbs_remove_wep_keys(struct lbs_private *priv)
|
||||
struct cmd_ds_802_11_set_wep cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.keyindex = cpu_to_le16(priv->wep_tx_key);
|
||||
@ -892,7 +858,6 @@ static int lbs_remove_wep_keys(struct lbs_private *priv)
|
||||
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -905,8 +870,6 @@ static int lbs_set_wep_keys(struct lbs_private *priv)
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
/*
|
||||
* command 13 00
|
||||
* size 50 00
|
||||
@ -956,7 +919,6 @@ static int lbs_set_wep_keys(struct lbs_private *priv)
|
||||
ret = lbs_remove_wep_keys(priv);
|
||||
}
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -969,8 +931,6 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable)
|
||||
struct cmd_ds_802_11_enable_rsn cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable);
|
||||
|
||||
/*
|
||||
* cmd 2f 00
|
||||
* size 0c 00
|
||||
@ -986,7 +946,6 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable)
|
||||
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1014,8 +973,6 @@ static int lbs_set_key_material(struct lbs_private *priv,
|
||||
struct cmd_key_material cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
/*
|
||||
* Example for WPA (TKIP):
|
||||
*
|
||||
@ -1044,7 +1001,6 @@ static int lbs_set_key_material(struct lbs_private *priv,
|
||||
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1061,8 +1017,6 @@ static int lbs_set_authtype(struct lbs_private *priv,
|
||||
struct cmd_ds_802_11_authenticate cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type);
|
||||
|
||||
/*
|
||||
* cmd 11 00
|
||||
* size 19 00
|
||||
@ -1085,7 +1039,6 @@ static int lbs_set_authtype(struct lbs_private *priv,
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1116,8 +1069,6 @@ static int lbs_associate(struct lbs_private *priv,
|
||||
u8 *pos;
|
||||
u8 *tmp;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
if (!cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
@ -1262,7 +1213,6 @@ static int lbs_associate(struct lbs_private *priv,
|
||||
|
||||
kfree(cmd);
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1329,8 +1279,6 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (dev == priv->mesh_dev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
if (!sme->bssid) {
|
||||
struct cfg80211_scan_request *creq;
|
||||
|
||||
@ -1442,7 +1390,6 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
done:
|
||||
if (bss)
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1478,8 +1425,6 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (dev == priv->mesh_dev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code);
|
||||
|
||||
/* store for lbs_cfg_ret_disconnect() */
|
||||
priv->disassoc_reason = reason_code;
|
||||
|
||||
@ -1496,8 +1441,6 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
|
||||
if (netdev == priv->mesh_dev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
if (key_index != priv->wep_tx_key) {
|
||||
lbs_deb_assoc("set_default_key: to %d\n", key_index);
|
||||
priv->wep_tx_key = key_index;
|
||||
@ -1520,8 +1463,6 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
|
||||
if (netdev == priv->mesh_dev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n",
|
||||
params->cipher, mac_addr);
|
||||
lbs_deb_assoc("add_key: key index %d, key len %d\n",
|
||||
@ -1575,8 +1516,6 @@ static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
|
||||
u8 key_index, bool pairwise, const u8 *mac_addr)
|
||||
{
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n",
|
||||
key_index, mac_addr);
|
||||
|
||||
@ -1619,8 +1558,6 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
int ret;
|
||||
size_t i;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) |
|
||||
BIT(NL80211_STA_INFO_TX_PACKETS) |
|
||||
BIT(NL80211_STA_INFO_RX_BYTES) |
|
||||
@ -1675,15 +1612,12 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
if (priv->iface_running)
|
||||
ret = lbs_set_iface_type(priv, type);
|
||||
|
||||
if (!ret)
|
||||
priv->wdev->iftype = type;
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1713,8 +1647,6 @@ static void lbs_join_post(struct lbs_private *priv,
|
||||
u8 *fake = fake_ie;
|
||||
struct cfg80211_bss *bss;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
/*
|
||||
* For cfg80211_inform_bss, we'll need a fake IE, as we can't get
|
||||
* the real IE from the firmware. So we fabricate a fake IE based on
|
||||
@ -1777,8 +1709,6 @@ static void lbs_join_post(struct lbs_private *priv,
|
||||
netif_carrier_on(priv->dev);
|
||||
if (!priv->tx_pending_len)
|
||||
netif_wake_queue(priv->dev);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
}
|
||||
|
||||
static int lbs_ibss_join_existing(struct lbs_private *priv,
|
||||
@ -1790,8 +1720,6 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
|
||||
u8 preamble = RADIO_PREAMBLE_SHORT;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
/* TODO: set preamble based on scan result */
|
||||
ret = lbs_set_radio(priv, preamble, 1);
|
||||
if (ret)
|
||||
@ -1888,7 +1816,6 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
|
||||
lbs_join_post(priv, params, bss->bssid, bss->capability);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1904,8 +1831,6 @@ static int lbs_ibss_start_new(struct lbs_private *priv,
|
||||
int ret = 0;
|
||||
u16 capability;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
ret = lbs_set_radio(priv, preamble, 1);
|
||||
if (ret)
|
||||
goto out;
|
||||
@ -1975,7 +1900,6 @@ static int lbs_ibss_start_new(struct lbs_private *priv,
|
||||
lbs_join_post(priv, params, resp->bssid, capability);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1990,8 +1914,6 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (dev == priv->mesh_dev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
if (!params->chandef.chan) {
|
||||
ret = -ENOTSUPP;
|
||||
goto out;
|
||||
@ -2015,7 +1937,6 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2029,8 +1950,6 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
|
||||
if (dev == priv->mesh_dev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
|
||||
@ -2038,7 +1957,6 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
|
||||
/* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
|
||||
lbs_mac_event_disconnected(priv, true);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2114,8 +2032,6 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev)
|
||||
int ret = 0;
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
|
||||
if (!wdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@ -2127,12 +2043,10 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev)
|
||||
goto err_wiphy_new;
|
||||
}
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
return wdev;
|
||||
|
||||
err_wiphy_new:
|
||||
kfree(wdev);
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@ -2155,15 +2069,11 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
|
||||
};
|
||||
size_t i;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regmap); i++)
|
||||
if (regmap[i].code == priv->regioncode) {
|
||||
regulatory_hint(priv->wdev->wiphy, regmap[i].cn);
|
||||
break;
|
||||
}
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
}
|
||||
|
||||
static void lbs_reg_notifier(struct wiphy *wiphy,
|
||||
@ -2171,15 +2081,9 @@ static void lbs_reg_notifier(struct wiphy *wiphy,
|
||||
{
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
|
||||
"callback for domain %c%c\n", request->alpha2[0],
|
||||
request->alpha2[1]);
|
||||
|
||||
memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
|
||||
if (lbs_iface_active(priv))
|
||||
lbs_set_11d_domain_info(priv);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CFG80211);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2192,8 +2096,6 @@ int lbs_cfg_register(struct lbs_private *priv)
|
||||
struct wireless_dev *wdev = priv->wdev;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
wdev->wiphy->max_scan_ssids = 1;
|
||||
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||
|
||||
@ -2229,13 +2131,11 @@ int lbs_cfg_register(struct lbs_private *priv)
|
||||
|
||||
lbs_cfg_set_regulatory_hint(priv);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lbs_scan_deinit(struct lbs_private *priv)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
cancel_delayed_work_sync(&priv->scan_work);
|
||||
}
|
||||
|
||||
@ -2244,8 +2144,6 @@ void lbs_cfg_free(struct lbs_private *priv)
|
||||
{
|
||||
struct wireless_dev *wdev = priv->wdev;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||
|
||||
if (!wdev)
|
||||
return;
|
||||
|
||||
|
@ -91,8 +91,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
|
||||
int ret = -1;
|
||||
u32 i;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
|
||||
@ -159,14 +157,12 @@ int lbs_update_hw_spec(struct lbs_private *priv)
|
||||
}
|
||||
|
||||
out:
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
|
||||
struct cmd_header *resp)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
if (priv->is_host_sleep_activated) {
|
||||
priv->is_host_sleep_configured = 0;
|
||||
if (priv->psstate == PS_STATE_FULL_POWER) {
|
||||
@ -176,7 +172,7 @@ static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
|
||||
} else {
|
||||
priv->is_host_sleep_configured = 1;
|
||||
}
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -236,8 +232,6 @@ int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
|
||||
struct cmd_ds_802_11_ps_mode cmd;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(cmd_action);
|
||||
@ -262,7 +256,6 @@ int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
|
||||
lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -272,8 +265,6 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
|
||||
struct cmd_ds_802_11_sleep_params cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
if (cmd_action == CMD_ACT_GET) {
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
} else {
|
||||
@ -304,7 +295,6 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
|
||||
sp->sp_reserved = le16_to_cpu(cmd.reserved);
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -312,8 +302,6 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
if (priv->is_deep_sleep) {
|
||||
if (!wait_event_interruptible_timeout(priv->ds_awake_q,
|
||||
!priv->is_deep_sleep, (10 * HZ))) {
|
||||
@ -322,7 +310,6 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv)
|
||||
}
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -330,8 +317,6 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
if (deep_sleep) {
|
||||
if (priv->is_deep_sleep != 1) {
|
||||
lbs_deb_cmd("deep sleep: sleep\n");
|
||||
@ -358,7 +343,6 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
|
||||
}
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -366,10 +350,9 @@ static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
|
||||
unsigned long dummy,
|
||||
struct cmd_header *cmd)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_FW);
|
||||
priv->is_host_sleep_activated = 1;
|
||||
wake_up_interruptible(&priv->host_sleep_q);
|
||||
lbs_deb_leave(LBS_DEB_FW);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -379,8 +362,6 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
|
||||
int ret = 0;
|
||||
uint32_t criteria = EHS_REMOVE_WAKEUP;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
if (host_sleep) {
|
||||
if (priv->is_host_sleep_activated != 1) {
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
@ -438,8 +419,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
|
||||
struct cmd_ds_802_11_snmp_mib cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof (cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_ACT_SET);
|
||||
@ -470,7 +449,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -488,8 +466,6 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
|
||||
struct cmd_ds_802_11_snmp_mib cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof (cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_ACT_GET);
|
||||
@ -513,7 +489,6 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
|
||||
}
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -533,8 +508,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
|
||||
struct cmd_ds_802_11_rf_tx_power cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_ACT_GET);
|
||||
@ -548,7 +521,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
|
||||
*maxlevel = cmd.maxlevel;
|
||||
}
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -565,8 +537,6 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
|
||||
struct cmd_ds_802_11_rf_tx_power cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_ACT_SET);
|
||||
@ -576,7 +546,6 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
|
||||
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -608,7 +577,6 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
|
||||
ARPHRD_ETHER;
|
||||
}
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -624,8 +592,6 @@ static int lbs_get_channel(struct lbs_private *priv)
|
||||
struct cmd_ds_802_11_rf_channel cmd;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
|
||||
@ -638,7 +604,6 @@ static int lbs_get_channel(struct lbs_private *priv)
|
||||
lbs_deb_cmd("current radio channel is %d\n", ret);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -647,14 +612,12 @@ int lbs_update_channel(struct lbs_private *priv)
|
||||
int ret;
|
||||
|
||||
/* the channel in f/w could be out of sync; get the current channel */
|
||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||
|
||||
ret = lbs_get_channel(priv);
|
||||
if (ret > 0) {
|
||||
priv->channel = ret;
|
||||
ret = 0;
|
||||
}
|
||||
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -674,8 +637,6 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
|
||||
@ -690,7 +651,6 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
|
||||
priv->channel);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -708,8 +668,6 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
|
||||
struct cmd_ds_802_11_rssi cmd;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
BUG_ON(rssi == NULL);
|
||||
BUG_ON(nf == NULL);
|
||||
|
||||
@ -724,7 +682,6 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
|
||||
*rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -752,7 +709,6 @@ int lbs_set_11d_domain_info(struct lbs_private *priv)
|
||||
size_t triplet_size;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_11D);
|
||||
if (!priv->country_code[0])
|
||||
goto out;
|
||||
|
||||
@ -849,7 +805,6 @@ int lbs_set_11d_domain_info(struct lbs_private *priv)
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -869,8 +824,6 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
|
||||
struct cmd_ds_reg_access cmd;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
BUG_ON(value == NULL);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
@ -894,7 +847,6 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
|
||||
}
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -914,8 +866,6 @@ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
|
||||
struct cmd_ds_reg_access cmd;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_ACT_SET);
|
||||
@ -933,7 +883,6 @@ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
|
||||
ret = lbs_cmd_with_response(priv, reg, &cmd);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -943,15 +892,13 @@ static void lbs_queue_cmd(struct lbs_private *priv,
|
||||
unsigned long flags;
|
||||
int addtail = 1;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
if (!cmdnode) {
|
||||
lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
|
||||
goto done;
|
||||
return;
|
||||
}
|
||||
if (!cmdnode->cmdbuf->size) {
|
||||
lbs_deb_host("DNLD_CMD: cmd size is zero\n");
|
||||
goto done;
|
||||
return;
|
||||
}
|
||||
cmdnode->result = 0;
|
||||
|
||||
@ -979,9 +926,6 @@ static void lbs_queue_cmd(struct lbs_private *priv,
|
||||
|
||||
lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
|
||||
le16_to_cpu(cmdnode->cmdbuf->command));
|
||||
|
||||
done:
|
||||
lbs_deb_leave(LBS_DEB_HOST);
|
||||
}
|
||||
|
||||
static void lbs_submit_command(struct lbs_private *priv,
|
||||
@ -994,8 +938,6 @@ static void lbs_submit_command(struct lbs_private *priv,
|
||||
int timeo = 3 * HZ;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
cmd = cmdnode->cmdbuf;
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
@ -1036,8 +978,6 @@ static void lbs_submit_command(struct lbs_private *priv,
|
||||
/* Setup the timer after transmit command */
|
||||
mod_timer(&priv->command_timer, jiffies + timeo);
|
||||
}
|
||||
|
||||
lbs_deb_leave(LBS_DEB_HOST);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1047,10 +987,8 @@ static void lbs_submit_command(struct lbs_private *priv,
|
||||
static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
|
||||
struct cmd_ctrl_node *cmdnode)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
if (!cmdnode)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
cmdnode->callback = NULL;
|
||||
cmdnode->callback_arg = 0;
|
||||
@ -1058,8 +996,6 @@ static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
|
||||
memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
|
||||
|
||||
list_add_tail(&cmdnode->list, &priv->cmdfreeq);
|
||||
out:
|
||||
lbs_deb_leave(LBS_DEB_HOST);
|
||||
}
|
||||
|
||||
static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
|
||||
@ -1107,8 +1043,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
|
||||
struct cmd_ds_802_11_radio_control cmd;
|
||||
int ret = -EINVAL;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(CMD_ACT_SET);
|
||||
cmd.control = 0;
|
||||
@ -1141,7 +1075,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
|
||||
ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1149,15 +1082,11 @@ void lbs_set_mac_control(struct lbs_private *priv)
|
||||
{
|
||||
struct cmd_ds_mac_control cmd;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(priv->mac_control);
|
||||
cmd.reserved = 0;
|
||||
|
||||
lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
}
|
||||
|
||||
int lbs_set_mac_control_sync(struct lbs_private *priv)
|
||||
@ -1165,14 +1094,11 @@ int lbs_set_mac_control_sync(struct lbs_private *priv)
|
||||
struct cmd_ds_mac_control cmd;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||
cmd.action = cpu_to_le16(priv->mac_control);
|
||||
cmd.reserved = 0;
|
||||
ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1191,8 +1117,6 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv)
|
||||
u32 i;
|
||||
struct cmd_ctrl_node *cmdarray;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
/* Allocate and initialize the command array */
|
||||
bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
|
||||
if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
|
||||
@ -1219,7 +1143,6 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv)
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1235,8 +1158,6 @@ int lbs_free_cmd_buffer(struct lbs_private *priv)
|
||||
struct cmd_ctrl_node *cmdarray;
|
||||
unsigned int i;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
/* need to check if cmd array is allocated or not */
|
||||
if (priv->cmd_array == NULL) {
|
||||
lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
|
||||
@ -1260,7 +1181,6 @@ int lbs_free_cmd_buffer(struct lbs_private *priv)
|
||||
}
|
||||
|
||||
done:
|
||||
lbs_deb_leave(LBS_DEB_HOST);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1278,8 +1198,6 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
|
||||
struct cmd_ctrl_node *tempnode;
|
||||
unsigned long flags;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
if (!priv)
|
||||
return NULL;
|
||||
|
||||
@ -1296,7 +1214,6 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
|
||||
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_HOST);
|
||||
return tempnode;
|
||||
}
|
||||
|
||||
@ -1318,8 +1235,6 @@ int lbs_execute_next_command(struct lbs_private *priv)
|
||||
/* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
|
||||
* only caller to us is lbs_thread() and we get even when a
|
||||
* data packet is received */
|
||||
lbs_deb_enter(LBS_DEB_THREAD);
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
if (priv->cur_cmd) {
|
||||
@ -1440,7 +1355,6 @@ int lbs_execute_next_command(struct lbs_private *priv)
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
lbs_deb_leave(LBS_DEB_THREAD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1449,7 +1363,6 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
|
||||
sizeof(confirm_sleep));
|
||||
|
||||
@ -1457,7 +1370,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
|
||||
sizeof(confirm_sleep));
|
||||
if (ret) {
|
||||
netdev_alert(priv->dev, "confirm_sleep failed\n");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
@ -1475,9 +1388,6 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
|
||||
priv->psstate = PS_STATE_SLEEP;
|
||||
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
out:
|
||||
lbs_deb_leave(LBS_DEB_HOST);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1493,8 +1403,6 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
|
||||
unsigned long flags =0;
|
||||
int allowed = 1;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
if (priv->dnld_sent) {
|
||||
allowed = 0;
|
||||
@ -1520,8 +1428,6 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
|
||||
} else {
|
||||
lbs_deb_host("sleep confirm has been delayed\n");
|
||||
}
|
||||
|
||||
lbs_deb_leave(LBS_DEB_HOST);
|
||||
}
|
||||
|
||||
|
||||
@ -1596,8 +1502,6 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
|
||||
{
|
||||
struct cmd_ctrl_node *cmdnode;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
if (priv->surpriseremoved) {
|
||||
lbs_deb_host("PREP_CMD: card removed\n");
|
||||
cmdnode = ERR_PTR(-ENOENT);
|
||||
@ -1643,17 +1547,14 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
|
||||
wake_up(&priv->waitq);
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
|
||||
return cmdnode;
|
||||
}
|
||||
|
||||
void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
|
||||
struct cmd_header *in_cmd, int in_cmd_size)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
__lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
|
||||
lbs_cmd_async_callback, 0);
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
}
|
||||
|
||||
int __lbs_cmd(struct lbs_private *priv, uint16_t command,
|
||||
@ -1665,8 +1566,6 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
|
||||
callback, callback_arg);
|
||||
if (IS_ERR(cmdnode)) {
|
||||
@ -1693,7 +1592,6 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__lbs_cmd);
|
||||
|
@ -32,8 +32,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv,
|
||||
if (priv->connect_status != LBS_CONNECTED)
|
||||
return;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||
|
||||
/*
|
||||
* Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
|
||||
* It causes problem in the Supplicant
|
||||
@ -61,7 +59,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv,
|
||||
lbs_deb_cmd("disconnected, so exit PS mode\n");
|
||||
lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
|
||||
}
|
||||
lbs_deb_leave(LBS_DEB_ASSOC);
|
||||
}
|
||||
|
||||
int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
|
||||
@ -72,8 +69,6 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
|
||||
unsigned long flags;
|
||||
uint16_t result;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_HOST);
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
@ -221,7 +216,6 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
|
||||
|
||||
done:
|
||||
mutex_unlock(&priv->lock);
|
||||
lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -230,8 +224,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
|
||||
int ret = 0;
|
||||
struct cmd_header cmd;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
switch (event) {
|
||||
case MACREG_INT_CODE_LINK_SENSED:
|
||||
lbs_deb_cmd("EVENT: link sensed\n");
|
||||
@ -359,6 +351,5 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
|
||||
break;
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -55,15 +55,6 @@ do { if ((lbs_debug & (grp)) == (grp)) \
|
||||
#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define lbs_deb_enter(grp) \
|
||||
LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s()\n", __func__);
|
||||
#define lbs_deb_enter_args(grp, fmt, args...) \
|
||||
LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args);
|
||||
#define lbs_deb_leave(grp) \
|
||||
LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s()\n", __func__);
|
||||
#define lbs_deb_leave_args(grp, fmt, args...) \
|
||||
LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s(), " fmt "\n", \
|
||||
__func__, ##args);
|
||||
#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
|
||||
#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
|
||||
#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
|
||||
|
@ -41,8 +41,6 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev,
|
||||
struct cmd_ds_802_11_eeprom_access cmd;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ETHTOOL);
|
||||
|
||||
if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN ||
|
||||
eeprom->len > LBS_EEPROM_READ_LEN) {
|
||||
ret = -EINVAL;
|
||||
@ -59,7 +57,6 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev,
|
||||
memcpy(bytes, cmd.value, eeprom->len);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_ETHTOOL, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -336,13 +336,11 @@ static inline u32 get_model(u16 manf_id, u16 card_id)
|
||||
|
||||
static inline void if_cs_enable_ints(struct if_cs_card *card)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
|
||||
}
|
||||
|
||||
static inline void if_cs_disable_ints(struct if_cs_card *card)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK);
|
||||
}
|
||||
|
||||
@ -355,7 +353,6 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
|
||||
int ret = -1;
|
||||
int loops = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_disable_ints(card);
|
||||
|
||||
/* Is hardware ready? */
|
||||
@ -388,7 +385,6 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
|
||||
|
||||
done:
|
||||
if_cs_enable_ints(card);
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -400,7 +396,6 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
|
||||
struct if_cs_card *card = (struct if_cs_card *)priv->card;
|
||||
u16 status;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
if_cs_disable_ints(card);
|
||||
|
||||
status = if_cs_read16(card, IF_CS_CARD_STATUS);
|
||||
@ -416,8 +411,6 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
|
||||
if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX);
|
||||
if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX);
|
||||
if_cs_enable_ints(card);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CS);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -429,8 +422,6 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
|
||||
int ret = -1;
|
||||
u16 status;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
/* is hardware ready? */
|
||||
status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
|
||||
if ((status & IF_CS_BIT_RESP) == 0) {
|
||||
@ -463,7 +454,6 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -473,8 +463,6 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
|
||||
u16 len;
|
||||
u8 *data;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
len = if_cs_read16(priv->card, IF_CS_READ_LEN);
|
||||
if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
|
||||
netdev_err(priv->dev,
|
||||
@ -501,7 +489,6 @@ dat_err:
|
||||
if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
|
||||
return skb;
|
||||
}
|
||||
|
||||
@ -511,8 +498,6 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
|
||||
struct lbs_private *priv = card->priv;
|
||||
u16 cause;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
/* Ask card interrupt cause register if there is something for us */
|
||||
cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE);
|
||||
lbs_deb_cs("cause 0x%04x\n", cause);
|
||||
@ -569,7 +554,6 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
|
||||
/* Clear interrupt cause */
|
||||
if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CS);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -591,8 +575,6 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
|
||||
int sent = 0;
|
||||
u8 scratch;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
/*
|
||||
* This is the only place where an unaligned register access happens on
|
||||
* the CF8305 card, therefore for the sake of speed of the driver, we do
|
||||
@ -671,7 +653,6 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
|
||||
}
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -683,8 +664,6 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
|
||||
int len = 0;
|
||||
int sent;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
lbs_deb_cs("fw size %td\n", fw->size);
|
||||
|
||||
ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
|
||||
@ -734,7 +713,6 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
|
||||
pr_err("firmware download failed\n");
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -792,8 +770,6 @@ static int if_cs_host_to_card(struct lbs_private *priv,
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);
|
||||
|
||||
switch (type) {
|
||||
case MVMS_DAT:
|
||||
priv->dnld_sent = DNLD_DATA_SENT;
|
||||
@ -809,7 +785,6 @@ static int if_cs_host_to_card(struct lbs_private *priv,
|
||||
__func__, type);
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -818,14 +793,10 @@ static void if_cs_release(struct pcmcia_device *p_dev)
|
||||
{
|
||||
struct if_cs_card *card = p_dev->priv;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
free_irq(p_dev->irq, card);
|
||||
pcmcia_disable_device(p_dev);
|
||||
if (card->iobase)
|
||||
ioport_unmap(card->iobase);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CS);
|
||||
}
|
||||
|
||||
|
||||
@ -850,8 +821,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
|
||||
struct lbs_private *priv;
|
||||
struct if_cs_card *card;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
|
||||
if (!card)
|
||||
goto out;
|
||||
@ -961,7 +930,6 @@ out2:
|
||||
out1:
|
||||
pcmcia_disable_device(p_dev);
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -970,15 +938,11 @@ static void if_cs_detach(struct pcmcia_device *p_dev)
|
||||
{
|
||||
struct if_cs_card *card = p_dev->priv;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CS);
|
||||
|
||||
lbs_stop_card(card->priv);
|
||||
lbs_remove_card(card->priv);
|
||||
if_cs_disable_ints(card);
|
||||
if_cs_release(p_dev);
|
||||
kfree(card);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CS);
|
||||
}
|
||||
|
||||
|
||||
|
@ -211,8 +211,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
|
||||
unsigned long flags;
|
||||
u8 i;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
if (size > LBS_CMD_BUFFER_SIZE) {
|
||||
lbs_deb_sdio("response packet too large (%d bytes)\n",
|
||||
(int)size);
|
||||
@ -233,7 +231,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -244,8 +241,6 @@ static int if_sdio_handle_data(struct if_sdio_card *card,
|
||||
struct sk_buff *skb;
|
||||
char *data;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
|
||||
lbs_deb_sdio("response packet too large (%d bytes)\n",
|
||||
(int)size);
|
||||
@ -270,8 +265,6 @@ static int if_sdio_handle_data(struct if_sdio_card *card,
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -281,8 +274,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
|
||||
int ret;
|
||||
u32 event;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
if (card->model == MODEL_8385) {
|
||||
event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
|
||||
if (ret)
|
||||
@ -307,8 +298,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -337,8 +326,6 @@ static int if_sdio_card_to_host(struct if_sdio_card *card)
|
||||
int ret;
|
||||
u16 size, type, chunk;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
size = if_sdio_read_rx_len(card, &ret);
|
||||
if (ret)
|
||||
goto out;
|
||||
@ -410,8 +397,6 @@ out:
|
||||
if (ret)
|
||||
pr_err("problem fetching packet from firmware\n");
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -422,8 +407,6 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
card = container_of(work, struct if_sdio_card, packet_worker);
|
||||
|
||||
while (1) {
|
||||
@ -451,8 +434,6 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
|
||||
|
||||
kfree(packet);
|
||||
}
|
||||
|
||||
lbs_deb_leave(LBS_DEB_SDIO);
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
@ -471,8 +452,6 @@ static int if_sdio_prog_helper(struct if_sdio_card *card,
|
||||
const u8 *firmware;
|
||||
size_t size;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
chunk_buffer = kzalloc(64, GFP_KERNEL);
|
||||
if (!chunk_buffer) {
|
||||
ret = -ENOMEM;
|
||||
@ -556,7 +535,6 @@ out:
|
||||
if (ret)
|
||||
pr_err("failed to load helper firmware\n");
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -570,8 +548,6 @@ static int if_sdio_prog_real(struct if_sdio_card *card,
|
||||
const u8 *firmware;
|
||||
size_t size, req_size;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
chunk_buffer = kzalloc(512, GFP_KERNEL);
|
||||
if (!chunk_buffer) {
|
||||
ret = -ENOMEM;
|
||||
@ -691,7 +667,6 @@ out:
|
||||
if (ret)
|
||||
pr_err("failed to load firmware\n");
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -725,8 +700,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
|
||||
int ret;
|
||||
u16 scratch;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
/*
|
||||
* Disable interrupts
|
||||
*/
|
||||
@ -769,7 +742,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
|
||||
fw_table, if_sdio_do_prog_firmware);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -948,8 +920,6 @@ static int if_sdio_host_to_card(struct lbs_private *priv,
|
||||
u16 size;
|
||||
unsigned long flags;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb);
|
||||
|
||||
card = priv->card;
|
||||
|
||||
if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
|
||||
@ -1013,8 +983,6 @@ static int if_sdio_host_to_card(struct lbs_private *priv,
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1040,7 +1008,6 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
|
||||
struct if_sdio_card *card = priv->card;
|
||||
int ret = -1;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
sdio_claim_host(card->func);
|
||||
|
||||
sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
|
||||
@ -1048,7 +1015,7 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
|
||||
netdev_err(priv->dev, "sdio_writeb failed!\n");
|
||||
|
||||
sdio_release_host(card->func);
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1057,7 +1024,6 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
|
||||
struct if_sdio_card *card = priv->card;
|
||||
int ret = -1;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
sdio_claim_host(card->func);
|
||||
|
||||
sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
|
||||
@ -1065,7 +1031,7 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
|
||||
netdev_err(priv->dev, "sdio_writeb failed!\n");
|
||||
|
||||
sdio_release_host(card->func);
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
@ -1143,19 +1109,17 @@ static void if_sdio_interrupt(struct sdio_func *func)
|
||||
struct if_sdio_card *card;
|
||||
u8 cause;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
card = sdio_get_drvdata(func);
|
||||
|
||||
cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
|
||||
if (ret || !cause)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
|
||||
|
||||
sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
|
||||
if (ret)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
/*
|
||||
* Ignore the define name, this really means the card has
|
||||
@ -1169,13 +1133,8 @@ static void if_sdio_interrupt(struct sdio_func *func)
|
||||
if (cause & IF_SDIO_H_INT_UPLD) {
|
||||
ret = if_sdio_card_to_host(card);
|
||||
if (ret)
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
}
|
||||
|
||||
static int if_sdio_probe(struct sdio_func *func,
|
||||
@ -1187,8 +1146,6 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||
unsigned int model;
|
||||
struct if_sdio_packet *packet;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
for (i = 0;i < func->card->num_info;i++) {
|
||||
if (sscanf(func->card->info[i],
|
||||
"802.11 SDIO ID: %x", &model) == 1)
|
||||
@ -1273,8 +1230,6 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||
goto err_activate_card;
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
|
||||
err_activate_card:
|
||||
@ -1298,8 +1253,6 @@ static void if_sdio_remove(struct sdio_func *func)
|
||||
struct if_sdio_card *card;
|
||||
struct if_sdio_packet *packet;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
card = sdio_get_drvdata(func);
|
||||
|
||||
/* Undo decrement done above in if_sdio_probe */
|
||||
@ -1335,7 +1288,6 @@ static void if_sdio_remove(struct sdio_func *func)
|
||||
}
|
||||
|
||||
kfree(card);
|
||||
lbs_deb_leave(LBS_DEB_SDIO);
|
||||
}
|
||||
|
||||
static int if_sdio_suspend(struct device *dev)
|
||||
@ -1415,8 +1367,6 @@ static int __init if_sdio_init_module(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");
|
||||
printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");
|
||||
|
||||
@ -1425,23 +1375,17 @@ static int __init if_sdio_init_module(void)
|
||||
/* Clear the flag in case user removes the card. */
|
||||
user_rmmod = 0;
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit if_sdio_exit_module(void)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
/* Set the flag as user is removing this module. */
|
||||
user_rmmod = 1;
|
||||
|
||||
cancel_work_sync(&card_reset_work);
|
||||
|
||||
sdio_unregister_driver(&if_sdio_driver);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_SDIO);
|
||||
}
|
||||
|
||||
module_init(if_sdio_init_module);
|
||||
|
@ -466,8 +466,6 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
|
||||
const u8 *fw;
|
||||
u8 temp[HELPER_FW_LOAD_CHUNK_SZ];
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
|
||||
err = spu_set_interrupt_mode(card, 1, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -533,7 +531,7 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
|
||||
out:
|
||||
if (err)
|
||||
pr_err("failed to load helper firmware (err=%d)\n", err);
|
||||
lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -588,8 +586,6 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
|
||||
const u8 *fw;
|
||||
u16 num_crc_errs;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
|
||||
err = spu_set_interrupt_mode(card, 1, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -666,7 +662,7 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
|
||||
out:
|
||||
if (err)
|
||||
pr_err("failed to load firmware (err=%d)\n", err);
|
||||
lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -699,8 +695,6 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
|
||||
*/
|
||||
BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0);
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
|
||||
/* How many bytes are there to read? */
|
||||
err = spu_read_u16(card, IF_SPI_SCRATCH_2_REG, &len);
|
||||
if (err)
|
||||
@ -735,7 +729,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
|
||||
out:
|
||||
if (err)
|
||||
netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
|
||||
lbs_deb_leave(LBS_DEB_SPI);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -748,8 +742,6 @@ static int if_spi_c2h_data(struct if_spi_card *card)
|
||||
u16 len;
|
||||
int err = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
|
||||
/* How many bytes are there to read? */
|
||||
err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len);
|
||||
if (err)
|
||||
@ -794,7 +786,7 @@ free_skb:
|
||||
out:
|
||||
if (err)
|
||||
netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
|
||||
lbs_deb_leave(LBS_DEB_SPI);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -870,8 +862,6 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
|
||||
card = container_of(work, struct if_spi_card, packet_work);
|
||||
priv = card->priv;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
|
||||
/*
|
||||
* Read the host interrupt status register to see what we
|
||||
* can do.
|
||||
@ -943,8 +933,6 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
|
||||
err:
|
||||
if (err)
|
||||
netdev_err(priv->dev, "%s: got error %d\n", __func__, err);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_SPI);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -962,8 +950,6 @@ static int if_spi_host_to_card(struct lbs_private *priv,
|
||||
struct if_spi_packet *packet;
|
||||
u16 blen;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb);
|
||||
|
||||
if (nb == 0) {
|
||||
netdev_err(priv->dev, "%s: invalid size requested: %d\n",
|
||||
__func__, nb);
|
||||
@ -1004,7 +990,6 @@ static int if_spi_host_to_card(struct lbs_private *priv,
|
||||
/* Queue spi xfer work */
|
||||
queue_work(card->workqueue, &card->packet_work);
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1035,8 +1020,6 @@ static int if_spi_init_card(struct if_spi_card *card)
|
||||
const struct firmware *helper = NULL;
|
||||
const struct firmware *mainfw = NULL;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
|
||||
err = spu_init(card, card->pdata->use_dummy_writes);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -1093,7 +1076,6 @@ static int if_spi_init_card(struct if_spi_card *card)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1126,8 +1108,6 @@ static int if_spi_probe(struct spi_device *spi)
|
||||
struct libertas_spi_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||
int err = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
|
||||
if (!pdata) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
@ -1221,7 +1201,6 @@ teardown:
|
||||
if (pdata->teardown)
|
||||
pdata->teardown(spi);
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1231,7 +1210,6 @@ static int libertas_spi_remove(struct spi_device *spi)
|
||||
struct lbs_private *priv = card->priv;
|
||||
|
||||
lbs_deb_spi("libertas_spi_remove\n");
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
|
||||
cancel_work_sync(&card->resume_work);
|
||||
|
||||
@ -1243,7 +1221,7 @@ static int libertas_spi_remove(struct spi_device *spi)
|
||||
if (card->pdata->teardown)
|
||||
card->pdata->teardown(spi);
|
||||
free_if_spi_card(card);
|
||||
lbs_deb_leave(LBS_DEB_SPI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1297,18 +1275,16 @@ static struct spi_driver libertas_spi_driver = {
|
||||
static int __init if_spi_init_module(void)
|
||||
{
|
||||
int ret = 0;
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
|
||||
printk(KERN_INFO "libertas_spi: Libertas SPI driver\n");
|
||||
ret = spi_register_driver(&libertas_spi_driver);
|
||||
lbs_deb_leave(LBS_DEB_SPI);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit if_spi_exit_module(void)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_SPI);
|
||||
spi_unregister_driver(&libertas_spi_driver);
|
||||
lbs_deb_leave(LBS_DEB_SPI);
|
||||
}
|
||||
|
||||
module_init(if_spi_init_module);
|
||||
|
@ -111,8 +111,6 @@ static void if_usb_write_bulk_callback(struct urb *urb)
|
||||
*/
|
||||
static void if_usb_free(struct if_usb_card *cardp)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
/* Unlink tx & rx urb */
|
||||
usb_kill_urb(cardp->tx_urb);
|
||||
usb_kill_urb(cardp->rx_urb);
|
||||
@ -125,8 +123,6 @@ static void if_usb_free(struct if_usb_card *cardp)
|
||||
|
||||
kfree(cardp->ep_out_buf);
|
||||
cardp->ep_out_buf = NULL;
|
||||
|
||||
lbs_deb_leave(LBS_DEB_USB);
|
||||
}
|
||||
|
||||
static void if_usb_setup_firmware(struct lbs_private *priv)
|
||||
@ -306,8 +302,6 @@ static void if_usb_disconnect(struct usb_interface *intf)
|
||||
struct if_usb_card *cardp = usb_get_intfdata(intf);
|
||||
struct lbs_private *priv = cardp->priv;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
cardp->surprise_removed = 1;
|
||||
|
||||
if (priv) {
|
||||
@ -320,8 +314,6 @@ static void if_usb_disconnect(struct usb_interface *intf)
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
usb_put_dev(interface_to_usbdev(intf));
|
||||
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,8 +380,6 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
|
||||
struct cmd_header *cmd = cardp->ep_out_buf + 4;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
|
||||
|
||||
cmd->command = cpu_to_le16(CMD_802_11_RESET);
|
||||
@ -407,8 +397,6 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
|
||||
if_usb_reset_olpc_card(NULL);
|
||||
#endif
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -671,8 +659,6 @@ static void if_usb_receive(struct urb *urb)
|
||||
__le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
|
||||
uint32_t event;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
if (recvlength) {
|
||||
if (urb->status) {
|
||||
lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
|
||||
@ -688,7 +674,7 @@ static void if_usb_receive(struct urb *urb)
|
||||
recvlength, recvtype);
|
||||
} else if (urb->status) {
|
||||
kfree_skb(skb);
|
||||
goto rx_exit;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (recvtype) {
|
||||
@ -724,8 +710,6 @@ static void if_usb_receive(struct urb *urb)
|
||||
|
||||
setup_for_next:
|
||||
if_usb_submit_rx_urb(cardp);
|
||||
rx_exit:
|
||||
lbs_deb_leave(LBS_DEB_USB);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -835,8 +819,6 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
|
||||
int i = 0;
|
||||
static int reset_count = 10;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
if (ret) {
|
||||
pr_err("failed to find firmware (%d)\n", ret);
|
||||
goto done;
|
||||
@ -942,7 +924,6 @@ restart:
|
||||
|
||||
done:
|
||||
cardp->fw = NULL;
|
||||
lbs_deb_leave(LBS_DEB_USB);
|
||||
}
|
||||
|
||||
|
||||
@ -953,8 +934,6 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
struct lbs_private *priv = cardp->priv;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
if (priv->psstate != PS_STATE_FULL_POWER) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
@ -978,7 +957,6 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
usb_kill_urb(cardp->rx_urb);
|
||||
|
||||
out:
|
||||
lbs_deb_leave(LBS_DEB_USB);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -987,13 +965,10 @@ static int if_usb_resume(struct usb_interface *intf)
|
||||
struct if_usb_card *cardp = usb_get_intfdata(intf);
|
||||
struct lbs_private *priv = cardp->priv;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_USB);
|
||||
|
||||
if_usb_submit_rx_urb(cardp);
|
||||
|
||||
lbs_resume(priv);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_USB);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
@ -180,7 +180,6 @@ static int lbs_dev_open(struct net_device *dev)
|
||||
struct lbs_private *priv = dev->ml_priv;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_NET);
|
||||
if (!priv->iface_running) {
|
||||
ret = lbs_start_iface(priv);
|
||||
if (ret)
|
||||
@ -197,7 +196,6 @@ static int lbs_dev_open(struct net_device *dev)
|
||||
spin_unlock_irq(&priv->driver_lock);
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -216,8 +214,6 @@ int lbs_stop_iface(struct lbs_private *priv)
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
priv->iface_running = false;
|
||||
kfree_skb(priv->currenttxskb);
|
||||
@ -236,7 +232,6 @@ int lbs_stop_iface(struct lbs_private *priv)
|
||||
if (priv->power_save)
|
||||
ret = priv->power_save(priv);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -250,8 +245,6 @@ static int lbs_eth_stop(struct net_device *dev)
|
||||
{
|
||||
struct lbs_private *priv = dev->ml_priv;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_NET);
|
||||
|
||||
if (priv->connect_status == LBS_CONNECTED)
|
||||
lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING);
|
||||
|
||||
@ -269,7 +262,6 @@ static int lbs_eth_stop(struct net_device *dev)
|
||||
if (!lbs_iface_active(priv))
|
||||
lbs_stop_iface(priv);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_NET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -277,8 +269,6 @@ void lbs_host_to_card_done(struct lbs_private *priv)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_THREAD);
|
||||
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
del_timer(&priv->tx_lockup_timer);
|
||||
|
||||
@ -291,7 +281,6 @@ void lbs_host_to_card_done(struct lbs_private *priv)
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
lbs_deb_leave(LBS_DEB_THREAD);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
|
||||
|
||||
@ -301,8 +290,6 @@ int lbs_set_mac_address(struct net_device *dev, void *addr)
|
||||
struct lbs_private *priv = dev->ml_priv;
|
||||
struct sockaddr *phwaddr = addr;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_NET);
|
||||
|
||||
/*
|
||||
* Can only set MAC address when all interfaces are down, to be written
|
||||
* to the hardware when one of them is brought up.
|
||||
@ -318,7 +305,6 @@ int lbs_set_mac_address(struct net_device *dev, void *addr)
|
||||
if (priv->mesh_dev)
|
||||
memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -378,8 +364,6 @@ void lbs_update_mcast(struct lbs_private *priv)
|
||||
int nr_addrs;
|
||||
int old_mac_control = priv->mac_control;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_NET);
|
||||
|
||||
if (netif_running(priv->dev))
|
||||
dev_flags |= priv->dev->flags;
|
||||
if (priv->mesh_dev && netif_running(priv->mesh_dev))
|
||||
@ -424,8 +408,6 @@ void lbs_update_mcast(struct lbs_private *priv)
|
||||
out_set_mac_control:
|
||||
if (priv->mac_control != old_mac_control)
|
||||
lbs_set_mac_control(priv);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_NET);
|
||||
}
|
||||
|
||||
static void lbs_set_mcast_worker(struct work_struct *work)
|
||||
@ -455,8 +437,6 @@ static int lbs_thread(void *data)
|
||||
struct lbs_private *priv = dev->ml_priv;
|
||||
wait_queue_t wait;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_THREAD);
|
||||
|
||||
init_waitqueue_entry(&wait, current);
|
||||
|
||||
for (;;) {
|
||||
@ -648,7 +628,6 @@ static int lbs_thread(void *data)
|
||||
del_timer(&priv->tx_lockup_timer);
|
||||
del_timer(&priv->auto_deepsleep_timer);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_THREAD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -664,8 +643,6 @@ static int lbs_setup_firmware(struct lbs_private *priv)
|
||||
int ret = -1;
|
||||
s16 curlevel = 0, minlevel = 0, maxlevel = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_FW);
|
||||
|
||||
/* Read MAC address from firmware */
|
||||
eth_broadcast_addr(priv->current_addr);
|
||||
ret = lbs_update_hw_spec(priv);
|
||||
@ -687,7 +664,6 @@ static int lbs_setup_firmware(struct lbs_private *priv)
|
||||
|
||||
ret = lbs_set_mac_control_sync(priv);
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -695,8 +671,6 @@ int lbs_suspend(struct lbs_private *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_FW);
|
||||
|
||||
if (priv->is_deep_sleep) {
|
||||
ret = lbs_set_deep_sleep(priv, 0);
|
||||
if (ret) {
|
||||
@ -713,7 +687,6 @@ int lbs_suspend(struct lbs_private *priv)
|
||||
if (priv->mesh_dev)
|
||||
netif_device_detach(priv->mesh_dev);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_suspend);
|
||||
@ -722,8 +695,6 @@ int lbs_resume(struct lbs_private *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_FW);
|
||||
|
||||
ret = lbs_set_host_sleep(priv, 0);
|
||||
|
||||
netif_device_attach(priv->dev);
|
||||
@ -741,7 +712,6 @@ int lbs_resume(struct lbs_private *priv)
|
||||
if (priv->setup_fw_on_resume)
|
||||
ret = lbs_setup_firmware(priv);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_resume);
|
||||
@ -757,7 +727,6 @@ static void lbs_cmd_timeout_handler(unsigned long data)
|
||||
struct lbs_private *priv = (struct lbs_private *)data;
|
||||
unsigned long flags;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
if (!priv->cur_cmd)
|
||||
@ -778,7 +747,6 @@ static void lbs_cmd_timeout_handler(unsigned long data)
|
||||
wake_up(&priv->waitq);
|
||||
out:
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -793,7 +761,6 @@ static void lbs_tx_lockup_handler(unsigned long data)
|
||||
struct lbs_private *priv = (struct lbs_private *)data;
|
||||
unsigned long flags;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_TX);
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
netdev_info(priv->dev, "TX lockup detected\n");
|
||||
@ -804,7 +771,6 @@ static void lbs_tx_lockup_handler(unsigned long data)
|
||||
wake_up_interruptible(&priv->waitq);
|
||||
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
lbs_deb_leave(LBS_DEB_TX);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -817,8 +783,6 @@ static void auto_deepsleep_timer_fn(unsigned long data)
|
||||
{
|
||||
struct lbs_private *priv = (struct lbs_private *)data;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
if (priv->is_activity_detected) {
|
||||
priv->is_activity_detected = 0;
|
||||
} else {
|
||||
@ -836,32 +800,25 @@ static void auto_deepsleep_timer_fn(unsigned long data)
|
||||
}
|
||||
mod_timer(&priv->auto_deepsleep_timer , jiffies +
|
||||
(priv->auto_deep_sleep_timeout * HZ)/1000);
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
}
|
||||
|
||||
int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
priv->is_auto_deep_sleep_enabled = 1;
|
||||
if (priv->is_deep_sleep)
|
||||
priv->wakeup_dev_required = 1;
|
||||
mod_timer(&priv->auto_deepsleep_timer ,
|
||||
jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_SDIO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_SDIO);
|
||||
|
||||
priv->is_auto_deep_sleep_enabled = 0;
|
||||
priv->auto_deep_sleep_timeout = 0;
|
||||
del_timer(&priv->auto_deepsleep_timer);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_SDIO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -869,8 +826,6 @@ static int lbs_init_adapter(struct lbs_private *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
eth_broadcast_addr(priv->current_addr);
|
||||
|
||||
priv->connect_status = LBS_DISCONNECTED;
|
||||
@ -921,22 +876,16 @@ static int lbs_init_adapter(struct lbs_private *priv)
|
||||
}
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lbs_free_adapter(struct lbs_private *priv)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
lbs_free_cmd_buffer(priv);
|
||||
kfifo_free(&priv->event_fifo);
|
||||
del_timer(&priv->command_timer);
|
||||
del_timer(&priv->tx_lockup_timer);
|
||||
del_timer(&priv->auto_deepsleep_timer);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
}
|
||||
|
||||
static const struct net_device_ops lbs_netdev_ops = {
|
||||
@ -962,8 +911,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
|
||||
struct wireless_dev *wdev;
|
||||
struct lbs_private *priv = NULL;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
/* Allocate an Ethernet device and register it */
|
||||
wdev = lbs_cfg_alloc(dmdev);
|
||||
if (IS_ERR(wdev)) {
|
||||
@ -1031,7 +978,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
|
||||
priv = NULL;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv);
|
||||
return priv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_add_card);
|
||||
@ -1041,8 +987,6 @@ void lbs_remove_card(struct lbs_private *priv)
|
||||
{
|
||||
struct net_device *dev = priv->dev;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
lbs_remove_mesh(priv);
|
||||
|
||||
if (priv->wiphy_registered)
|
||||
@ -1083,8 +1027,6 @@ void lbs_remove_card(struct lbs_private *priv)
|
||||
lbs_free_adapter(priv);
|
||||
lbs_cfg_free(priv);
|
||||
free_netdev(dev);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_remove_card);
|
||||
|
||||
@ -1105,8 +1047,6 @@ int lbs_start_card(struct lbs_private *priv)
|
||||
struct net_device *dev = priv->dev;
|
||||
int ret = -1;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
/* poke the firmware */
|
||||
ret = lbs_setup_firmware(priv);
|
||||
if (ret)
|
||||
@ -1133,7 +1073,6 @@ int lbs_start_card(struct lbs_private *priv)
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_start_card);
|
||||
@ -1143,16 +1082,14 @@ void lbs_stop_card(struct lbs_private *priv)
|
||||
{
|
||||
struct net_device *dev;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
|
||||
if (!priv)
|
||||
goto out;
|
||||
return;
|
||||
dev = priv->dev;
|
||||
|
||||
/* If the netdev isn't registered, it means that lbs_start_card() was
|
||||
* never called so we have nothing to do here. */
|
||||
if (dev->reg_state != NETREG_REGISTERED)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
netif_stop_queue(dev);
|
||||
netif_carrier_off(dev);
|
||||
@ -1160,9 +1097,6 @@ void lbs_stop_card(struct lbs_private *priv)
|
||||
lbs_debugfs_remove_one(priv);
|
||||
lbs_deinit_mesh(priv);
|
||||
unregister_netdev(dev);
|
||||
|
||||
out:
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_stop_card);
|
||||
|
||||
@ -1171,7 +1105,6 @@ void lbs_queue_event(struct lbs_private *priv, u32 event)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_THREAD);
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
|
||||
if (priv->psstate == PS_STATE_SLEEP)
|
||||
@ -1182,14 +1115,11 @@ void lbs_queue_event(struct lbs_private *priv, u32 event)
|
||||
wake_up(&priv->waitq);
|
||||
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
lbs_deb_leave(LBS_DEB_THREAD);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_queue_event);
|
||||
|
||||
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_THREAD);
|
||||
|
||||
if (priv->psstate == PS_STATE_SLEEP)
|
||||
priv->psstate = PS_STATE_AWAKE;
|
||||
|
||||
@ -1198,28 +1128,23 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
|
||||
priv->resp_idx = resp_idx;
|
||||
|
||||
wake_up(&priv->waitq);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_THREAD);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_notify_command_response);
|
||||
|
||||
static int __init lbs_init_module(void)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
memset(&confirm_sleep, 0, sizeof(confirm_sleep));
|
||||
confirm_sleep.hdr.command = cpu_to_le16(CMD_802_11_PS_MODE);
|
||||
confirm_sleep.hdr.size = cpu_to_le16(sizeof(confirm_sleep));
|
||||
confirm_sleep.action = cpu_to_le16(PS_MODE_ACTION_SLEEP_CONFIRMED);
|
||||
lbs_debugfs_init();
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit lbs_exit_module(void)
|
||||
{
|
||||
lbs_deb_enter(LBS_DEB_MAIN);
|
||||
lbs_debugfs_remove();
|
||||
lbs_deb_leave(LBS_DEB_MAIN);
|
||||
}
|
||||
|
||||
module_init(lbs_init_module);
|
||||
|
@ -26,8 +26,6 @@ static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
|
||||
{
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
|
||||
|
||||
cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
|
||||
cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
|
||||
cmd->hdr.result = 0;
|
||||
@ -36,7 +34,6 @@ static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
|
||||
|
||||
ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -47,8 +44,6 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
|
||||
int ret;
|
||||
u16 command = CMD_MESH_CONFIG_OLD;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_CMD);
|
||||
|
||||
/*
|
||||
* Command id is 0xac for v10 FW along with mesh interface
|
||||
* id in bits 14-13-12.
|
||||
@ -66,7 +61,6 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
|
||||
|
||||
ret = lbs_cmd_with_response(priv, command, cmd);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_CMD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -823,8 +817,6 @@ int lbs_init_mesh(struct lbs_private *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MESH);
|
||||
|
||||
/* Determine mesh_fw_ver from fwrelease and fwcapinfo */
|
||||
/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
|
||||
/* 5.110.22 have mesh command with 0xa3 command id */
|
||||
@ -870,7 +862,6 @@ int lbs_init_mesh(struct lbs_private *priv)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -887,14 +878,11 @@ int lbs_deinit_mesh(struct lbs_private *priv)
|
||||
struct net_device *dev = priv->dev;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MESH);
|
||||
|
||||
if (priv->mesh_tlv) {
|
||||
device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -909,7 +897,6 @@ static int lbs_mesh_stop(struct net_device *dev)
|
||||
{
|
||||
struct lbs_private *priv = dev->ml_priv;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MESH);
|
||||
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
|
||||
lbs_mesh_get_channel(priv));
|
||||
|
||||
@ -924,7 +911,6 @@ static int lbs_mesh_stop(struct net_device *dev)
|
||||
if (!lbs_iface_active(priv))
|
||||
lbs_stop_iface(priv);
|
||||
|
||||
lbs_deb_leave(LBS_DEB_MESH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -939,7 +925,6 @@ static int lbs_mesh_dev_open(struct net_device *dev)
|
||||
struct lbs_private *priv = dev->ml_priv;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_NET);
|
||||
if (!priv->iface_running) {
|
||||
ret = lbs_start_iface(priv);
|
||||
if (ret)
|
||||
@ -965,7 +950,6 @@ static int lbs_mesh_dev_open(struct net_device *dev)
|
||||
lbs_mesh_get_channel(priv));
|
||||
|
||||
out:
|
||||
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -989,8 +973,6 @@ static int lbs_add_mesh(struct lbs_private *priv)
|
||||
struct wireless_dev *mesh_wdev;
|
||||
int ret = 0;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MESH);
|
||||
|
||||
/* Allocate a virtual mesh device */
|
||||
mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
|
||||
if (!mesh_wdev) {
|
||||
@ -1048,7 +1030,6 @@ err_free_wdev:
|
||||
kfree(mesh_wdev);
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1060,7 +1041,6 @@ void lbs_remove_mesh(struct lbs_private *priv)
|
||||
if (!mesh_dev)
|
||||
return;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_MESH);
|
||||
netif_stop_queue(mesh_dev);
|
||||
netif_carrier_off(mesh_dev);
|
||||
sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
|
||||
@ -1069,7 +1049,6 @@ void lbs_remove_mesh(struct lbs_private *priv)
|
||||
priv->mesh_dev = NULL;
|
||||
kfree(mesh_dev->ieee80211_ptr);
|
||||
free_netdev(mesh_dev);
|
||||
lbs_deb_leave(LBS_DEB_MESH);
|
||||
}
|
||||
|
||||
|
||||
@ -1108,15 +1087,15 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
|
||||
* Ethtool related
|
||||
*/
|
||||
|
||||
static const char * const mesh_stat_strings[] = {
|
||||
"drop_duplicate_bcast",
|
||||
"drop_ttl_zero",
|
||||
"drop_no_fwd_route",
|
||||
"drop_no_buffers",
|
||||
"fwded_unicast_cnt",
|
||||
"fwded_bcast_cnt",
|
||||
"drop_blind_table",
|
||||
"tx_failed_cnt"
|
||||
static const char mesh_stat_strings[MESH_STATS_NUM][ETH_GSTRING_LEN] = {
|
||||
"drop_duplicate_bcast",
|
||||
"drop_ttl_zero",
|
||||
"drop_no_fwd_route",
|
||||
"drop_no_buffers",
|
||||
"fwded_unicast_cnt",
|
||||
"fwded_bcast_cnt",
|
||||
"drop_blind_table",
|
||||
"tx_failed_cnt"
|
||||
};
|
||||
|
||||
void lbs_mesh_ethtool_get_stats(struct net_device *dev,
|
||||
@ -1126,8 +1105,6 @@ void lbs_mesh_ethtool_get_stats(struct net_device *dev,
|
||||
struct cmd_ds_mesh_access mesh_access;
|
||||
int ret;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ETHTOOL);
|
||||
|
||||
/* Get Mesh Statistics */
|
||||
ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
|
||||
|
||||
@ -1153,8 +1130,6 @@ void lbs_mesh_ethtool_get_stats(struct net_device *dev,
|
||||
data[5] = priv->mstats.fwd_bcast_cnt;
|
||||
data[6] = priv->mstats.drop_blind;
|
||||
data[7] = priv->mstats.tx_failed_cnt;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ETHTOOL);
|
||||
}
|
||||
|
||||
int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
|
||||
@ -1170,18 +1145,9 @@ int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
|
||||
void lbs_mesh_ethtool_get_strings(struct net_device *dev,
|
||||
uint32_t stringset, uint8_t *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_ETHTOOL);
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
for (i = 0; i < MESH_STATS_NUM; i++) {
|
||||
memcpy(s + i * ETH_GSTRING_LEN,
|
||||
mesh_stat_strings[i],
|
||||
ETH_GSTRING_LEN);
|
||||
}
|
||||
memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings));
|
||||
break;
|
||||
}
|
||||
lbs_deb_enter(LBS_DEB_ETHTOOL);
|
||||
}
|
||||
|
@ -65,8 +65,6 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
|
||||
0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
lbs_deb_enter(LBS_DEB_RX);
|
||||
|
||||
BUG_ON(!skb);
|
||||
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
@ -158,7 +156,6 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
|
||||
@ -221,8 +218,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
|
||||
struct rx_radiotap_hdr radiotap_hdr;
|
||||
struct rx_radiotap_hdr *pradiotap_hdr;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_RX);
|
||||
|
||||
p_rx_pkt = (struct rx80211packethdr *) skb->data;
|
||||
prxpd = &p_rx_pkt->rx_pd;
|
||||
|
||||
@ -281,6 +276,5 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -70,8 +70,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
uint16_t pkt_len;
|
||||
netdev_tx_t ret = NETDEV_TX_OK;
|
||||
|
||||
lbs_deb_enter(LBS_DEB_TX);
|
||||
|
||||
/* We need to protect against the queues being restarted before
|
||||
we get round to stopping them */
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
@ -166,7 +164,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
wake_up(&priv->waitq);
|
||||
|
||||
lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -128,9 +128,6 @@ void mwifiex_dfs_cac_work_queue(struct work_struct *work)
|
||||
container_of(delayed_work, struct mwifiex_private,
|
||||
dfs_cac_work);
|
||||
|
||||
if (WARN_ON(!priv))
|
||||
return;
|
||||
|
||||
chandef = priv->dfs_chandef;
|
||||
if (priv->wdev.cac_started) {
|
||||
mwifiex_dbg(priv->adapter, MSG,
|
||||
@ -289,9 +286,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
|
||||
container_of(delayed_work, struct mwifiex_private,
|
||||
dfs_chan_sw_work);
|
||||
|
||||
if (WARN_ON(!priv))
|
||||
return;
|
||||
|
||||
bss_cfg = &priv->bss_cfg;
|
||||
if (!bss_cfg->beacon_period) {
|
||||
mwifiex_dbg(priv->adapter, ERROR,
|
||||
|
@ -653,11 +653,13 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
|
||||
void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
|
||||
{
|
||||
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
|
||||
if (list_empty(&priv->rx_reorder_tbl_ptr)) {
|
||||
dev_dbg(priv->adapter->dev,
|
||||
"mwifiex_11n_delba: rx_reorder_tbl_ptr empty\n");
|
||||
return;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
|
||||
@ -666,9 +668,11 @@ void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
|
||||
"Send delba to tid=%d, %pM\n",
|
||||
tid, rx_reor_tbl_ptr->ta);
|
||||
mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0);
|
||||
return;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -764,14 +768,9 @@ void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
|
||||
list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) {
|
||||
if (!memcmp(tbl->ra, ra, ETH_ALEN)) {
|
||||
spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
|
||||
flags);
|
||||
list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list)
|
||||
if (!memcmp(tbl->ra, ra, ETH_ALEN))
|
||||
mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl);
|
||||
spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
|
||||
|
||||
return;
|
||||
|
@ -164,7 +164,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
|
||||
int pad = 0, aggr_num = 0, ret;
|
||||
struct mwifiex_tx_param tx_param;
|
||||
struct txpd *ptx_pd = NULL;
|
||||
int headroom = adapter->iface_type == MWIFIEX_USB ? 0 : INTF_HEADER_LEN;
|
||||
int headroom = adapter->intf_hdr_len;
|
||||
|
||||
skb_src = skb_peek(&pra_list->skb_head);
|
||||
if (!skb_src) {
|
||||
@ -250,15 +250,15 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (skb_src)
|
||||
tx_param.next_pkt_len = skb_src->len + sizeof(struct txpd);
|
||||
else
|
||||
tx_param.next_pkt_len = 0;
|
||||
|
||||
if (adapter->iface_type == MWIFIEX_USB) {
|
||||
ret = adapter->if_ops.host_to_card(adapter, priv->usb_port,
|
||||
skb_aggr, NULL);
|
||||
skb_aggr, &tx_param);
|
||||
} else {
|
||||
if (skb_src)
|
||||
tx_param.next_pkt_len =
|
||||
skb_src->len + sizeof(struct txpd);
|
||||
else
|
||||
tx_param.next_pkt_len = 0;
|
||||
|
||||
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
|
||||
skb_aggr, &tx_param);
|
||||
|
@ -2964,10 +2964,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
if (!dev) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"no memory available for netdevice\n");
|
||||
memset(&priv->wdev, 0, sizeof(priv->wdev));
|
||||
priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_netdev;
|
||||
}
|
||||
|
||||
mwifiex_init_priv_params(priv, dev);
|
||||
@ -2976,11 +2974,11 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
|
||||
HostCmd_ACT_GEN_SET, 0, NULL, true);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
goto err_set_bss_mode;
|
||||
|
||||
ret = mwifiex_sta_init_cmd(priv, false, false);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
goto err_sta_init;
|
||||
|
||||
mwifiex_setup_ht_caps(&wiphy->bands[NL80211_BAND_2GHZ]->ht_cap, priv);
|
||||
if (adapter->is_hw_11ac_capable)
|
||||
@ -3011,31 +3009,14 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
|
||||
SET_NETDEV_DEV(dev, adapter->dev);
|
||||
|
||||
/* Register network device */
|
||||
if (register_netdevice(dev)) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"cannot register virtual network device\n");
|
||||
free_netdev(dev);
|
||||
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
|
||||
priv->netdev = NULL;
|
||||
memset(&priv->wdev, 0, sizeof(priv->wdev));
|
||||
priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
return ERR_PTR(-EFAULT);
|
||||
}
|
||||
|
||||
priv->dfs_cac_workqueue = alloc_workqueue("MWIFIEX_DFS_CAC%s",
|
||||
WQ_HIGHPRI |
|
||||
WQ_MEM_RECLAIM |
|
||||
WQ_UNBOUND, 1, name);
|
||||
if (!priv->dfs_cac_workqueue) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"cannot register virtual network device\n");
|
||||
free_netdev(dev);
|
||||
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
|
||||
priv->netdev = NULL;
|
||||
memset(&priv->wdev, 0, sizeof(priv->wdev));
|
||||
priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
mwifiex_dbg(adapter, ERROR, "cannot alloc DFS CAC queue\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_cac;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue);
|
||||
@ -3044,16 +3025,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
WQ_HIGHPRI | WQ_UNBOUND |
|
||||
WQ_MEM_RECLAIM, 1, name);
|
||||
if (!priv->dfs_chan_sw_workqueue) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"cannot register virtual network device\n");
|
||||
free_netdev(dev);
|
||||
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
|
||||
priv->netdev = NULL;
|
||||
memset(&priv->wdev, 0, sizeof(priv->wdev));
|
||||
priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
destroy_workqueue(priv->dfs_cac_workqueue);
|
||||
priv->dfs_cac_workqueue = NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
mwifiex_dbg(adapter, ERROR, "cannot alloc DFS channel sw queue\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_chsw;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&priv->dfs_chan_sw_work,
|
||||
@ -3061,6 +3035,13 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
|
||||
sema_init(&priv->async_sem, 1);
|
||||
|
||||
/* Register network device */
|
||||
if (register_netdevice(dev)) {
|
||||
mwifiex_dbg(adapter, ERROR, "cannot register network device\n");
|
||||
ret = -EFAULT;
|
||||
goto err_reg_netdev;
|
||||
}
|
||||
|
||||
mwifiex_dbg(adapter, INFO,
|
||||
"info: %s: Marvell 802.11 Adapter\n", dev->name);
|
||||
|
||||
@ -3081,11 +3062,29 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
adapter->curr_iface_comb.p2p_intf++;
|
||||
break;
|
||||
default:
|
||||
/* This should be dead code; checked above */
|
||||
mwifiex_dbg(adapter, ERROR, "type not supported\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return &priv->wdev;
|
||||
|
||||
err_reg_netdev:
|
||||
destroy_workqueue(priv->dfs_chan_sw_workqueue);
|
||||
priv->dfs_chan_sw_workqueue = NULL;
|
||||
err_alloc_chsw:
|
||||
destroy_workqueue(priv->dfs_cac_workqueue);
|
||||
priv->dfs_cac_workqueue = NULL;
|
||||
err_alloc_cac:
|
||||
free_netdev(dev);
|
||||
priv->netdev = NULL;
|
||||
err_sta_init:
|
||||
err_set_bss_mode:
|
||||
err_alloc_netdev:
|
||||
memset(&priv->wdev, 0, sizeof(priv->wdev));
|
||||
priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
|
||||
|
||||
|
@ -258,10 +258,10 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
|
||||
if (ret == -EBUSY)
|
||||
cmd_node->cmd_skb = NULL;
|
||||
} else {
|
||||
skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN);
|
||||
skb_push(cmd_node->cmd_skb, adapter->intf_hdr_len);
|
||||
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
|
||||
cmd_node->cmd_skb, NULL);
|
||||
skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN);
|
||||
skb_pull(cmd_node->cmd_skb, adapter->intf_hdr_len);
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
@ -351,10 +351,10 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
|
||||
if (ret != -EBUSY)
|
||||
dev_kfree_skb_any(sleep_cfm_tmp);
|
||||
} else {
|
||||
skb_push(adapter->sleep_cfm, INTF_HEADER_LEN);
|
||||
skb_push(adapter->sleep_cfm, adapter->intf_hdr_len);
|
||||
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
|
||||
adapter->sleep_cfm, NULL);
|
||||
skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN);
|
||||
skb_pull(adapter->sleep_cfm, adapter->intf_hdr_len);
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
@ -761,8 +761,6 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
|
||||
}
|
||||
cmd_node = list_first_entry(&adapter->cmd_pending_q,
|
||||
struct cmd_ctrl_node, list);
|
||||
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
|
||||
cmd_pending_q_flags);
|
||||
|
||||
host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
|
||||
priv = cmd_node->priv;
|
||||
@ -771,11 +769,12 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"%s: cannot send cmd in sleep state,\t"
|
||||
"this should not happen\n", __func__);
|
||||
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
|
||||
cmd_pending_q_flags);
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
|
||||
list_del(&cmd_node->list);
|
||||
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
|
||||
cmd_pending_q_flags);
|
||||
@ -1056,12 +1055,10 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
|
||||
list_for_each_entry_safe(cmd_node, tmp_node,
|
||||
&adapter->cmd_pending_q, list) {
|
||||
list_del(&cmd_node->list);
|
||||
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
|
||||
|
||||
if (cmd_node->wait_q_enabled)
|
||||
adapter->cmd_wait_q.status = -1;
|
||||
mwifiex_recycle_cmd_node(adapter, cmd_node);
|
||||
spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
|
@ -405,6 +405,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
|
||||
#define HostCmd_CMD_TDLS_OPER 0x0122
|
||||
#define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223
|
||||
#define HostCmd_CMD_CHAN_REGION_CFG 0x0242
|
||||
#define HostCmd_CMD_PACKET_AGGR_CTRL 0x0251
|
||||
|
||||
#define PROTOCOL_NO_SECURITY 0x01
|
||||
#define PROTOCOL_STATIC_WEP 0x02
|
||||
@ -2268,6 +2269,14 @@ struct host_cmd_ds_chan_region_cfg {
|
||||
__le16 action;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_pkt_aggr_ctrl {
|
||||
__le16 action;
|
||||
__le16 enable;
|
||||
__le16 tx_aggr_max_size;
|
||||
__le16 tx_aggr_max_num;
|
||||
__le16 tx_aggr_align;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_command {
|
||||
__le16 command;
|
||||
__le16 size;
|
||||
@ -2343,6 +2352,7 @@ struct host_cmd_ds_command {
|
||||
struct host_cmd_ds_wakeup_reason hs_wakeup_reason;
|
||||
struct host_cmd_ds_gtk_rekey_params rekey;
|
||||
struct host_cmd_ds_chan_region_cfg reg_cfg;
|
||||
struct host_cmd_ds_pkt_aggr_ctrl pkt_aggr_ctrl;
|
||||
} params;
|
||||
} __packed;
|
||||
|
||||
|
@ -217,6 +217,11 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
|
||||
else
|
||||
adapter->data_sent = false;
|
||||
|
||||
if (adapter->iface_type == MWIFIEX_USB)
|
||||
adapter->intf_hdr_len = 0;
|
||||
else
|
||||
adapter->intf_hdr_len = INTF_HEADER_LEN;
|
||||
|
||||
adapter->cmd_resp_received = false;
|
||||
adapter->event_received = false;
|
||||
adapter->data_received = false;
|
||||
@ -409,11 +414,6 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
|
||||
static void
|
||||
mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
if (!adapter) {
|
||||
pr_err("%s: adapter is NULL\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
del_timer(&adapter->wakeup_timer);
|
||||
mwifiex_cancel_all_pending_cmd(adapter);
|
||||
wake_up_interruptible(&adapter->cmd_wait_q.wait);
|
||||
@ -439,7 +439,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
|
||||
struct mwifiex_private *priv;
|
||||
s32 i, j;
|
||||
|
||||
spin_lock_init(&adapter->mwifiex_lock);
|
||||
spin_lock_init(&adapter->int_lock);
|
||||
spin_lock_init(&adapter->main_proc_lock);
|
||||
spin_lock_init(&adapter->mwifiex_cmd_lock);
|
||||
@ -670,8 +669,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
|
||||
|
||||
mwifiex_clean_auto_tdls(priv);
|
||||
mwifiex_abort_cac(priv);
|
||||
mwifiex_clean_txrx(priv);
|
||||
mwifiex_delete_bss_prio_tbl(priv);
|
||||
mwifiex_free_priv(priv);
|
||||
}
|
||||
}
|
||||
|
||||
@ -694,11 +692,8 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
|
||||
|
||||
spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
|
||||
|
||||
spin_lock(&adapter->mwifiex_lock);
|
||||
|
||||
mwifiex_adapter_cleanup(adapter);
|
||||
|
||||
spin_unlock(&adapter->mwifiex_lock);
|
||||
adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY;
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,10 @@ bool mfg_mode;
|
||||
module_param(mfg_mode, bool, 0);
|
||||
MODULE_PARM_DESC(mfg_mode, "manufacturing mode enable:1, disable:0");
|
||||
|
||||
bool aggr_ctrl;
|
||||
module_param(aggr_ctrl, bool, 0000);
|
||||
MODULE_PARM_DESC(aggr_ctrl, "usb tx aggreataon enable:1, disable:0");
|
||||
|
||||
/*
|
||||
* This function registers the device and performs all the necessary
|
||||
* initializations.
|
||||
|
@ -60,6 +60,7 @@
|
||||
|
||||
extern const char driver_version[];
|
||||
extern bool mfg_mode;
|
||||
extern bool aggr_ctrl;
|
||||
|
||||
struct mwifiex_adapter;
|
||||
struct mwifiex_private;
|
||||
@ -798,6 +799,18 @@ struct mwifiex_auto_tdls_peer {
|
||||
u8 do_setup;
|
||||
};
|
||||
|
||||
#define MWIFIEX_TYPE_AGGR_DATA_V2 11
|
||||
#define MWIFIEX_BUS_AGGR_MODE_LEN_V2 (2)
|
||||
#define MWIFIEX_BUS_AGGR_MAX_LEN 16000
|
||||
#define MWIFIEX_BUS_AGGR_MAX_NUM 10
|
||||
struct bus_aggr_params {
|
||||
u16 enable;
|
||||
u16 mode;
|
||||
u16 tx_aggr_max_size;
|
||||
u16 tx_aggr_max_num;
|
||||
u16 tx_aggr_align;
|
||||
};
|
||||
|
||||
struct mwifiex_if_ops {
|
||||
int (*init_if) (struct mwifiex_adapter *);
|
||||
void (*cleanup_if) (struct mwifiex_adapter *);
|
||||
@ -849,6 +862,7 @@ struct mwifiex_adapter {
|
||||
u8 perm_addr[ETH_ALEN];
|
||||
bool surprise_removed;
|
||||
u32 fw_release_number;
|
||||
u8 intf_hdr_len;
|
||||
u16 init_wait_q_woken;
|
||||
wait_queue_head_t init_wait_q;
|
||||
void *card;
|
||||
@ -870,8 +884,6 @@ struct mwifiex_adapter {
|
||||
bool rx_locked;
|
||||
bool main_locked;
|
||||
struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
|
||||
/* spin lock for init/shutdown */
|
||||
spinlock_t mwifiex_lock;
|
||||
/* spin lock for main process */
|
||||
spinlock_t main_proc_lock;
|
||||
u32 mwifiex_processing;
|
||||
@ -1017,6 +1029,8 @@ struct mwifiex_adapter {
|
||||
/* Wake-on-WLAN (WoWLAN) */
|
||||
int irq_wakeup;
|
||||
bool wake_by_wifi;
|
||||
/* Aggregation parameters*/
|
||||
struct bus_aggr_params bus_aggr;
|
||||
};
|
||||
|
||||
void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
|
||||
@ -1235,7 +1249,8 @@ mwifiex_queuing_ra_based(struct mwifiex_private *priv)
|
||||
* Currently we assume if we are in Infra, then DA=RA. This might not be
|
||||
* true in the future
|
||||
*/
|
||||
if ((priv->bss_mode == NL80211_IFTYPE_STATION) &&
|
||||
if ((priv->bss_mode == NL80211_IFTYPE_STATION ||
|
||||
priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) &&
|
||||
(GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA))
|
||||
return false;
|
||||
|
||||
|
@ -370,7 +370,6 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
|
||||
* PCIe and HW.
|
||||
*/
|
||||
mwifiex_shutdown_sw(adapter);
|
||||
adapter->surprise_removed = true;
|
||||
clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
|
||||
clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
|
||||
} else {
|
||||
@ -378,7 +377,6 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
|
||||
* after performing FLR respectively. Reconfigure the software
|
||||
* and firmware including firmware redownload
|
||||
*/
|
||||
adapter->surprise_removed = false;
|
||||
ret = mwifiex_reinit_sw(adapter);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "reinit failed: %d\n", ret);
|
||||
@ -1391,7 +1389,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
|
||||
* first 2 bytes for len, next 2 bytes is for type
|
||||
*/
|
||||
rx_len = get_unaligned_le16(skb_data->data);
|
||||
if (WARN_ON(rx_len <= INTF_HEADER_LEN ||
|
||||
if (WARN_ON(rx_len <= adapter->intf_hdr_len ||
|
||||
rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"Invalid RX len %d, Rd=%#x, Wr=%#x\n",
|
||||
@ -1402,7 +1400,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
|
||||
mwifiex_dbg(adapter, DATA,
|
||||
"info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
|
||||
card->rxbd_rdptr, wrptr, rx_len);
|
||||
skb_pull(skb_data, INTF_HEADER_LEN);
|
||||
skb_pull(skb_data, adapter->intf_hdr_len);
|
||||
if (adapter->rx_work_enabled) {
|
||||
skb_queue_tail(&adapter->rx_data_q, skb_data);
|
||||
adapter->data_received = true;
|
||||
@ -1736,7 +1734,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
|
||||
MWIFIEX_MAX_DELAY_COUNT);
|
||||
mwifiex_unmap_pci_memory(adapter, skb,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
skb_pull(skb, INTF_HEADER_LEN);
|
||||
skb_pull(skb, adapter->intf_hdr_len);
|
||||
while (reg->sleep_cookie && (count++ < 10) &&
|
||||
mwifiex_pcie_ok_to_access_hw(adapter))
|
||||
usleep_range(50, 60);
|
||||
@ -1749,12 +1747,12 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
|
||||
}
|
||||
memcpy(adapter->upld_buf, skb->data,
|
||||
min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
|
||||
skb_push(skb, INTF_HEADER_LEN);
|
||||
skb_push(skb, adapter->intf_hdr_len);
|
||||
if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
|
||||
PCI_DMA_FROMDEVICE))
|
||||
return -1;
|
||||
} else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
|
||||
skb_pull(skb, INTF_HEADER_LEN);
|
||||
skb_pull(skb, adapter->intf_hdr_len);
|
||||
adapter->curr_cmd->resp_skb = skb;
|
||||
adapter->cmd_resp_received = true;
|
||||
/* Take the pointer and set it to CMD node and will
|
||||
@ -1791,7 +1789,7 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
|
||||
|
||||
if (skb) {
|
||||
card->cmdrsp_buf = skb;
|
||||
skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
|
||||
skb_push(card->cmdrsp_buf, adapter->intf_hdr_len);
|
||||
if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
|
||||
PCI_DMA_FROMDEVICE))
|
||||
return -1;
|
||||
@ -1856,14 +1854,15 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
|
||||
desc = card->evtbd_ring[rdptr];
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
|
||||
event = get_unaligned_le32(&skb_cmd->data[INTF_HEADER_LEN]);
|
||||
event = get_unaligned_le32(
|
||||
&skb_cmd->data[adapter->intf_hdr_len]);
|
||||
adapter->event_cause = event;
|
||||
/* The first 4bytes will be the event transfer header
|
||||
len is 2 bytes followed by type which is 2 bytes */
|
||||
memcpy(&data_len, skb_cmd->data, sizeof(__le16));
|
||||
evt_len = le16_to_cpu(data_len);
|
||||
skb_trim(skb_cmd, evt_len);
|
||||
skb_pull(skb_cmd, INTF_HEADER_LEN);
|
||||
skb_pull(skb_cmd, adapter->intf_hdr_len);
|
||||
mwifiex_dbg(adapter, EVENT,
|
||||
"info: Event length: %d\n", evt_len);
|
||||
|
||||
@ -1922,7 +1921,7 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
|
||||
}
|
||||
|
||||
if (!card->evt_buf_list[rdptr]) {
|
||||
skb_push(skb, INTF_HEADER_LEN);
|
||||
skb_push(skb, adapter->intf_hdr_len);
|
||||
skb_put(skb, MAX_EVENT_SIZE - skb->len);
|
||||
if (mwifiex_map_pci_memory(adapter, skb,
|
||||
MAX_EVENT_SIZE,
|
||||
@ -2380,11 +2379,6 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
|
||||
struct pcie_service_card *card;
|
||||
struct mwifiex_adapter *adapter;
|
||||
|
||||
if (!pdev) {
|
||||
pr_err("info: %s: pdev is NULL\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
card = pci_get_drvdata(pdev);
|
||||
|
||||
if (!card->adapter) {
|
||||
@ -2822,6 +2816,13 @@ static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter)
|
||||
mwifiex_upload_device_dump(adapter, drv_info, drv_info_size);
|
||||
}
|
||||
|
||||
static void mwifiex_pcie_card_reset_work(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
|
||||
pci_reset_function(card->dev);
|
||||
}
|
||||
|
||||
static void mwifiex_pcie_work(struct work_struct *work)
|
||||
{
|
||||
struct pcie_service_card *card =
|
||||
@ -2830,6 +2831,9 @@ static void mwifiex_pcie_work(struct work_struct *work)
|
||||
if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
|
||||
&card->work_flags))
|
||||
mwifiex_pcie_device_dump_work(card->adapter);
|
||||
if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET,
|
||||
&card->work_flags))
|
||||
mwifiex_pcie_card_reset_work(card->adapter);
|
||||
}
|
||||
|
||||
/* This function dumps FW information */
|
||||
@ -2837,12 +2841,72 @@ static void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
|
||||
if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags))
|
||||
return;
|
||||
if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
|
||||
&card->work_flags))
|
||||
schedule_work(&card->work);
|
||||
}
|
||||
|
||||
set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
|
||||
static void mwifiex_pcie_card_reset(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
|
||||
schedule_work(&card->work);
|
||||
if (!test_and_set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags))
|
||||
schedule_work(&card->work);
|
||||
}
|
||||
|
||||
static int mwifiex_pcie_alloc_buffers(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
|
||||
int ret;
|
||||
|
||||
card->cmdrsp_buf = NULL;
|
||||
ret = mwifiex_pcie_create_txbd_ring(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to create txbd ring\n");
|
||||
goto err_cre_txbd;
|
||||
}
|
||||
|
||||
ret = mwifiex_pcie_create_rxbd_ring(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to create rxbd ring\n");
|
||||
goto err_cre_rxbd;
|
||||
}
|
||||
|
||||
ret = mwifiex_pcie_create_evtbd_ring(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to create evtbd ring\n");
|
||||
goto err_cre_evtbd;
|
||||
}
|
||||
|
||||
ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to allocate cmdbuf buffer\n");
|
||||
goto err_alloc_cmdbuf;
|
||||
}
|
||||
|
||||
if (reg->sleep_cookie) {
|
||||
ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to allocate sleep_cookie buffer\n");
|
||||
goto err_alloc_cookie;
|
||||
}
|
||||
} else {
|
||||
card->sleep_cookie_vbase = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_alloc_cookie:
|
||||
mwifiex_pcie_delete_cmdrsp_buf(adapter);
|
||||
err_alloc_cmdbuf:
|
||||
mwifiex_pcie_delete_evtbd_ring(adapter);
|
||||
err_cre_evtbd:
|
||||
mwifiex_pcie_delete_rxbd_ring(adapter);
|
||||
err_cre_rxbd:
|
||||
mwifiex_pcie_delete_txbd_ring(adapter);
|
||||
err_cre_txbd:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter)
|
||||
@ -2862,20 +2926,12 @@ static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter)
|
||||
|
||||
/*
|
||||
* This function initializes the PCI-E host memory space, WCB rings, etc.
|
||||
*
|
||||
* The following initializations steps are followed -
|
||||
* - Allocate TXBD ring buffers
|
||||
* - Allocate RXBD ring buffers
|
||||
* - Allocate event BD ring buffers
|
||||
* - Allocate command response ring buffer
|
||||
* - Allocate sleep cookie buffer
|
||||
*/
|
||||
static int mwifiex_init_pcie(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
int ret;
|
||||
struct pci_dev *pdev = card->dev;
|
||||
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
|
||||
|
||||
pci_set_drvdata(pdev, card);
|
||||
|
||||
@ -2924,37 +2980,13 @@ static int mwifiex_init_pcie(struct mwifiex_adapter *adapter)
|
||||
pr_notice("PCI memory map Virt0: %p PCI memory map Virt2: %p\n",
|
||||
card->pci_mmap, card->pci_mmap1);
|
||||
|
||||
card->cmdrsp_buf = NULL;
|
||||
ret = mwifiex_pcie_create_txbd_ring(adapter);
|
||||
ret = mwifiex_pcie_alloc_buffers(adapter);
|
||||
if (ret)
|
||||
goto err_cre_txbd;
|
||||
ret = mwifiex_pcie_create_rxbd_ring(adapter);
|
||||
if (ret)
|
||||
goto err_cre_rxbd;
|
||||
ret = mwifiex_pcie_create_evtbd_ring(adapter);
|
||||
if (ret)
|
||||
goto err_cre_evtbd;
|
||||
ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
|
||||
if (ret)
|
||||
goto err_alloc_cmdbuf;
|
||||
if (reg->sleep_cookie) {
|
||||
ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
|
||||
if (ret)
|
||||
goto err_alloc_cookie;
|
||||
} else {
|
||||
card->sleep_cookie_vbase = NULL;
|
||||
}
|
||||
return ret;
|
||||
goto err_alloc_buffers;
|
||||
|
||||
err_alloc_cookie:
|
||||
mwifiex_pcie_delete_cmdrsp_buf(adapter);
|
||||
err_alloc_cmdbuf:
|
||||
mwifiex_pcie_delete_evtbd_ring(adapter);
|
||||
err_cre_evtbd:
|
||||
mwifiex_pcie_delete_rxbd_ring(adapter);
|
||||
err_cre_rxbd:
|
||||
mwifiex_pcie_delete_txbd_ring(adapter);
|
||||
err_cre_txbd:
|
||||
return 0;
|
||||
|
||||
err_alloc_buffers:
|
||||
pci_iounmap(pdev, card->pci_mmap1);
|
||||
err_iomap2:
|
||||
pci_release_region(pdev, 2);
|
||||
@ -3168,73 +3200,25 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
|
||||
card->adapter = NULL;
|
||||
}
|
||||
|
||||
/* This function initializes the PCI-E host memory space, WCB rings, etc.
|
||||
*
|
||||
* The following initializations steps are followed -
|
||||
* - Allocate TXBD ring buffers
|
||||
* - Allocate RXBD ring buffers
|
||||
* - Allocate event BD ring buffers
|
||||
* - Allocate command response ring buffer
|
||||
* - Allocate sleep cookie buffer
|
||||
* Part of mwifiex_init_pcie(), not reset the PCIE registers
|
||||
/*
|
||||
* This function initializes the PCI-E host memory space, WCB rings, etc.,
|
||||
* similar to mwifiex_init_pcie(), but without resetting PCI-E state.
|
||||
*/
|
||||
static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
int ret;
|
||||
struct pci_dev *pdev = card->dev;
|
||||
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
|
||||
|
||||
/* tx_buf_size might be changed to 3584 by firmware during
|
||||
* data transfer, we should reset it to default size.
|
||||
*/
|
||||
adapter->tx_buf_size = card->pcie.tx_buf_size;
|
||||
|
||||
card->cmdrsp_buf = NULL;
|
||||
ret = mwifiex_pcie_create_txbd_ring(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to create txbd ring\n");
|
||||
goto err_cre_txbd;
|
||||
}
|
||||
ret = mwifiex_pcie_alloc_buffers(adapter);
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
ret = mwifiex_pcie_create_rxbd_ring(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to create rxbd ring\n");
|
||||
goto err_cre_rxbd;
|
||||
}
|
||||
|
||||
ret = mwifiex_pcie_create_evtbd_ring(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to create evtbd ring\n");
|
||||
goto err_cre_evtbd;
|
||||
}
|
||||
|
||||
ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to allocate cmdbuf buffer\n");
|
||||
goto err_alloc_cmdbuf;
|
||||
}
|
||||
|
||||
if (reg->sleep_cookie) {
|
||||
ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to allocate sleep_cookie buffer\n");
|
||||
goto err_alloc_cookie;
|
||||
}
|
||||
} else {
|
||||
card->sleep_cookie_vbase = NULL;
|
||||
}
|
||||
return;
|
||||
|
||||
err_alloc_cookie:
|
||||
mwifiex_pcie_delete_cmdrsp_buf(adapter);
|
||||
err_alloc_cmdbuf:
|
||||
mwifiex_pcie_delete_evtbd_ring(adapter);
|
||||
err_cre_evtbd:
|
||||
mwifiex_pcie_delete_rxbd_ring(adapter);
|
||||
err_cre_rxbd:
|
||||
mwifiex_pcie_delete_txbd_ring(adapter);
|
||||
err_cre_txbd:
|
||||
pci_iounmap(pdev, card->pci_mmap1);
|
||||
}
|
||||
|
||||
@ -3274,6 +3258,7 @@ static struct mwifiex_if_ops pcie_ops = {
|
||||
.cleanup_mpa_buf = NULL,
|
||||
.init_fw_port = mwifiex_pcie_init_fw_port,
|
||||
.clean_pcie_ring = mwifiex_clean_pcie_ring_buf,
|
||||
.card_reset = mwifiex_pcie_card_reset,
|
||||
.reg_dump = mwifiex_pcie_reg_dump,
|
||||
.device_dump = mwifiex_pcie_device_dump,
|
||||
.down_dev = mwifiex_pcie_down_dev,
|
||||
|
@ -1125,7 +1125,7 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter,
|
||||
data = skb->data;
|
||||
total_pkt_len = skb->len;
|
||||
|
||||
while (total_pkt_len >= (SDIO_HEADER_OFFSET + INTF_HEADER_LEN)) {
|
||||
while (total_pkt_len >= (SDIO_HEADER_OFFSET + adapter->intf_hdr_len)) {
|
||||
if (total_pkt_len < adapter->sdio_rx_block_size)
|
||||
break;
|
||||
blk_num = *(data + BLOCK_NUMBER_OFFSET);
|
||||
@ -1152,7 +1152,7 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter,
|
||||
break;
|
||||
skb_put(skb_deaggr, pkt_len);
|
||||
memcpy(skb_deaggr->data, data + SDIO_HEADER_OFFSET, pkt_len);
|
||||
skb_pull(skb_deaggr, INTF_HEADER_LEN);
|
||||
skb_pull(skb_deaggr, adapter->intf_hdr_len);
|
||||
|
||||
mwifiex_handle_rx_packet(adapter, skb_deaggr);
|
||||
data += blk_size;
|
||||
@ -1178,7 +1178,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
|
||||
|
||||
if (upld_typ != MWIFIEX_TYPE_AGGR_DATA) {
|
||||
skb_trim(skb, pkt_len);
|
||||
skb_pull(skb, INTF_HEADER_LEN);
|
||||
skb_pull(skb, adapter->intf_hdr_len);
|
||||
}
|
||||
|
||||
switch (upld_typ) {
|
||||
@ -1537,7 +1537,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
|
||||
rx_len = card->mp_regs[reg->cmd_rd_len_1] << 8;
|
||||
rx_len |= (u16)card->mp_regs[reg->cmd_rd_len_0];
|
||||
rx_blocks = DIV_ROUND_UP(rx_len, MWIFIEX_SDIO_BLOCK_SIZE);
|
||||
if (rx_len <= INTF_HEADER_LEN ||
|
||||
if (rx_len <= adapter->intf_hdr_len ||
|
||||
(rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
|
||||
MWIFIEX_RX_DATA_BUF_SIZE)
|
||||
return -1;
|
||||
@ -1635,7 +1635,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
|
||||
rx_blocks =
|
||||
(rx_len + MWIFIEX_SDIO_BLOCK_SIZE -
|
||||
1) / MWIFIEX_SDIO_BLOCK_SIZE;
|
||||
if (rx_len <= INTF_HEADER_LEN ||
|
||||
if (rx_len <= adapter->intf_hdr_len ||
|
||||
(card->mpa_rx.enabled &&
|
||||
((rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
|
||||
card->mpa_rx.buf_size))) {
|
||||
@ -1896,7 +1896,7 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
|
||||
adapter->cmd_sent = true;
|
||||
/* Type must be MWIFIEX_TYPE_CMD */
|
||||
|
||||
if (pkt_len <= INTF_HEADER_LEN ||
|
||||
if (pkt_len <= adapter->intf_hdr_len ||
|
||||
pkt_len > MWIFIEX_UPLD_SIZE)
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"%s: payload=%p, nb=%d\n",
|
||||
@ -2533,12 +2533,8 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct sdio_mmc_card *card = adapter->card;
|
||||
|
||||
if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags))
|
||||
return;
|
||||
|
||||
set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
|
||||
|
||||
schedule_work(&card->work);
|
||||
if (!test_and_set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags))
|
||||
schedule_work(&card->work);
|
||||
}
|
||||
|
||||
/* This function dumps FW information */
|
||||
@ -2546,11 +2542,9 @@ static void mwifiex_sdio_device_dump(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct sdio_mmc_card *card = adapter->card;
|
||||
|
||||
if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags))
|
||||
return;
|
||||
|
||||
set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
|
||||
schedule_work(&card->work);
|
||||
if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
|
||||
&card->work_flags))
|
||||
schedule_work(&card->work);
|
||||
}
|
||||
|
||||
/* Function to dump SDIO function registers and SDIO scratch registers in case
|
||||
|
@ -2064,6 +2064,15 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
|
||||
case HostCmd_CMD_11AC_CFG:
|
||||
ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf);
|
||||
break;
|
||||
case HostCmd_CMD_PACKET_AGGR_CTRL:
|
||||
cmd_ptr->command = cpu_to_le16(cmd_no);
|
||||
cmd_ptr->params.pkt_aggr_ctrl.action = cpu_to_le16(cmd_action);
|
||||
cmd_ptr->params.pkt_aggr_ctrl.enable =
|
||||
cpu_to_le16(*(u16 *)data_buf);
|
||||
cmd_ptr->size =
|
||||
cpu_to_le16(sizeof(struct host_cmd_ds_pkt_aggr_ctrl) +
|
||||
S_DS_GEN);
|
||||
break;
|
||||
case HostCmd_CMD_P2P_MODE_CFG:
|
||||
cmd_ptr->command = cpu_to_le16(cmd_no);
|
||||
cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action);
|
||||
@ -2241,6 +2250,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
|
||||
enum state_11d_t state_11d;
|
||||
struct mwifiex_ds_11n_tx_cfg tx_cfg;
|
||||
u8 sdio_sp_rx_aggr_enable;
|
||||
u16 packet_aggr_enable;
|
||||
int data;
|
||||
|
||||
if (first_sta) {
|
||||
@ -2387,6 +2397,14 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
|
||||
"11D: failed to enable 11D\n");
|
||||
}
|
||||
|
||||
/* Pacekt aggregation handshake with firmware */
|
||||
if (aggr_ctrl) {
|
||||
packet_aggr_enable = true;
|
||||
mwifiex_send_cmd(priv, HostCmd_CMD_PACKET_AGGR_CTRL,
|
||||
HostCmd_ACT_GEN_SET, 0,
|
||||
&packet_aggr_enable, true);
|
||||
}
|
||||
|
||||
/* Send cmd to FW to configure 11n specific configuration
|
||||
* (Short GI, Channel BW, Green field support etc.) for transmit
|
||||
*/
|
||||
|
@ -1154,6 +1154,27 @@ static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mwifiex_ret_pkt_aggr_ctrl(struct mwifiex_private *priv,
|
||||
struct host_cmd_ds_command *resp)
|
||||
{
|
||||
struct host_cmd_ds_pkt_aggr_ctrl *pkt_aggr_ctrl =
|
||||
&resp->params.pkt_aggr_ctrl;
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
|
||||
adapter->bus_aggr.enable = le16_to_cpu(pkt_aggr_ctrl->enable);
|
||||
if (adapter->bus_aggr.enable)
|
||||
adapter->intf_hdr_len = INTF_HEADER_LEN;
|
||||
adapter->bus_aggr.mode = MWIFIEX_BUS_AGGR_MODE_LEN_V2;
|
||||
adapter->bus_aggr.tx_aggr_max_size =
|
||||
le16_to_cpu(pkt_aggr_ctrl->tx_aggr_max_size);
|
||||
adapter->bus_aggr.tx_aggr_max_num =
|
||||
le16_to_cpu(pkt_aggr_ctrl->tx_aggr_max_num);
|
||||
adapter->bus_aggr.tx_aggr_align =
|
||||
le16_to_cpu(pkt_aggr_ctrl->tx_aggr_align);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the command responses.
|
||||
*
|
||||
@ -1255,6 +1276,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
|
||||
break;
|
||||
case HostCmd_CMD_11AC_CFG:
|
||||
break;
|
||||
case HostCmd_CMD_PACKET_AGGR_CTRL:
|
||||
ret = mwifiex_ret_pkt_aggr_ctrl(priv, resp);
|
||||
break;
|
||||
case HostCmd_CMD_P2P_MODE_CFG:
|
||||
ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf);
|
||||
break;
|
||||
|
@ -49,8 +49,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
|
||||
struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
unsigned int pad;
|
||||
u16 pkt_type, pkt_offset;
|
||||
int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 :
|
||||
INTF_HEADER_LEN;
|
||||
int hroom = adapter->intf_hdr_len;
|
||||
|
||||
if (!skb->len) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
@ -116,7 +115,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
|
||||
|
||||
local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset);
|
||||
|
||||
/* make space for INTF_HEADER_LEN */
|
||||
/* make space for adapter->intf_hdr_len */
|
||||
skb_push(skb, hroom);
|
||||
|
||||
if (!local_tx_pd->tx_control)
|
||||
@ -165,8 +164,9 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->bss_num = priv->bss_num;
|
||||
tx_info->bss_type = priv->bss_type;
|
||||
tx_info->pkt_len = data_len - (sizeof(struct txpd) + INTF_HEADER_LEN);
|
||||
skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN);
|
||||
tx_info->pkt_len = data_len -
|
||||
(sizeof(struct txpd) + adapter->intf_hdr_len);
|
||||
skb_reserve(skb, sizeof(struct txpd) + adapter->intf_hdr_len);
|
||||
skb_push(skb, sizeof(struct txpd));
|
||||
|
||||
local_tx_pd = (struct txpd *) skb->data;
|
||||
@ -177,11 +177,11 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
|
||||
local_tx_pd->bss_num = priv->bss_num;
|
||||
local_tx_pd->bss_type = priv->bss_type;
|
||||
|
||||
skb_push(skb, adapter->intf_hdr_len);
|
||||
if (adapter->iface_type == MWIFIEX_USB) {
|
||||
ret = adapter->if_ops.host_to_card(adapter, priv->usb_port,
|
||||
skb, NULL);
|
||||
} else {
|
||||
skb_push(skb, INTF_HEADER_LEN);
|
||||
tx_param.next_pkt_len = 0;
|
||||
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
|
||||
skb, &tx_param);
|
||||
|
@ -55,11 +55,8 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,
|
||||
tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
|
||||
} else {
|
||||
tid_list = &priv->wmm.tid_tbl_ptr[tid_down].ra_list;
|
||||
if (!list_empty(tid_list))
|
||||
ra_list = list_first_entry(tid_list,
|
||||
struct mwifiex_ra_list_tbl, list);
|
||||
else
|
||||
ra_list = NULL;
|
||||
ra_list = list_first_entry_or_null(tid_list,
|
||||
struct mwifiex_ra_list_tbl, list);
|
||||
tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT;
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
|
||||
struct mwifiex_sta_node *dest_node;
|
||||
struct ethhdr *hdr = (void *)skb->data;
|
||||
|
||||
hroom = (adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN;
|
||||
hroom = adapter->intf_hdr_len;
|
||||
|
||||
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
|
||||
dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest);
|
||||
@ -117,7 +117,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
|
||||
if (adapter->iface_type == MWIFIEX_USB) {
|
||||
ret = adapter->if_ops.host_to_card(adapter,
|
||||
priv->usb_port,
|
||||
skb, NULL);
|
||||
skb, tx_param);
|
||||
} else {
|
||||
ret = adapter->if_ops.host_to_card(adapter,
|
||||
MWIFIEX_TYPE_DATA,
|
||||
@ -179,18 +179,13 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
|
||||
mwifiex_write_data_complete(adapter, skb, 0, 0);
|
||||
return ret;
|
||||
}
|
||||
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
|
||||
if (adapter->iface_type == MWIFIEX_USB)
|
||||
local_tx_pd = (struct txpd *)head_ptr;
|
||||
else
|
||||
local_tx_pd = (struct txpd *) (head_ptr +
|
||||
INTF_HEADER_LEN);
|
||||
}
|
||||
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
|
||||
local_tx_pd = (struct txpd *)(head_ptr + adapter->intf_hdr_len);
|
||||
|
||||
if (adapter->iface_type == MWIFIEX_USB) {
|
||||
ret = adapter->if_ops.host_to_card(adapter,
|
||||
priv->usb_port,
|
||||
skb, NULL);
|
||||
skb, tx_param);
|
||||
} else {
|
||||
ret = adapter->if_ops.host_to_card(adapter,
|
||||
MWIFIEX_TYPE_DATA,
|
||||
|
@ -312,6 +312,17 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
|
||||
adapter->event_skb->len -
|
||||
sizeof(eventcause));
|
||||
break;
|
||||
|
||||
case EVENT_REMAIN_ON_CHAN_EXPIRED:
|
||||
mwifiex_dbg(adapter, EVENT,
|
||||
"event: uap: Remain on channel expired\n");
|
||||
cfg80211_remain_on_channel_expired(&priv->wdev,
|
||||
priv->roc_cfg.cookie,
|
||||
&priv->roc_cfg.chan,
|
||||
GFP_ATOMIC);
|
||||
memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg));
|
||||
break;
|
||||
|
||||
default:
|
||||
mwifiex_dbg(adapter, EVENT,
|
||||
"event: unknown event id: %#x\n", eventcause);
|
||||
|
@ -468,8 +468,7 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
|
||||
struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
int pad;
|
||||
u16 pkt_type, pkt_offset;
|
||||
int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 :
|
||||
INTF_HEADER_LEN;
|
||||
int hroom = adapter->intf_hdr_len;
|
||||
|
||||
if (!skb->len) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
@ -521,7 +520,7 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
|
||||
|
||||
txpd->tx_pkt_offset = cpu_to_le16(pkt_offset);
|
||||
|
||||
/* make space for INTF_HEADER_LEN */
|
||||
/* make space for adapter->intf_hdr_len */
|
||||
skb_push(skb, hroom);
|
||||
|
||||
if (!txpd->tx_control)
|
||||
|
@ -363,6 +363,7 @@ static void mwifiex_usb_free(struct usb_card_rec *card)
|
||||
for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
|
||||
port = &card->port[i];
|
||||
for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) {
|
||||
usb_kill_urb(port->tx_data_list[j].urb);
|
||||
usb_free_urb(port->tx_data_list[j].urb);
|
||||
port->tx_data_list[j].urb = NULL;
|
||||
}
|
||||
@ -424,7 +425,8 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
|
||||
card->intf = intf;
|
||||
|
||||
pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x\n",
|
||||
udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass,
|
||||
le16_to_cpu(udev->descriptor.bcdUSB),
|
||||
udev->descriptor.bDeviceClass,
|
||||
udev->descriptor.bDeviceSubClass,
|
||||
udev->descriptor.bDeviceProtocol);
|
||||
|
||||
@ -661,75 +663,6 @@ static struct usb_driver mwifiex_usb_driver = {
|
||||
.soft_unbind = 1,
|
||||
};
|
||||
|
||||
static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
|
||||
struct usb_tx_data_port *port;
|
||||
int i, j;
|
||||
|
||||
card->tx_cmd.adapter = adapter;
|
||||
card->tx_cmd.ep = card->tx_cmd_ep;
|
||||
|
||||
card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!card->tx_cmd.urb)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
|
||||
port = &card->port[i];
|
||||
if (!port->tx_data_ep)
|
||||
continue;
|
||||
port->tx_data_ix = 0;
|
||||
if (port->tx_data_ep == MWIFIEX_USB_EP_DATA)
|
||||
port->block_status = false;
|
||||
else
|
||||
port->block_status = true;
|
||||
for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) {
|
||||
port->tx_data_list[j].adapter = adapter;
|
||||
port->tx_data_list[j].ep = port->tx_data_ep;
|
||||
port->tx_data_list[j].urb =
|
||||
usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!port->tx_data_list[j].urb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
|
||||
int i;
|
||||
|
||||
card->rx_cmd.adapter = adapter;
|
||||
card->rx_cmd.ep = card->rx_cmd_ep;
|
||||
|
||||
card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!card->rx_cmd.urb)
|
||||
return -ENOMEM;
|
||||
|
||||
card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE);
|
||||
if (!card->rx_cmd.skb)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE))
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) {
|
||||
card->rx_data_list[i].adapter = adapter;
|
||||
card->rx_data_list[i].ep = card->rx_data_ep;
|
||||
|
||||
card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!card->rx_data_list[i].urb)
|
||||
return -1;
|
||||
if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i],
|
||||
MWIFIEX_RX_DATA_BUF_SIZE))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
|
||||
u32 *len, u8 ep, u32 timeout)
|
||||
{
|
||||
@ -845,73 +778,31 @@ static inline u8 mwifiex_usb_data_sent(struct mwifiex_adapter *adapter)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function write a command/data packet to card. */
|
||||
static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
|
||||
struct sk_buff *skb,
|
||||
struct mwifiex_tx_param *tx_param)
|
||||
static int mwifiex_usb_construct_send_urb(struct mwifiex_adapter *adapter,
|
||||
struct usb_tx_data_port *port, u8 ep,
|
||||
struct urb_context *context,
|
||||
struct sk_buff *skb_send)
|
||||
{
|
||||
struct usb_card_rec *card = adapter->card;
|
||||
struct urb_context *context = NULL;
|
||||
struct usb_tx_data_port *port = NULL;
|
||||
u8 *data = (u8 *)skb->data;
|
||||
int ret = -EINPROGRESS;
|
||||
struct urb *tx_urb;
|
||||
int idx, ret = -EINPROGRESS;
|
||||
|
||||
if (adapter->is_suspended) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"%s: not allowed while suspended\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (adapter->surprise_removed) {
|
||||
mwifiex_dbg(adapter, ERROR, "%s: device removed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mwifiex_dbg(adapter, INFO, "%s: ep=%d\n", __func__, ep);
|
||||
|
||||
if (ep == card->tx_cmd_ep) {
|
||||
context = &card->tx_cmd;
|
||||
} else {
|
||||
for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) {
|
||||
if (ep == card->port[idx].tx_data_ep) {
|
||||
port = &card->port[idx];
|
||||
if (atomic_read(&port->tx_data_urb_pending)
|
||||
>= MWIFIEX_TX_DATA_URB) {
|
||||
port->block_status = true;
|
||||
adapter->data_sent =
|
||||
mwifiex_usb_data_sent(adapter);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB)
|
||||
port->tx_data_ix = 0;
|
||||
context =
|
||||
&port->tx_data_list[port->tx_data_ix++];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!port) {
|
||||
mwifiex_dbg(adapter, ERROR, "Wrong usb tx data port\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
context->adapter = adapter;
|
||||
context->ep = ep;
|
||||
context->skb = skb;
|
||||
context->skb = skb_send;
|
||||
tx_urb = context->urb;
|
||||
|
||||
if (ep == card->tx_cmd_ep &&
|
||||
card->tx_cmd_ep_type == USB_ENDPOINT_XFER_INT)
|
||||
usb_fill_int_urb(tx_urb, card->udev,
|
||||
usb_sndintpipe(card->udev, ep), data,
|
||||
skb->len, mwifiex_usb_tx_complete,
|
||||
usb_sndintpipe(card->udev, ep), skb_send->data,
|
||||
skb_send->len, mwifiex_usb_tx_complete,
|
||||
(void *)context, card->tx_cmd_interval);
|
||||
else
|
||||
usb_fill_bulk_urb(tx_urb, card->udev,
|
||||
usb_sndbulkpipe(card->udev, ep), data,
|
||||
skb->len, mwifiex_usb_tx_complete,
|
||||
(void *)context);
|
||||
usb_sndbulkpipe(card->udev, ep),
|
||||
skb_send->data, skb_send->len,
|
||||
mwifiex_usb_tx_complete, (void *)context);
|
||||
|
||||
tx_urb->transfer_flags |= URB_ZERO_PACKET;
|
||||
|
||||
@ -948,6 +839,444 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mwifiex_usb_prepare_tx_aggr_skb(struct mwifiex_adapter *adapter,
|
||||
struct usb_tx_data_port *port,
|
||||
struct sk_buff **skb_send)
|
||||
{
|
||||
struct sk_buff *skb_aggr, *skb_tmp;
|
||||
u8 *payload, pad;
|
||||
u16 align = adapter->bus_aggr.tx_aggr_align;
|
||||
struct mwifiex_txinfo *tx_info = NULL;
|
||||
bool is_txinfo_set = false;
|
||||
|
||||
/* Packets in aggr_list will be send in either skb_aggr or
|
||||
* write complete, delete the tx_aggr timer
|
||||
*/
|
||||
if (port->tx_aggr.timer_cnxt.is_hold_timer_set) {
|
||||
del_timer(&port->tx_aggr.timer_cnxt.hold_timer);
|
||||
port->tx_aggr.timer_cnxt.is_hold_timer_set = false;
|
||||
port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0;
|
||||
}
|
||||
|
||||
skb_aggr = mwifiex_alloc_dma_align_buf(port->tx_aggr.aggr_len,
|
||||
GFP_ATOMIC);
|
||||
if (!skb_aggr) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"%s: alloc skb_aggr failed\n", __func__);
|
||||
|
||||
while ((skb_tmp = skb_dequeue(&port->tx_aggr.aggr_list)))
|
||||
mwifiex_write_data_complete(adapter, skb_tmp, 0, -1);
|
||||
|
||||
port->tx_aggr.aggr_num = 0;
|
||||
port->tx_aggr.aggr_len = 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
tx_info = MWIFIEX_SKB_TXCB(skb_aggr);
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
|
||||
while ((skb_tmp = skb_dequeue(&port->tx_aggr.aggr_list))) {
|
||||
/* padding for aligning next packet header*/
|
||||
pad = (align - (skb_tmp->len & (align - 1))) % align;
|
||||
payload = skb_put(skb_aggr, skb_tmp->len + pad);
|
||||
memcpy(payload, skb_tmp->data, skb_tmp->len);
|
||||
if (skb_queue_empty(&port->tx_aggr.aggr_list)) {
|
||||
/* do not padding for last packet*/
|
||||
*(u16 *)payload = cpu_to_le16(skb_tmp->len);
|
||||
*(u16 *)&payload[2] =
|
||||
cpu_to_le16(MWIFIEX_TYPE_AGGR_DATA_V2 | 0x80);
|
||||
skb_trim(skb_aggr, skb_aggr->len - pad);
|
||||
} else {
|
||||
/* add aggregation interface header */
|
||||
*(u16 *)payload = cpu_to_le16(skb_tmp->len + pad);
|
||||
*(u16 *)&payload[2] =
|
||||
cpu_to_le16(MWIFIEX_TYPE_AGGR_DATA_V2);
|
||||
}
|
||||
|
||||
if (!is_txinfo_set) {
|
||||
tx_info->bss_num = MWIFIEX_SKB_TXCB(skb_tmp)->bss_num;
|
||||
tx_info->bss_type = MWIFIEX_SKB_TXCB(skb_tmp)->bss_type;
|
||||
is_txinfo_set = true;
|
||||
}
|
||||
|
||||
port->tx_aggr.aggr_num--;
|
||||
port->tx_aggr.aggr_len -= (skb_tmp->len + pad);
|
||||
mwifiex_write_data_complete(adapter, skb_tmp, 0, 0);
|
||||
}
|
||||
|
||||
tx_info->pkt_len = skb_aggr->len -
|
||||
(sizeof(struct txpd) + adapter->intf_hdr_len);
|
||||
tx_info->flags |= MWIFIEX_BUF_FLAG_AGGR_PKT;
|
||||
|
||||
port->tx_aggr.aggr_num = 0;
|
||||
port->tx_aggr.aggr_len = 0;
|
||||
*skb_send = skb_aggr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function prepare data packet to be send under usb tx aggregation
|
||||
* protocol, check current usb aggregation status, link packet to aggrgation
|
||||
* list if possible, work flow as below:
|
||||
* (1) if only 1 packet available, add usb tx aggregation header and send.
|
||||
* (2) if packet is able to aggregated, link it to current aggregation list.
|
||||
* (3) if packet is not able to aggregated, aggregate and send exist packets
|
||||
* in aggrgation list. Then, link packet in the list if there is more
|
||||
* packet in transmit queue, otherwise try to transmit single packet.
|
||||
*/
|
||||
static int mwifiex_usb_aggr_tx_data(struct mwifiex_adapter *adapter, u8 ep,
|
||||
struct sk_buff *skb,
|
||||
struct mwifiex_tx_param *tx_param,
|
||||
struct usb_tx_data_port *port)
|
||||
{
|
||||
u8 *payload, pad;
|
||||
u16 align = adapter->bus_aggr.tx_aggr_align;
|
||||
struct sk_buff *skb_send = NULL;
|
||||
struct urb_context *context = NULL;
|
||||
struct txpd *local_tx_pd =
|
||||
(struct txpd *)((u8 *)skb->data + adapter->intf_hdr_len);
|
||||
u8 f_send_aggr_buf = 0;
|
||||
u8 f_send_cur_buf = 0;
|
||||
u8 f_precopy_cur_buf = 0;
|
||||
u8 f_postcopy_cur_buf = 0;
|
||||
u32 timeout;
|
||||
int ret;
|
||||
|
||||
/* padding to ensure each packet alginment */
|
||||
pad = (align - (skb->len & (align - 1))) % align;
|
||||
|
||||
if (tx_param && tx_param->next_pkt_len) {
|
||||
/* next packet available in tx queue*/
|
||||
if (port->tx_aggr.aggr_len + skb->len + pad >
|
||||
adapter->bus_aggr.tx_aggr_max_size) {
|
||||
f_send_aggr_buf = 1;
|
||||
f_postcopy_cur_buf = 1;
|
||||
} else {
|
||||
/* current packet could be aggregated*/
|
||||
f_precopy_cur_buf = 1;
|
||||
|
||||
if (port->tx_aggr.aggr_len + skb->len + pad +
|
||||
tx_param->next_pkt_len >
|
||||
adapter->bus_aggr.tx_aggr_max_size ||
|
||||
port->tx_aggr.aggr_num + 2 >
|
||||
adapter->bus_aggr.tx_aggr_max_num) {
|
||||
/* next packet could not be aggregated
|
||||
* send current aggregation buffer
|
||||
*/
|
||||
f_send_aggr_buf = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* last packet in tx queue */
|
||||
if (port->tx_aggr.aggr_num > 0) {
|
||||
/* pending packets in aggregation buffer*/
|
||||
if (port->tx_aggr.aggr_len + skb->len + pad >
|
||||
adapter->bus_aggr.tx_aggr_max_size) {
|
||||
/* current packet not be able to aggregated,
|
||||
* send aggr buffer first, then send packet.
|
||||
*/
|
||||
f_send_cur_buf = 1;
|
||||
} else {
|
||||
/* last packet, Aggregation and send */
|
||||
f_precopy_cur_buf = 1;
|
||||
}
|
||||
|
||||
f_send_aggr_buf = 1;
|
||||
} else {
|
||||
/* no pending packets in aggregation buffer,
|
||||
* send current packet immediately
|
||||
*/
|
||||
f_send_cur_buf = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (local_tx_pd->flags & MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET) {
|
||||
/* Send NULL packet immediately*/
|
||||
if (f_precopy_cur_buf) {
|
||||
if (skb_queue_empty(&port->tx_aggr.aggr_list)) {
|
||||
f_precopy_cur_buf = 0;
|
||||
f_send_aggr_buf = 0;
|
||||
f_send_cur_buf = 1;
|
||||
} else {
|
||||
f_send_aggr_buf = 1;
|
||||
}
|
||||
} else if (f_postcopy_cur_buf) {
|
||||
f_send_cur_buf = 1;
|
||||
f_postcopy_cur_buf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (f_precopy_cur_buf) {
|
||||
skb_queue_tail(&port->tx_aggr.aggr_list, skb);
|
||||
port->tx_aggr.aggr_len += (skb->len + pad);
|
||||
port->tx_aggr.aggr_num++;
|
||||
if (f_send_aggr_buf)
|
||||
goto send_aggr_buf;
|
||||
|
||||
/* packet will not been send immediately,
|
||||
* set a timer to make sure it will be sent under
|
||||
* strict time limit. Dynamically fit the timeout
|
||||
* value, according to packets number in aggr_list
|
||||
*/
|
||||
if (!port->tx_aggr.timer_cnxt.is_hold_timer_set) {
|
||||
port->tx_aggr.timer_cnxt.hold_tmo_msecs =
|
||||
MWIFIEX_USB_TX_AGGR_TMO_MIN;
|
||||
timeout =
|
||||
port->tx_aggr.timer_cnxt.hold_tmo_msecs;
|
||||
mod_timer(&port->tx_aggr.timer_cnxt.hold_timer,
|
||||
jiffies + msecs_to_jiffies(timeout));
|
||||
port->tx_aggr.timer_cnxt.is_hold_timer_set = true;
|
||||
} else {
|
||||
if (port->tx_aggr.timer_cnxt.hold_tmo_msecs <
|
||||
MWIFIEX_USB_TX_AGGR_TMO_MAX) {
|
||||
/* Dyanmic fit timeout */
|
||||
timeout =
|
||||
++port->tx_aggr.timer_cnxt.hold_tmo_msecs;
|
||||
mod_timer(&port->tx_aggr.timer_cnxt.hold_timer,
|
||||
jiffies + msecs_to_jiffies(timeout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_aggr_buf:
|
||||
if (f_send_aggr_buf) {
|
||||
ret = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send);
|
||||
if (!ret) {
|
||||
context = &port->tx_data_list[port->tx_data_ix++];
|
||||
ret = mwifiex_usb_construct_send_urb(adapter, port, ep,
|
||||
context, skb_send);
|
||||
if (ret == -1)
|
||||
mwifiex_write_data_complete(adapter, skb_send,
|
||||
0, -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (f_send_cur_buf) {
|
||||
if (f_send_aggr_buf) {
|
||||
if (atomic_read(&port->tx_data_urb_pending) >=
|
||||
MWIFIEX_TX_DATA_URB) {
|
||||
port->block_status = true;
|
||||
adapter->data_sent =
|
||||
mwifiex_usb_data_sent(adapter);
|
||||
/* no available urb, postcopy packet*/
|
||||
f_postcopy_cur_buf = 1;
|
||||
goto postcopy_cur_buf;
|
||||
}
|
||||
|
||||
if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB)
|
||||
port->tx_data_ix = 0;
|
||||
}
|
||||
|
||||
payload = skb->data;
|
||||
*(u16 *)&payload[2] =
|
||||
cpu_to_le16(MWIFIEX_TYPE_AGGR_DATA_V2 | 0x80);
|
||||
*(u16 *)payload = cpu_to_le16(skb->len);
|
||||
skb_send = skb;
|
||||
context = &port->tx_data_list[port->tx_data_ix++];
|
||||
return mwifiex_usb_construct_send_urb(adapter, port, ep,
|
||||
context, skb_send);
|
||||
}
|
||||
|
||||
postcopy_cur_buf:
|
||||
if (f_postcopy_cur_buf) {
|
||||
skb_queue_tail(&port->tx_aggr.aggr_list, skb);
|
||||
port->tx_aggr.aggr_len += (skb->len + pad);
|
||||
port->tx_aggr.aggr_num++;
|
||||
/* New aggregation begin, start timer */
|
||||
if (!port->tx_aggr.timer_cnxt.is_hold_timer_set) {
|
||||
port->tx_aggr.timer_cnxt.hold_tmo_msecs =
|
||||
MWIFIEX_USB_TX_AGGR_TMO_MIN;
|
||||
timeout = port->tx_aggr.timer_cnxt.hold_tmo_msecs;
|
||||
mod_timer(&port->tx_aggr.timer_cnxt.hold_timer,
|
||||
jiffies + msecs_to_jiffies(timeout));
|
||||
port->tx_aggr.timer_cnxt.is_hold_timer_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static void mwifiex_usb_tx_aggr_tmo(unsigned long context)
|
||||
{
|
||||
struct urb_context *urb_cnxt = NULL;
|
||||
struct sk_buff *skb_send = NULL;
|
||||
struct tx_aggr_tmr_cnxt *timer_context =
|
||||
(struct tx_aggr_tmr_cnxt *)context;
|
||||
struct mwifiex_adapter *adapter = timer_context->adapter;
|
||||
struct usb_tx_data_port *port = timer_context->port;
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
spin_lock_irqsave(&port->tx_aggr_lock, flags);
|
||||
err = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send);
|
||||
if (err) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"prepare tx aggr skb failed, err=%d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_read(&port->tx_data_urb_pending) >=
|
||||
MWIFIEX_TX_DATA_URB) {
|
||||
port->block_status = true;
|
||||
adapter->data_sent =
|
||||
mwifiex_usb_data_sent(adapter);
|
||||
err = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB)
|
||||
port->tx_data_ix = 0;
|
||||
|
||||
urb_cnxt = &port->tx_data_list[port->tx_data_ix++];
|
||||
err = mwifiex_usb_construct_send_urb(adapter, port, port->tx_data_ep,
|
||||
urb_cnxt, skb_send);
|
||||
done:
|
||||
if (err == -1)
|
||||
mwifiex_write_data_complete(adapter, skb_send, 0, -1);
|
||||
spin_unlock_irqrestore(&port->tx_aggr_lock, flags);
|
||||
}
|
||||
|
||||
/* This function write a command/data packet to card. */
|
||||
static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep,
|
||||
struct sk_buff *skb,
|
||||
struct mwifiex_tx_param *tx_param)
|
||||
{
|
||||
struct usb_card_rec *card = adapter->card;
|
||||
struct urb_context *context = NULL;
|
||||
struct usb_tx_data_port *port = NULL;
|
||||
unsigned long flags;
|
||||
int idx, ret;
|
||||
|
||||
if (adapter->is_suspended) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"%s: not allowed while suspended\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (adapter->surprise_removed) {
|
||||
mwifiex_dbg(adapter, ERROR, "%s: device removed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mwifiex_dbg(adapter, INFO, "%s: ep=%d\n", __func__, ep);
|
||||
|
||||
if (ep == card->tx_cmd_ep) {
|
||||
context = &card->tx_cmd;
|
||||
} else {
|
||||
/* get the data port structure for endpoint */
|
||||
for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) {
|
||||
if (ep == card->port[idx].tx_data_ep) {
|
||||
port = &card->port[idx];
|
||||
if (atomic_read(&port->tx_data_urb_pending)
|
||||
>= MWIFIEX_TX_DATA_URB) {
|
||||
port->block_status = true;
|
||||
adapter->data_sent =
|
||||
mwifiex_usb_data_sent(adapter);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB)
|
||||
port->tx_data_ix = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
mwifiex_dbg(adapter, ERROR, "Wrong usb tx data port\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (adapter->bus_aggr.enable) {
|
||||
spin_lock_irqsave(&port->tx_aggr_lock, flags);
|
||||
ret = mwifiex_usb_aggr_tx_data(adapter, ep, skb,
|
||||
tx_param, port);
|
||||
spin_unlock_irqrestore(&port->tx_aggr_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
context = &port->tx_data_list[port->tx_data_ix++];
|
||||
}
|
||||
|
||||
return mwifiex_usb_construct_send_urb(adapter, port, ep, context, skb);
|
||||
}
|
||||
|
||||
static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
|
||||
struct usb_tx_data_port *port;
|
||||
int i, j;
|
||||
|
||||
card->tx_cmd.adapter = adapter;
|
||||
card->tx_cmd.ep = card->tx_cmd_ep;
|
||||
|
||||
card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!card->tx_cmd.urb)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) {
|
||||
port = &card->port[i];
|
||||
if (!port->tx_data_ep)
|
||||
continue;
|
||||
port->tx_data_ix = 0;
|
||||
skb_queue_head_init(&port->tx_aggr.aggr_list);
|
||||
if (port->tx_data_ep == MWIFIEX_USB_EP_DATA)
|
||||
port->block_status = false;
|
||||
else
|
||||
port->block_status = true;
|
||||
for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) {
|
||||
port->tx_data_list[j].adapter = adapter;
|
||||
port->tx_data_list[j].ep = port->tx_data_ep;
|
||||
port->tx_data_list[j].urb =
|
||||
usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!port->tx_data_list[j].urb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
port->tx_aggr.timer_cnxt.adapter = adapter;
|
||||
port->tx_aggr.timer_cnxt.port = port;
|
||||
port->tx_aggr.timer_cnxt.is_hold_timer_set = false;
|
||||
port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0;
|
||||
setup_timer(&port->tx_aggr.timer_cnxt.hold_timer,
|
||||
mwifiex_usb_tx_aggr_tmo,
|
||||
(unsigned long)&port->tx_aggr.timer_cnxt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
|
||||
int i;
|
||||
|
||||
card->rx_cmd.adapter = adapter;
|
||||
card->rx_cmd.ep = card->rx_cmd_ep;
|
||||
|
||||
card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!card->rx_cmd.urb)
|
||||
return -ENOMEM;
|
||||
|
||||
card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE);
|
||||
if (!card->rx_cmd.skb)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE))
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) {
|
||||
card->rx_data_list[i].adapter = adapter;
|
||||
card->rx_data_list[i].ep = card->rx_data_ep;
|
||||
|
||||
card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!card->rx_data_list[i].urb)
|
||||
return -1;
|
||||
if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i],
|
||||
MWIFIEX_RX_DATA_BUF_SIZE))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function register usb device and initialize parameter. */
|
||||
static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
@ -988,10 +1317,32 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mwifiex_usb_cleanup_tx_aggr(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
|
||||
struct usb_tx_data_port *port;
|
||||
struct sk_buff *skb_tmp;
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) {
|
||||
port = &card->port[idx];
|
||||
if (adapter->bus_aggr.enable)
|
||||
while ((skb_tmp =
|
||||
skb_dequeue(&port->tx_aggr.aggr_list)))
|
||||
mwifiex_write_data_complete(adapter, skb_tmp,
|
||||
0, -1);
|
||||
del_timer_sync(&port->tx_aggr.timer_cnxt.hold_timer);
|
||||
port->tx_aggr.timer_cnxt.is_hold_timer_set = false;
|
||||
port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
|
||||
|
||||
mwifiex_usb_cleanup_tx_aggr(adapter);
|
||||
|
||||
card->adapter = NULL;
|
||||
}
|
||||
|
||||
|
@ -64,12 +64,35 @@ struct urb_context {
|
||||
u8 ep;
|
||||
};
|
||||
|
||||
#define MWIFIEX_USB_TX_AGGR_TMO_MIN 1
|
||||
#define MWIFIEX_USB_TX_AGGR_TMO_MAX 4
|
||||
|
||||
struct tx_aggr_tmr_cnxt {
|
||||
struct mwifiex_adapter *adapter;
|
||||
struct usb_tx_data_port *port;
|
||||
struct timer_list hold_timer;
|
||||
bool is_hold_timer_set;
|
||||
u32 hold_tmo_msecs;
|
||||
};
|
||||
|
||||
struct usb_tx_aggr {
|
||||
struct sk_buff_head aggr_list;
|
||||
int aggr_len;
|
||||
int aggr_num;
|
||||
struct tx_aggr_tmr_cnxt timer_cnxt;
|
||||
};
|
||||
|
||||
struct usb_tx_data_port {
|
||||
u8 tx_data_ep;
|
||||
u8 block_status;
|
||||
atomic_t tx_data_urb_pending;
|
||||
int tx_data_ix;
|
||||
struct urb_context tx_data_list[MWIFIEX_TX_DATA_URB];
|
||||
/* usb tx aggregation*/
|
||||
struct usb_tx_aggr tx_aggr;
|
||||
struct sk_buff *skb_aggr[MWIFIEX_TX_DATA_URB];
|
||||
/* lock for protect tx aggregation data path*/
|
||||
spinlock_t tx_aggr_lock;
|
||||
};
|
||||
|
||||
struct usb_card_rec {
|
||||
|
@ -868,12 +868,8 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
|
||||
return;
|
||||
default:
|
||||
list_head = priv->wmm.tid_tbl_ptr[tid_down].ra_list;
|
||||
if (!list_empty(&list_head))
|
||||
ra_list = list_first_entry(
|
||||
&list_head, struct mwifiex_ra_list_tbl,
|
||||
list);
|
||||
else
|
||||
ra_list = NULL;
|
||||
ra_list = list_first_entry_or_null(&list_head,
|
||||
struct mwifiex_ra_list_tbl, list);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -1363,13 +1359,13 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
|
||||
|
||||
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
|
||||
|
||||
tx_param.next_pkt_len =
|
||||
((skb_next) ? skb_next->len +
|
||||
sizeof(struct txpd) : 0);
|
||||
if (adapter->iface_type == MWIFIEX_USB) {
|
||||
ret = adapter->if_ops.host_to_card(adapter, priv->usb_port,
|
||||
skb, NULL);
|
||||
skb, &tx_param);
|
||||
} else {
|
||||
tx_param.next_pkt_len =
|
||||
((skb_next) ? skb_next->len +
|
||||
sizeof(struct txpd) : 0);
|
||||
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
|
||||
skb, &tx_param);
|
||||
}
|
||||
|
16
drivers/net/wireless/quantenna/Kconfig
Normal file
16
drivers/net/wireless/quantenna/Kconfig
Normal file
@ -0,0 +1,16 @@
|
||||
config WLAN_VENDOR_QUANTENNA
|
||||
bool "Quantenna wireless cards support"
|
||||
default y
|
||||
---help---
|
||||
If you have a wireless card belonging to this class, say Y.
|
||||
|
||||
Note that the answer to this question doesn't directly affect the
|
||||
kernel: saying N will just cause the configurator to skip all
|
||||
the questions about cards. If you say Y, you will be asked for
|
||||
your specific card in the following questions.
|
||||
|
||||
if WLAN_VENDOR_QUANTENNA
|
||||
|
||||
source "drivers/net/wireless/quantenna/qtnfmac/Kconfig"
|
||||
|
||||
endif # WLAN_VENDOR_QUANTENNA
|
6
drivers/net/wireless/quantenna/Makefile
Normal file
6
drivers/net/wireless/quantenna/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
#
|
||||
# Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_QTNFMAC) += qtnfmac/
|
19
drivers/net/wireless/quantenna/qtnfmac/Kconfig
Normal file
19
drivers/net/wireless/quantenna/qtnfmac/Kconfig
Normal file
@ -0,0 +1,19 @@
|
||||
config QTNFMAC
|
||||
tristate
|
||||
depends on QTNFMAC_PEARL_PCIE
|
||||
default m if QTNFMAC_PEARL_PCIE=m
|
||||
default y if QTNFMAC_PEARL_PCIE=y
|
||||
|
||||
config QTNFMAC_PEARL_PCIE
|
||||
tristate "Quantenna QSR10g PCIe support"
|
||||
default n
|
||||
depends on HAS_DMA && PCI && CFG80211
|
||||
select QTNFMAC
|
||||
select FW_LOADER
|
||||
select CRC32
|
||||
---help---
|
||||
This option adds support for wireless adapters based on Quantenna
|
||||
802.11ac QSR10g (aka Pearl) FullMAC chipset running over PCIe.
|
||||
|
||||
If you choose to build it as a module, two modules will be built:
|
||||
qtnfmac.ko and qtnfmac_pearl_pcie.ko.
|
31
drivers/net/wireless/quantenna/qtnfmac/Makefile
Normal file
31
drivers/net/wireless/quantenna/qtnfmac/Makefile
Normal file
@ -0,0 +1,31 @@
|
||||
#
|
||||
# Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
ccflags-y += \
|
||||
-Idrivers/net/wireless/quantenna/qtnfmac
|
||||
|
||||
obj-$(CONFIG_QTNFMAC) += qtnfmac.o
|
||||
qtnfmac-objs += \
|
||||
core.o \
|
||||
commands.o \
|
||||
trans.o \
|
||||
cfg80211.o \
|
||||
event.o \
|
||||
util.o \
|
||||
qlink_util.o
|
||||
|
||||
#
|
||||
|
||||
obj-$(CONFIG_QTNFMAC_PEARL_PCIE) += qtnfmac_pearl_pcie.o
|
||||
|
||||
qtnfmac_pearl_pcie-objs += \
|
||||
shm_ipc.o \
|
||||
pearl/pcie.o
|
||||
|
||||
qtnfmac_pearl_pcie-$(CONFIG_DEBUG_FS) += debug.o
|
||||
|
||||
#
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN
|
139
drivers/net/wireless/quantenna/qtnfmac/bus.h
Normal file
139
drivers/net/wireless/quantenna/qtnfmac/bus.h
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Quantenna Communications
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QTNFMAC_BUS_H
|
||||
#define QTNFMAC_BUS_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define QTNF_MAX_MAC 3
|
||||
|
||||
enum qtnf_fw_state {
|
||||
QTNF_FW_STATE_RESET,
|
||||
QTNF_FW_STATE_FW_DNLD_DONE,
|
||||
QTNF_FW_STATE_BOOT_DONE,
|
||||
QTNF_FW_STATE_ACTIVE,
|
||||
QTNF_FW_STATE_DEAD,
|
||||
};
|
||||
|
||||
struct qtnf_bus;
|
||||
|
||||
struct qtnf_bus_ops {
|
||||
/* mgmt methods */
|
||||
int (*preinit)(struct qtnf_bus *);
|
||||
void (*stop)(struct qtnf_bus *);
|
||||
|
||||
/* control path methods */
|
||||
int (*control_tx)(struct qtnf_bus *, struct sk_buff *);
|
||||
|
||||
/* data xfer methods */
|
||||
int (*data_tx)(struct qtnf_bus *, struct sk_buff *);
|
||||
void (*data_tx_timeout)(struct qtnf_bus *, struct net_device *);
|
||||
void (*data_rx_start)(struct qtnf_bus *);
|
||||
void (*data_rx_stop)(struct qtnf_bus *);
|
||||
};
|
||||
|
||||
struct qtnf_bus {
|
||||
struct device *dev;
|
||||
enum qtnf_fw_state fw_state;
|
||||
u32 chip;
|
||||
u32 chiprev;
|
||||
const struct qtnf_bus_ops *bus_ops;
|
||||
struct qtnf_wmac *mac[QTNF_MAX_MAC];
|
||||
struct qtnf_qlink_transport trans;
|
||||
struct qtnf_hw_info hw_info;
|
||||
char fwname[32];
|
||||
struct napi_struct mux_napi;
|
||||
struct net_device mux_dev;
|
||||
struct completion request_firmware_complete;
|
||||
struct workqueue_struct *workqueue;
|
||||
struct work_struct event_work;
|
||||
struct mutex bus_lock; /* lock during command/event processing */
|
||||
struct dentry *dbg_dir;
|
||||
/* bus private data */
|
||||
char bus_priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
|
||||
static inline void *get_bus_priv(struct qtnf_bus *bus)
|
||||
{
|
||||
if (WARN(!bus, "qtnfmac: invalid bus pointer"))
|
||||
return NULL;
|
||||
|
||||
return &bus->bus_priv;
|
||||
}
|
||||
|
||||
/* callback wrappers */
|
||||
|
||||
static inline int qtnf_bus_preinit(struct qtnf_bus *bus)
|
||||
{
|
||||
if (!bus->bus_ops->preinit)
|
||||
return 0;
|
||||
return bus->bus_ops->preinit(bus);
|
||||
}
|
||||
|
||||
static inline void qtnf_bus_stop(struct qtnf_bus *bus)
|
||||
{
|
||||
if (!bus->bus_ops->stop)
|
||||
return;
|
||||
bus->bus_ops->stop(bus);
|
||||
}
|
||||
|
||||
static inline int qtnf_bus_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
|
||||
{
|
||||
return bus->bus_ops->data_tx(bus, skb);
|
||||
}
|
||||
|
||||
static inline void
|
||||
qtnf_bus_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev)
|
||||
{
|
||||
return bus->bus_ops->data_tx_timeout(bus, ndev);
|
||||
}
|
||||
|
||||
static inline int qtnf_bus_control_tx(struct qtnf_bus *bus, struct sk_buff *skb)
|
||||
{
|
||||
return bus->bus_ops->control_tx(bus, skb);
|
||||
}
|
||||
|
||||
static inline void qtnf_bus_data_rx_start(struct qtnf_bus *bus)
|
||||
{
|
||||
return bus->bus_ops->data_rx_start(bus);
|
||||
}
|
||||
|
||||
static inline void qtnf_bus_data_rx_stop(struct qtnf_bus *bus)
|
||||
{
|
||||
return bus->bus_ops->data_rx_stop(bus);
|
||||
}
|
||||
|
||||
static __always_inline void qtnf_bus_lock(struct qtnf_bus *bus)
|
||||
{
|
||||
mutex_lock(&bus->bus_lock);
|
||||
}
|
||||
|
||||
static __always_inline void qtnf_bus_unlock(struct qtnf_bus *bus)
|
||||
{
|
||||
mutex_unlock(&bus->bus_lock);
|
||||
}
|
||||
|
||||
/* interface functions from common layer */
|
||||
|
||||
void qtnf_rx_frame(struct device *dev, struct sk_buff *rxp);
|
||||
int qtnf_core_attach(struct qtnf_bus *bus);
|
||||
void qtnf_core_detach(struct qtnf_bus *bus);
|
||||
void qtnf_txflowblock(struct device *dev, bool state);
|
||||
void qtnf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
|
||||
|
||||
#endif /* QTNFMAC_BUS_H */
|
995
drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
Normal file
995
drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
Normal file
@ -0,0 +1,995 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2012 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include "cfg80211.h"
|
||||
#include "commands.h"
|
||||
#include "core.h"
|
||||
#include "util.h"
|
||||
#include "bus.h"
|
||||
|
||||
/* Supported rates to be advertised to the cfg80211 */
|
||||
static struct ieee80211_rate qtnf_rates_2g[] = {
|
||||
{.bitrate = 10, .hw_value = 2, },
|
||||
{.bitrate = 20, .hw_value = 4, },
|
||||
{.bitrate = 55, .hw_value = 11, },
|
||||
{.bitrate = 110, .hw_value = 22, },
|
||||
{.bitrate = 60, .hw_value = 12, },
|
||||
{.bitrate = 90, .hw_value = 18, },
|
||||
{.bitrate = 120, .hw_value = 24, },
|
||||
{.bitrate = 180, .hw_value = 36, },
|
||||
{.bitrate = 240, .hw_value = 48, },
|
||||
{.bitrate = 360, .hw_value = 72, },
|
||||
{.bitrate = 480, .hw_value = 96, },
|
||||
{.bitrate = 540, .hw_value = 108, },
|
||||
};
|
||||
|
||||
/* Supported rates to be advertised to the cfg80211 */
|
||||
static struct ieee80211_rate qtnf_rates_5g[] = {
|
||||
{.bitrate = 60, .hw_value = 12, },
|
||||
{.bitrate = 90, .hw_value = 18, },
|
||||
{.bitrate = 120, .hw_value = 24, },
|
||||
{.bitrate = 180, .hw_value = 36, },
|
||||
{.bitrate = 240, .hw_value = 48, },
|
||||
{.bitrate = 360, .hw_value = 72, },
|
||||
{.bitrate = 480, .hw_value = 96, },
|
||||
{.bitrate = 540, .hw_value = 108, },
|
||||
};
|
||||
|
||||
/* Supported crypto cipher suits to be advertised to cfg80211 */
|
||||
static const u32 qtnf_cipher_suites[] = {
|
||||
WLAN_CIPHER_SUITE_TKIP,
|
||||
WLAN_CIPHER_SUITE_CCMP,
|
||||
WLAN_CIPHER_SUITE_AES_CMAC,
|
||||
};
|
||||
|
||||
/* Supported mgmt frame types to be advertised to cfg80211 */
|
||||
static const struct ieee80211_txrx_stypes
|
||||
qtnf_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
[NL80211_IFTYPE_STATION] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
|
||||
},
|
||||
[NL80211_IFTYPE_AP] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
qtnf_change_virtual_intf(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
u8 *mac_addr;
|
||||
int ret;
|
||||
|
||||
if (params)
|
||||
mac_addr = params->macaddr;
|
||||
else
|
||||
mac_addr = NULL;
|
||||
|
||||
qtnf_scan_done(vif->mac, true);
|
||||
|
||||
ret = qtnf_cmd_send_change_intf_type(vif, type, mac_addr);
|
||||
if (ret) {
|
||||
pr_err("VIF%u.%u: failed to change VIF type: %d\n",
|
||||
vif->mac->macid, vif->vifid, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
vif->wdev.iftype = type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
|
||||
{
|
||||
struct net_device *netdev = wdev->netdev;
|
||||
struct qtnf_vif *vif;
|
||||
|
||||
if (WARN_ON(!netdev))
|
||||
return -EFAULT;
|
||||
|
||||
vif = qtnf_netdev_get_priv(wdev->netdev);
|
||||
|
||||
if (qtnf_cmd_send_del_intf(vif))
|
||||
pr_err("VIF%u.%u: failed to delete VIF\n", vif->mac->macid,
|
||||
vif->vifid);
|
||||
|
||||
/* Stop data */
|
||||
netif_tx_stop_all_queues(netdev);
|
||||
if (netif_carrier_ok(netdev))
|
||||
netif_carrier_off(netdev);
|
||||
|
||||
if (netdev->reg_state == NETREG_REGISTERED)
|
||||
unregister_netdevice(netdev);
|
||||
|
||||
vif->netdev->ieee80211_ptr = NULL;
|
||||
vif->netdev = NULL;
|
||||
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
eth_zero_addr(vif->mac_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,
|
||||
const char *name,
|
||||
unsigned char name_assign_t,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct qtnf_wmac *mac;
|
||||
struct qtnf_vif *vif;
|
||||
u8 *mac_addr = NULL;
|
||||
|
||||
mac = wiphy_priv(wiphy);
|
||||
|
||||
if (!mac)
|
||||
return ERR_PTR(-EFAULT);
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_AP:
|
||||
vif = qtnf_mac_get_free_vif(mac);
|
||||
if (!vif) {
|
||||
pr_err("MAC%u: no free VIF available\n", mac->macid);
|
||||
return ERR_PTR(-EFAULT);
|
||||
}
|
||||
|
||||
eth_zero_addr(vif->mac_addr);
|
||||
vif->bss_priority = QTNF_DEF_BSS_PRIORITY;
|
||||
vif->wdev.wiphy = wiphy;
|
||||
vif->wdev.iftype = type;
|
||||
vif->sta_state = QTNF_STA_DISCONNECTED;
|
||||
break;
|
||||
default:
|
||||
pr_err("MAC%u: unsupported IF type %d\n", mac->macid, type);
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
}
|
||||
|
||||
if (params)
|
||||
mac_addr = params->macaddr;
|
||||
|
||||
if (qtnf_cmd_send_add_intf(vif, type, mac_addr)) {
|
||||
pr_err("VIF%u.%u: failed to add VIF\n", mac->macid, vif->vifid);
|
||||
goto err_cmd;
|
||||
}
|
||||
|
||||
if (!is_valid_ether_addr(vif->mac_addr)) {
|
||||
pr_err("VIF%u.%u: FW reported bad MAC: %pM\n",
|
||||
mac->macid, vif->vifid, vif->mac_addr);
|
||||
goto err_mac;
|
||||
}
|
||||
|
||||
if (qtnf_core_net_attach(mac, vif, name, name_assign_t, type)) {
|
||||
pr_err("VIF%u.%u: failed to attach netdev\n", mac->macid,
|
||||
vif->vifid);
|
||||
goto err_net;
|
||||
}
|
||||
|
||||
vif->wdev.netdev = vif->netdev;
|
||||
return &vif->wdev;
|
||||
|
||||
err_net:
|
||||
vif->netdev = NULL;
|
||||
err_mac:
|
||||
qtnf_cmd_send_del_intf(vif);
|
||||
err_cmd:
|
||||
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
|
||||
return ERR_PTR(-EFAULT);
|
||||
}
|
||||
|
||||
static int qtnf_mgmt_set_appie(struct qtnf_vif *vif,
|
||||
const struct cfg80211_beacon_data *info)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!info->beacon_ies || !info->beacon_ies_len) {
|
||||
ret = qtnf_cmd_send_mgmt_set_appie(vif, QLINK_MGMT_FRAME_BEACON,
|
||||
NULL, 0);
|
||||
} else {
|
||||
ret = qtnf_cmd_send_mgmt_set_appie(vif, QLINK_MGMT_FRAME_BEACON,
|
||||
info->beacon_ies,
|
||||
info->beacon_ies_len);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!info->proberesp_ies || !info->proberesp_ies_len) {
|
||||
ret = qtnf_cmd_send_mgmt_set_appie(vif,
|
||||
QLINK_MGMT_FRAME_PROBE_RESP,
|
||||
NULL, 0);
|
||||
} else {
|
||||
ret = qtnf_cmd_send_mgmt_set_appie(vif,
|
||||
QLINK_MGMT_FRAME_PROBE_RESP,
|
||||
info->proberesp_ies,
|
||||
info->proberesp_ies_len);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!info->assocresp_ies || !info->assocresp_ies_len) {
|
||||
ret = qtnf_cmd_send_mgmt_set_appie(vif,
|
||||
QLINK_MGMT_FRAME_ASSOC_RESP,
|
||||
NULL, 0);
|
||||
} else {
|
||||
ret = qtnf_cmd_send_mgmt_set_appie(vif,
|
||||
QLINK_MGMT_FRAME_ASSOC_RESP,
|
||||
info->assocresp_ies,
|
||||
info->assocresp_ies_len);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qtnf_change_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_beacon_data *info)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
|
||||
if (!(vif->bss_status & QTNF_STATE_AP_START)) {
|
||||
pr_err("VIF%u.%u: not started\n", vif->mac->macid, vif->vifid);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return qtnf_mgmt_set_appie(vif, info);
|
||||
}
|
||||
|
||||
static int qtnf_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_ap_settings *settings)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
struct qtnf_bss_config *bss_cfg;
|
||||
int ret;
|
||||
|
||||
bss_cfg = &vif->bss_cfg;
|
||||
|
||||
memset(bss_cfg, 0, sizeof(*bss_cfg));
|
||||
|
||||
bss_cfg->bcn_period = settings->beacon_interval;
|
||||
bss_cfg->dtim = settings->dtim_period;
|
||||
bss_cfg->auth_type = settings->auth_type;
|
||||
bss_cfg->privacy = settings->privacy;
|
||||
|
||||
bss_cfg->ssid_len = settings->ssid_len;
|
||||
memcpy(&bss_cfg->ssid, settings->ssid, bss_cfg->ssid_len);
|
||||
|
||||
memcpy(&bss_cfg->chandef, &settings->chandef,
|
||||
sizeof(struct cfg80211_chan_def));
|
||||
memcpy(&bss_cfg->crypto, &settings->crypto,
|
||||
sizeof(struct cfg80211_crypto_settings));
|
||||
|
||||
ret = qtnf_cmd_send_config_ap(vif);
|
||||
if (ret) {
|
||||
pr_err("VIF%u.%u: failed to push config to FW\n",
|
||||
vif->mac->macid, vif->vifid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(vif->bss_status & QTNF_STATE_AP_CONFIG)) {
|
||||
pr_err("VIF%u.%u: AP config failed in FW\n", vif->mac->macid,
|
||||
vif->vifid);
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qtnf_mgmt_set_appie(vif, &settings->beacon);
|
||||
if (ret) {
|
||||
pr_err("VIF%u.%u: failed to add IEs to beacon\n",
|
||||
vif->mac->macid, vif->vifid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qtnf_cmd_send_start_ap(vif);
|
||||
if (ret) {
|
||||
pr_err("VIF%u.%u: failed to start AP\n", vif->mac->macid,
|
||||
vif->vifid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(vif->bss_status & QTNF_STATE_AP_START)) {
|
||||
pr_err("VIF%u.%u: FW failed to start AP operation\n",
|
||||
vif->mac->macid, vif->vifid);
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = qtnf_cmd_send_stop_ap(vif);
|
||||
if (ret) {
|
||||
pr_err("VIF%u.%u: failed to stop AP operation in FW\n",
|
||||
vif->mac->macid, vif->vifid);
|
||||
vif->bss_status &= ~QTNF_STATE_AP_START;
|
||||
vif->bss_status &= ~QTNF_STATE_AP_CONFIG;
|
||||
|
||||
netif_carrier_off(vif->netdev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qtnf_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
||||
{
|
||||
struct qtnf_wmac *mac = wiphy_priv(wiphy);
|
||||
struct qtnf_vif *vif;
|
||||
int ret;
|
||||
|
||||
vif = qtnf_mac_get_base_vif(mac);
|
||||
if (!vif) {
|
||||
pr_err("MAC%u: primary VIF is not configured\n", mac->macid);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (changed & (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT)) {
|
||||
pr_err("MAC%u: can't modify retry params\n", mac->macid);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = qtnf_cmd_send_update_phy_params(mac, changed);
|
||||
if (ret)
|
||||
pr_err("MAC%u: failed to update PHY params\n", mac->macid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
qtnf_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
|
||||
u16 mgmt_type;
|
||||
u16 new_mask;
|
||||
u16 qlink_frame_type = 0;
|
||||
|
||||
mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
|
||||
|
||||
if (reg)
|
||||
new_mask = vif->mgmt_frames_bitmask | BIT(mgmt_type);
|
||||
else
|
||||
new_mask = vif->mgmt_frames_bitmask & ~BIT(mgmt_type);
|
||||
|
||||
if (new_mask == vif->mgmt_frames_bitmask)
|
||||
return;
|
||||
|
||||
switch (frame_type & IEEE80211_FCTL_STYPE) {
|
||||
case IEEE80211_STYPE_PROBE_REQ:
|
||||
qlink_frame_type = QLINK_MGMT_FRAME_PROBE_REQ;
|
||||
break;
|
||||
case IEEE80211_STYPE_ACTION:
|
||||
qlink_frame_type = QLINK_MGMT_FRAME_ACTION;
|
||||
break;
|
||||
default:
|
||||
pr_warn("VIF%u.%u: unsupported frame type: %X\n",
|
||||
vif->mac->macid, vif->vifid,
|
||||
(frame_type & IEEE80211_FCTL_STYPE) >> 4);
|
||||
return;
|
||||
}
|
||||
|
||||
if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg)) {
|
||||
pr_warn("VIF%u.%u: failed to %sregister mgmt frame type 0x%x\n",
|
||||
vif->mac->macid, vif->vifid, reg ? "" : "un",
|
||||
frame_type);
|
||||
return;
|
||||
}
|
||||
|
||||
vif->mgmt_frames_bitmask = new_mask;
|
||||
pr_debug("VIF%u.%u: %sregistered mgmt frame type 0x%x\n",
|
||||
vif->mac->macid, vif->vifid, reg ? "" : "un", frame_type);
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
|
||||
const struct ieee80211_mgmt *mgmt_frame = (void *)params->buf;
|
||||
u32 short_cookie = prandom_u32();
|
||||
u16 flags = 0;
|
||||
|
||||
*cookie = short_cookie;
|
||||
|
||||
if (params->offchan)
|
||||
flags |= QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN;
|
||||
|
||||
if (params->no_cck)
|
||||
flags |= QLINK_MGMT_FRAME_TX_FLAG_NO_CCK;
|
||||
|
||||
if (params->dont_wait_for_ack)
|
||||
flags |= QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT;
|
||||
|
||||
pr_debug("%s freq:%u; FC:%.4X; DA:%pM; len:%zu; C:%.8X; FL:%.4X\n",
|
||||
wdev->netdev->name, params->chan->center_freq,
|
||||
le16_to_cpu(mgmt_frame->frame_control), mgmt_frame->da,
|
||||
params->len, short_cookie, flags);
|
||||
|
||||
return qtnf_cmd_send_mgmt_frame(vif, short_cookie, flags,
|
||||
params->chan->center_freq,
|
||||
params->buf, params->len);
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_get_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *mac, struct station_info *sinfo)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
|
||||
return qtnf_cmd_get_sta_info(vif, mac, sinfo);
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
int idx, u8 *mac, struct station_info *sinfo)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
const struct qtnf_sta_node *sta_node;
|
||||
int ret;
|
||||
|
||||
sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx);
|
||||
|
||||
if (unlikely(!sta_node))
|
||||
return -ENOENT;
|
||||
|
||||
ether_addr_copy(mac, sta_node->mac_addr);
|
||||
|
||||
ret = qtnf_cmd_get_sta_info(vif, sta_node->mac_addr, sinfo);
|
||||
|
||||
if (unlikely(ret == -ENOENT)) {
|
||||
qtnf_sta_list_del(&vif->sta_list, mac);
|
||||
cfg80211_del_sta(vif->netdev, mac, GFP_KERNEL);
|
||||
sinfo->filled = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qtnf_add_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_index, bool pairwise, const u8 *mac_addr,
|
||||
struct key_params *params)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = qtnf_cmd_send_add_key(vif, key_index, pairwise, mac_addr, params);
|
||||
if (ret)
|
||||
pr_err("VIF%u.%u: failed to add key: cipher=%x idx=%u pw=%u\n",
|
||||
vif->mac->macid, vif->vifid, params->cipher, key_index,
|
||||
pairwise);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qtnf_del_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_index, bool pairwise, const u8 *mac_addr)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = qtnf_cmd_send_del_key(vif, key_index, pairwise, mac_addr);
|
||||
if (ret)
|
||||
pr_err("VIF%u.%u: failed to delete key: idx=%u pw=%u\n",
|
||||
vif->mac->macid, vif->vifid, key_index, pairwise);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qtnf_set_default_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_index, bool unicast, bool multicast)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = qtnf_cmd_send_set_default_key(vif, key_index, unicast, multicast);
|
||||
if (ret)
|
||||
pr_err("VIF%u.%u: failed to set dflt key: idx=%u uc=%u mc=%u\n",
|
||||
vif->mac->macid, vif->vifid, key_index, unicast,
|
||||
multicast);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_index)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = qtnf_cmd_send_set_default_mgmt_key(vif, key_index);
|
||||
if (ret)
|
||||
pr_err("VIF%u.%u: failed to set default MGMT key: idx=%u\n",
|
||||
vif->mac->macid, vif->vifid, key_index);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_change_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *mac, struct station_parameters *params)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = qtnf_cmd_send_change_sta(vif, mac, params);
|
||||
if (ret)
|
||||
pr_err("VIF%u.%u: failed to change STA %pM\n",
|
||||
vif->mac->macid, vif->vifid, mac);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_del_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct station_del_parameters *params)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
if (params->mac &&
|
||||
(vif->wdev.iftype == NL80211_IFTYPE_AP) &&
|
||||
!is_broadcast_ether_addr(params->mac) &&
|
||||
!qtnf_sta_list_lookup(&vif->sta_list, params->mac))
|
||||
return 0;
|
||||
|
||||
qtnf_scan_done(vif->mac, true);
|
||||
|
||||
ret = qtnf_cmd_send_del_sta(vif, params);
|
||||
if (ret)
|
||||
pr_err("VIF%u.%u: failed to delete STA %pM\n",
|
||||
vif->mac->macid, vif->vifid, params->mac);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct qtnf_wmac *mac = wiphy_priv(wiphy);
|
||||
int ret;
|
||||
|
||||
mac->scan_req = request;
|
||||
|
||||
ret = qtnf_cmd_send_scan(mac);
|
||||
if (ret)
|
||||
pr_err("MAC%u: failed to start scan\n", mac->macid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_connect_params *sme)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
struct qtnf_bss_config *bss_cfg;
|
||||
int ret;
|
||||
|
||||
if (vif->wdev.iftype != NL80211_IFTYPE_STATION)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (vif->sta_state != QTNF_STA_DISCONNECTED)
|
||||
return -EBUSY;
|
||||
|
||||
bss_cfg = &vif->bss_cfg;
|
||||
memset(bss_cfg, 0, sizeof(*bss_cfg));
|
||||
|
||||
bss_cfg->ssid_len = sme->ssid_len;
|
||||
memcpy(&bss_cfg->ssid, sme->ssid, bss_cfg->ssid_len);
|
||||
bss_cfg->chandef.chan = sme->channel;
|
||||
bss_cfg->auth_type = sme->auth_type;
|
||||
bss_cfg->privacy = sme->privacy;
|
||||
bss_cfg->mfp = sme->mfp;
|
||||
|
||||
if ((sme->bg_scan_period > 0) &&
|
||||
(sme->bg_scan_period <= QTNF_MAX_BG_SCAN_PERIOD))
|
||||
bss_cfg->bg_scan_period = sme->bg_scan_period;
|
||||
else if (sme->bg_scan_period == -1)
|
||||
bss_cfg->bg_scan_period = QTNF_DEFAULT_BG_SCAN_PERIOD;
|
||||
else
|
||||
bss_cfg->bg_scan_period = 0; /* disabled */
|
||||
|
||||
bss_cfg->connect_flags = 0;
|
||||
|
||||
if (sme->flags & ASSOC_REQ_DISABLE_HT)
|
||||
bss_cfg->connect_flags |= QLINK_STA_CONNECT_DISABLE_HT;
|
||||
if (sme->flags & ASSOC_REQ_DISABLE_VHT)
|
||||
bss_cfg->connect_flags |= QLINK_STA_CONNECT_DISABLE_VHT;
|
||||
if (sme->flags & ASSOC_REQ_USE_RRM)
|
||||
bss_cfg->connect_flags |= QLINK_STA_CONNECT_USE_RRM;
|
||||
|
||||
memcpy(&bss_cfg->crypto, &sme->crypto, sizeof(bss_cfg->crypto));
|
||||
if (sme->bssid)
|
||||
ether_addr_copy(bss_cfg->bssid, sme->bssid);
|
||||
else
|
||||
eth_zero_addr(bss_cfg->bssid);
|
||||
|
||||
ret = qtnf_cmd_send_connect(vif, sme);
|
||||
if (ret) {
|
||||
pr_err("VIF%u.%u: failed to connect\n", vif->mac->macid,
|
||||
vif->vifid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
vif->sta_state = QTNF_STA_CONNECTING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev,
|
||||
u16 reason_code)
|
||||
{
|
||||
struct qtnf_wmac *mac = wiphy_priv(wiphy);
|
||||
struct qtnf_vif *vif;
|
||||
int ret;
|
||||
|
||||
vif = qtnf_mac_get_base_vif(mac);
|
||||
if (!vif) {
|
||||
pr_err("MAC%u: primary VIF is not configured\n", mac->macid);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (vif->wdev.iftype != NL80211_IFTYPE_STATION)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (vif->sta_state == QTNF_STA_DISCONNECTED)
|
||||
return 0;
|
||||
|
||||
ret = qtnf_cmd_send_disconnect(vif, reason_code);
|
||||
if (ret) {
|
||||
pr_err("VIF%u.%u: failed to disconnect\n", mac->macid,
|
||||
vif->vifid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
vif->sta_state = QTNF_STA_DISCONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cfg80211_ops qtn_cfg80211_ops = {
|
||||
.add_virtual_intf = qtnf_add_virtual_intf,
|
||||
.change_virtual_intf = qtnf_change_virtual_intf,
|
||||
.del_virtual_intf = qtnf_del_virtual_intf,
|
||||
.start_ap = qtnf_start_ap,
|
||||
.change_beacon = qtnf_change_beacon,
|
||||
.stop_ap = qtnf_stop_ap,
|
||||
.set_wiphy_params = qtnf_set_wiphy_params,
|
||||
.mgmt_frame_register = qtnf_mgmt_frame_register,
|
||||
.mgmt_tx = qtnf_mgmt_tx,
|
||||
.change_station = qtnf_change_station,
|
||||
.del_station = qtnf_del_station,
|
||||
.get_station = qtnf_get_station,
|
||||
.dump_station = qtnf_dump_station,
|
||||
.add_key = qtnf_add_key,
|
||||
.del_key = qtnf_del_key,
|
||||
.set_default_key = qtnf_set_default_key,
|
||||
.set_default_mgmt_key = qtnf_set_default_mgmt_key,
|
||||
.scan = qtnf_scan,
|
||||
.connect = qtnf_connect,
|
||||
.disconnect = qtnf_disconnect
|
||||
};
|
||||
|
||||
static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy,
|
||||
struct regulatory_request *req)
|
||||
{
|
||||
struct qtnf_wmac *mac = wiphy_priv(wiphy);
|
||||
struct qtnf_bus *bus;
|
||||
struct qtnf_vif *vif;
|
||||
struct qtnf_wmac *chan_mac;
|
||||
int i;
|
||||
enum nl80211_band band;
|
||||
|
||||
bus = mac->bus;
|
||||
|
||||
pr_debug("MAC%u: initiator=%d alpha=%c%c\n", mac->macid, req->initiator,
|
||||
req->alpha2[0], req->alpha2[1]);
|
||||
|
||||
vif = qtnf_mac_get_base_vif(mac);
|
||||
if (!vif) {
|
||||
pr_err("MAC%u: primary VIF is not configured\n", mac->macid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ignore non-ISO3166 country codes */
|
||||
for (i = 0; i < sizeof(req->alpha2); i++) {
|
||||
if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
|
||||
pr_err("MAC%u: not an ISO3166 code\n", mac->macid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!strncasecmp(req->alpha2, bus->hw_info.alpha2_code,
|
||||
sizeof(req->alpha2))) {
|
||||
pr_warn("MAC%u: unchanged country code\n", mac->macid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (qtnf_cmd_send_regulatory_config(mac, req->alpha2)) {
|
||||
pr_err("MAC%u: failed to configure regulatory\n", mac->macid);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < bus->hw_info.num_mac; i++) {
|
||||
chan_mac = bus->mac[i];
|
||||
|
||||
if (!chan_mac)
|
||||
continue;
|
||||
|
||||
if (!(bus->hw_info.mac_bitmap & BIT(i)))
|
||||
continue;
|
||||
|
||||
for (band = 0; band < NUM_NL80211_BANDS; ++band) {
|
||||
if (!wiphy->bands[band])
|
||||
continue;
|
||||
|
||||
if (qtnf_cmd_get_mac_chan_info(chan_mac,
|
||||
wiphy->bands[band])) {
|
||||
pr_err("MAC%u: can't get channel info\n",
|
||||
chan_mac->macid);
|
||||
qtnf_core_detach(bus);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qtnf_band_setup_htvht_caps(struct qtnf_mac_info *macinfo,
|
||||
struct ieee80211_supported_band *band)
|
||||
{
|
||||
struct ieee80211_sta_ht_cap *ht_cap;
|
||||
struct ieee80211_sta_vht_cap *vht_cap;
|
||||
|
||||
ht_cap = &band->ht_cap;
|
||||
ht_cap->ht_supported = true;
|
||||
memcpy(&ht_cap->cap, &macinfo->ht_cap.cap_info,
|
||||
sizeof(u16));
|
||||
ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
||||
ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
|
||||
memcpy(&ht_cap->mcs, &macinfo->ht_cap.mcs,
|
||||
sizeof(ht_cap->mcs));
|
||||
|
||||
if (macinfo->phymode_cap & QLINK_PHYMODE_AC) {
|
||||
vht_cap = &band->vht_cap;
|
||||
vht_cap->vht_supported = true;
|
||||
memcpy(&vht_cap->cap,
|
||||
&macinfo->vht_cap.vht_cap_info, sizeof(u32));
|
||||
/* Update MCS support for VHT */
|
||||
memcpy(&vht_cap->vht_mcs,
|
||||
&macinfo->vht_cap.supp_mcs,
|
||||
sizeof(struct ieee80211_vht_mcs_info));
|
||||
}
|
||||
}
|
||||
|
||||
struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus)
|
||||
{
|
||||
struct wiphy *wiphy;
|
||||
|
||||
wiphy = wiphy_new(&qtn_cfg80211_ops, sizeof(struct qtnf_wmac));
|
||||
if (!wiphy)
|
||||
return NULL;
|
||||
|
||||
set_wiphy_dev(wiphy, bus->dev);
|
||||
|
||||
return wiphy;
|
||||
}
|
||||
|
||||
static int qtnf_wiphy_setup_if_comb(struct wiphy *wiphy,
|
||||
struct ieee80211_iface_combination *if_comb,
|
||||
const struct qtnf_mac_info *mac_info)
|
||||
{
|
||||
size_t max_interfaces = 0;
|
||||
u16 interface_modes = 0;
|
||||
size_t i;
|
||||
|
||||
if (unlikely(!mac_info->limits || !mac_info->n_limits))
|
||||
return -ENOENT;
|
||||
|
||||
if_comb->limits = mac_info->limits;
|
||||
if_comb->n_limits = mac_info->n_limits;
|
||||
|
||||
for (i = 0; i < mac_info->n_limits; i++) {
|
||||
max_interfaces += mac_info->limits[i].max;
|
||||
interface_modes |= mac_info->limits[i].types;
|
||||
}
|
||||
|
||||
if_comb->num_different_channels = 1;
|
||||
if_comb->beacon_int_infra_match = true;
|
||||
if_comb->max_interfaces = max_interfaces;
|
||||
if_comb->radar_detect_widths = mac_info->radar_detect_widths;
|
||||
wiphy->interface_modes = interface_modes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
|
||||
{
|
||||
struct wiphy *wiphy = priv_to_wiphy(mac);
|
||||
struct ieee80211_iface_combination *iface_comb = NULL;
|
||||
int ret;
|
||||
|
||||
if (!wiphy) {
|
||||
pr_err("invalid wiphy pointer\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
iface_comb = kzalloc(sizeof(*iface_comb), GFP_KERNEL);
|
||||
if (!iface_comb) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qtnf_wiphy_setup_if_comb(wiphy, iface_comb, &mac->macinfo);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
pr_info("MAC%u: phymode=%#x radar=%#x\n", mac->macid,
|
||||
mac->macinfo.phymode_cap, mac->macinfo.radar_detect_widths);
|
||||
|
||||
wiphy->frag_threshold = mac->macinfo.frag_thr;
|
||||
wiphy->rts_threshold = mac->macinfo.rts_thr;
|
||||
wiphy->retry_short = mac->macinfo.sretry_limit;
|
||||
wiphy->retry_long = mac->macinfo.lretry_limit;
|
||||
wiphy->coverage_class = mac->macinfo.coverage_class;
|
||||
|
||||
wiphy->max_scan_ssids = QTNF_MAX_SSID_LIST_LENGTH;
|
||||
wiphy->max_scan_ie_len = QTNF_MAX_VSIE_LEN;
|
||||
wiphy->mgmt_stypes = qtnf_mgmt_stypes;
|
||||
wiphy->max_remain_on_channel_duration = 5000;
|
||||
|
||||
wiphy->iface_combinations = iface_comb;
|
||||
wiphy->n_iface_combinations = 1;
|
||||
|
||||
/* Initialize cipher suits */
|
||||
wiphy->cipher_suites = qtnf_cipher_suites;
|
||||
wiphy->n_cipher_suites = ARRAY_SIZE(qtnf_cipher_suites);
|
||||
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
|
||||
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
|
||||
WIPHY_FLAG_AP_UAPSD;
|
||||
|
||||
wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2;
|
||||
|
||||
wiphy->available_antennas_tx = mac->macinfo.num_tx_chain;
|
||||
wiphy->available_antennas_rx = mac->macinfo.num_rx_chain;
|
||||
|
||||
wiphy->max_ap_assoc_sta = mac->macinfo.max_ap_assoc_sta;
|
||||
|
||||
ether_addr_copy(wiphy->perm_addr, mac->macaddr);
|
||||
|
||||
if (hw_info->hw_capab & QLINK_HW_SUPPORTS_REG_UPDATE) {
|
||||
pr_debug("device supports REG_UPDATE\n");
|
||||
wiphy->reg_notifier = qtnf_cfg80211_reg_notifier;
|
||||
pr_debug("hint regulatory about EP region: %c%c\n",
|
||||
hw_info->alpha2_code[0],
|
||||
hw_info->alpha2_code[1]);
|
||||
regulatory_hint(wiphy, hw_info->alpha2_code);
|
||||
} else {
|
||||
pr_debug("device doesn't support REG_UPDATE\n");
|
||||
wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
|
||||
}
|
||||
|
||||
ret = wiphy_register(wiphy);
|
||||
|
||||
out:
|
||||
if (ret < 0) {
|
||||
kfree(iface_comb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qtnf_netdev_updown(struct net_device *ndev, bool up)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||
|
||||
if (qtnf_cmd_send_updown_intf(vif, up))
|
||||
pr_err("failed to send up/down command to FW\n");
|
||||
}
|
||||
|
||||
void qtnf_virtual_intf_cleanup(struct net_device *ndev)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||
struct qtnf_wmac *mac = wiphy_priv(vif->wdev.wiphy);
|
||||
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_STATION) {
|
||||
switch (vif->sta_state) {
|
||||
case QTNF_STA_DISCONNECTED:
|
||||
break;
|
||||
case QTNF_STA_CONNECTING:
|
||||
cfg80211_connect_result(vif->netdev,
|
||||
vif->bss_cfg.bssid, NULL, 0,
|
||||
NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
GFP_KERNEL);
|
||||
qtnf_disconnect(vif->wdev.wiphy, ndev,
|
||||
WLAN_REASON_DEAUTH_LEAVING);
|
||||
break;
|
||||
case QTNF_STA_CONNECTED:
|
||||
cfg80211_disconnected(vif->netdev,
|
||||
WLAN_REASON_DEAUTH_LEAVING,
|
||||
NULL, 0, 1, GFP_KERNEL);
|
||||
qtnf_disconnect(vif->wdev.wiphy, ndev,
|
||||
WLAN_REASON_DEAUTH_LEAVING);
|
||||
break;
|
||||
}
|
||||
|
||||
vif->sta_state = QTNF_STA_DISCONNECTED;
|
||||
qtnf_scan_done(mac, true);
|
||||
}
|
||||
}
|
||||
|
||||
void qtnf_cfg80211_vif_reset(struct qtnf_vif *vif)
|
||||
{
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_STATION) {
|
||||
switch (vif->sta_state) {
|
||||
case QTNF_STA_CONNECTING:
|
||||
cfg80211_connect_result(vif->netdev,
|
||||
vif->bss_cfg.bssid, NULL, 0,
|
||||
NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
GFP_KERNEL);
|
||||
break;
|
||||
case QTNF_STA_CONNECTED:
|
||||
cfg80211_disconnected(vif->netdev,
|
||||
WLAN_REASON_DEAUTH_LEAVING,
|
||||
NULL, 0, 1, GFP_KERNEL);
|
||||
break;
|
||||
case QTNF_STA_DISCONNECTED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cfg80211_shutdown_all_interfaces(vif->wdev.wiphy);
|
||||
vif->sta_state = QTNF_STA_DISCONNECTED;
|
||||
}
|
||||
|
||||
void qtnf_band_init_rates(struct ieee80211_supported_band *band)
|
||||
{
|
||||
switch (band->band) {
|
||||
case NL80211_BAND_2GHZ:
|
||||
band->bitrates = qtnf_rates_2g;
|
||||
band->n_bitrates = ARRAY_SIZE(qtnf_rates_2g);
|
||||
break;
|
||||
case NL80211_BAND_5GHZ:
|
||||
band->bitrates = qtnf_rates_5g;
|
||||
band->n_bitrates = ARRAY_SIZE(qtnf_rates_5g);
|
||||
break;
|
||||
default:
|
||||
band->bitrates = NULL;
|
||||
band->n_bitrates = 0;
|
||||
break;
|
||||
}
|
||||
}
|
43
drivers/net/wireless/quantenna/qtnfmac/cfg80211.h
Normal file
43
drivers/net/wireless/quantenna/qtnfmac/cfg80211.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_FMAC_CFG80211_H_
|
||||
#define _QTN_FMAC_CFG80211_H_
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac);
|
||||
int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev);
|
||||
void qtnf_cfg80211_vif_reset(struct qtnf_vif *vif);
|
||||
void qtnf_band_init_rates(struct ieee80211_supported_band *band);
|
||||
void qtnf_band_setup_htvht_caps(struct qtnf_mac_info *macinfo,
|
||||
struct ieee80211_supported_band *band);
|
||||
|
||||
static inline void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted)
|
||||
{
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = aborted,
|
||||
};
|
||||
|
||||
if (mac->scan_req) {
|
||||
cfg80211_scan_done(mac->scan_req, &info);
|
||||
mac->scan_req = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _QTN_FMAC_CFG80211_H_ */
|
1982
drivers/net/wireless/quantenna/qtnfmac/commands.c
Normal file
1982
drivers/net/wireless/quantenna/qtnfmac/commands.c
Normal file
File diff suppressed because it is too large
Load Diff
74
drivers/net/wireless/quantenna/qtnfmac/commands.h
Normal file
74
drivers/net/wireless/quantenna/qtnfmac/commands.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Quantenna Communications, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QLINK_COMMANDS_H_
|
||||
#define QLINK_COMMANDS_H_
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "bus.h"
|
||||
|
||||
int qtnf_cmd_send_init_fw(struct qtnf_bus *bus);
|
||||
void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus);
|
||||
int qtnf_cmd_get_hw_info(struct qtnf_bus *bus);
|
||||
int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac);
|
||||
int qtnf_cmd_send_add_intf(struct qtnf_vif *vif, enum nl80211_iftype iftype,
|
||||
u8 *mac_addr);
|
||||
int qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif,
|
||||
enum nl80211_iftype iftype, u8 *mac_addr);
|
||||
int qtnf_cmd_send_del_intf(struct qtnf_vif *vif);
|
||||
int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
|
||||
struct ieee80211_supported_band *band);
|
||||
int qtnf_cmd_send_regulatory_config(struct qtnf_wmac *mac, const char *alpha2);
|
||||
int qtnf_cmd_send_config_ap(struct qtnf_vif *vif);
|
||||
int qtnf_cmd_send_start_ap(struct qtnf_vif *vif);
|
||||
int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif);
|
||||
int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg);
|
||||
int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
|
||||
u16 freq, const u8 *buf, size_t len);
|
||||
int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,
|
||||
const u8 *buf, size_t len);
|
||||
int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
|
||||
struct station_info *sinfo);
|
||||
int qtnf_cmd_send_phy_params(struct qtnf_wmac *mac, u16 cmd_action,
|
||||
void *data_buf);
|
||||
int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
|
||||
const u8 *mac_addr, struct key_params *params);
|
||||
int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
|
||||
const u8 *mac_addr);
|
||||
int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index,
|
||||
bool unicast, bool multicast);
|
||||
int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index);
|
||||
int qtnf_cmd_send_add_sta(struct qtnf_vif *vif, const u8 *mac,
|
||||
struct station_parameters *params);
|
||||
int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac,
|
||||
struct station_parameters *params);
|
||||
int qtnf_cmd_send_del_sta(struct qtnf_vif *vif,
|
||||
struct station_del_parameters *params);
|
||||
|
||||
int qtnf_cmd_resp_parse(struct qtnf_bus *bus, struct sk_buff *resp_skb);
|
||||
int qtnf_cmd_resp_check(const struct qtnf_vif *vif,
|
||||
const struct sk_buff *resp_skb, u16 cmd_id,
|
||||
u16 *result, const u8 **payload, size_t *payload_size);
|
||||
int qtnf_cmd_send_scan(struct qtnf_wmac *mac);
|
||||
int qtnf_cmd_send_connect(struct qtnf_vif *vif,
|
||||
struct cfg80211_connect_params *sme);
|
||||
int qtnf_cmd_send_disconnect(struct qtnf_vif *vif,
|
||||
u16 reason_code);
|
||||
int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif,
|
||||
bool up);
|
||||
|
||||
#endif /* QLINK_COMMANDS_H_ */
|
618
drivers/net/wireless/quantenna/qtnfmac/core.c
Normal file
618
drivers/net/wireless/quantenna/qtnfmac/core.c
Normal file
@ -0,0 +1,618 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "bus.h"
|
||||
#include "trans.h"
|
||||
#include "commands.h"
|
||||
#include "cfg80211.h"
|
||||
#include "event.h"
|
||||
#include "util.h"
|
||||
|
||||
#define QTNF_DMP_MAX_LEN 48
|
||||
#define QTNF_PRIMARY_VIF_IDX 0
|
||||
|
||||
struct qtnf_frame_meta_info {
|
||||
u8 magic_s;
|
||||
u8 ifidx;
|
||||
u8 macid;
|
||||
u8 magic_e;
|
||||
} __packed;
|
||||
|
||||
struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid)
|
||||
{
|
||||
struct qtnf_wmac *mac = NULL;
|
||||
|
||||
if (unlikely(macid >= QTNF_MAX_MAC)) {
|
||||
pr_err("invalid MAC index %u\n", macid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mac = bus->mac[macid];
|
||||
|
||||
if (unlikely(!mac)) {
|
||||
pr_err("MAC%u: not initialized\n", macid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mac;
|
||||
}
|
||||
|
||||
/* Netdev handler for open.
|
||||
*/
|
||||
static int qtnf_netdev_open(struct net_device *ndev)
|
||||
{
|
||||
netif_carrier_off(ndev);
|
||||
qtnf_netdev_updown(ndev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Netdev handler for close.
|
||||
*/
|
||||
static int qtnf_netdev_close(struct net_device *ndev)
|
||||
{
|
||||
netif_carrier_off(ndev);
|
||||
qtnf_virtual_intf_cleanup(ndev);
|
||||
qtnf_netdev_updown(ndev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Netdev handler for data transmission.
|
||||
*/
|
||||
static int
|
||||
qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
struct qtnf_vif *vif;
|
||||
struct qtnf_wmac *mac;
|
||||
|
||||
vif = qtnf_netdev_get_priv(ndev);
|
||||
|
||||
if (unlikely(skb->dev != ndev)) {
|
||||
pr_err_ratelimited("invalid skb->dev");
|
||||
dev_kfree_skb_any(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)) {
|
||||
pr_err_ratelimited("%s: VIF not initialized\n", ndev->name);
|
||||
dev_kfree_skb_any(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mac = vif->mac;
|
||||
if (unlikely(!mac)) {
|
||||
pr_err_ratelimited("%s: NULL mac pointer", ndev->name);
|
||||
dev_kfree_skb_any(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
|
||||
pr_err_ratelimited("%s: invalid skb len %d\n", ndev->name,
|
||||
skb->len);
|
||||
dev_kfree_skb_any(skb);
|
||||
ndev->stats.tx_dropped++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tx path is enabled: reset vif timeout */
|
||||
vif->cons_tx_timeout_cnt = 0;
|
||||
|
||||
return qtnf_bus_data_tx(mac->bus, skb);
|
||||
}
|
||||
|
||||
/* Netdev handler for getting stats.
|
||||
*/
|
||||
static struct net_device_stats *qtnf_netdev_get_stats(struct net_device *dev)
|
||||
{
|
||||
return &dev->stats;
|
||||
}
|
||||
|
||||
/* Netdev handler for transmission timeout.
|
||||
*/
|
||||
static void qtnf_netdev_tx_timeout(struct net_device *ndev)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
|
||||
struct qtnf_wmac *mac;
|
||||
struct qtnf_bus *bus;
|
||||
|
||||
if (unlikely(!vif || !vif->mac || !vif->mac->bus))
|
||||
return;
|
||||
|
||||
mac = vif->mac;
|
||||
bus = mac->bus;
|
||||
|
||||
pr_warn("VIF%u.%u: Tx timeout- %lu\n", mac->macid, vif->vifid, jiffies);
|
||||
|
||||
qtnf_bus_data_tx_timeout(bus, ndev);
|
||||
ndev->stats.tx_errors++;
|
||||
|
||||
if (++vif->cons_tx_timeout_cnt > QTNF_TX_TIMEOUT_TRSHLD) {
|
||||
pr_err("Tx timeout threshold exceeded !\n");
|
||||
pr_err("schedule interface %s reset !\n", netdev_name(ndev));
|
||||
queue_work(bus->workqueue, &vif->reset_work);
|
||||
}
|
||||
}
|
||||
|
||||
/* Network device ops handlers */
|
||||
const struct net_device_ops qtnf_netdev_ops = {
|
||||
.ndo_open = qtnf_netdev_open,
|
||||
.ndo_stop = qtnf_netdev_close,
|
||||
.ndo_start_xmit = qtnf_netdev_hard_start_xmit,
|
||||
.ndo_tx_timeout = qtnf_netdev_tx_timeout,
|
||||
.ndo_get_stats = qtnf_netdev_get_stats,
|
||||
};
|
||||
|
||||
static int qtnf_mac_init_single_band(struct wiphy *wiphy,
|
||||
struct qtnf_wmac *mac,
|
||||
enum nl80211_band band)
|
||||
{
|
||||
int ret;
|
||||
|
||||
wiphy->bands[band] = kzalloc(sizeof(*wiphy->bands[band]), GFP_KERNEL);
|
||||
if (!wiphy->bands[band])
|
||||
return -ENOMEM;
|
||||
|
||||
wiphy->bands[band]->band = band;
|
||||
|
||||
ret = qtnf_cmd_get_mac_chan_info(mac, wiphy->bands[band]);
|
||||
if (ret) {
|
||||
pr_err("MAC%u: band %u: failed to get chans info: %d\n",
|
||||
mac->macid, band, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
qtnf_band_init_rates(wiphy->bands[band]);
|
||||
qtnf_band_setup_htvht_caps(&mac->macinfo, wiphy->bands[band]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qtnf_mac_init_bands(struct qtnf_wmac *mac)
|
||||
{
|
||||
struct wiphy *wiphy = priv_to_wiphy(mac);
|
||||
int ret = 0;
|
||||
|
||||
if (mac->macinfo.bands_cap & QLINK_BAND_2GHZ) {
|
||||
ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_2GHZ);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mac->macinfo.bands_cap & QLINK_BAND_5GHZ) {
|
||||
ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_5GHZ);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mac->macinfo.bands_cap & QLINK_BAND_60GHZ)
|
||||
ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_60GHZ);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac)
|
||||
{
|
||||
struct qtnf_vif *vif;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < QTNF_MAX_INTF; i++) {
|
||||
vif = &mac->iflist[i];
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
|
||||
return vif;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac)
|
||||
{
|
||||
struct qtnf_vif *vif;
|
||||
|
||||
vif = &mac->iflist[QTNF_PRIMARY_VIF_IDX];
|
||||
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
|
||||
return NULL;
|
||||
|
||||
return vif;
|
||||
}
|
||||
|
||||
static void qtnf_vif_reset_handler(struct work_struct *work)
|
||||
{
|
||||
struct qtnf_vif *vif = container_of(work, struct qtnf_vif, reset_work);
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) {
|
||||
rtnl_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
/* stop tx completely */
|
||||
netif_tx_stop_all_queues(vif->netdev);
|
||||
if (netif_carrier_ok(vif->netdev))
|
||||
netif_carrier_off(vif->netdev);
|
||||
|
||||
qtnf_cfg80211_vif_reset(vif);
|
||||
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static void qtnf_mac_init_primary_intf(struct qtnf_wmac *mac)
|
||||
{
|
||||
struct qtnf_vif *vif = &mac->iflist[QTNF_PRIMARY_VIF_IDX];
|
||||
|
||||
vif->wdev.iftype = NL80211_IFTYPE_AP;
|
||||
vif->bss_priority = QTNF_DEF_BSS_PRIORITY;
|
||||
vif->wdev.wiphy = priv_to_wiphy(mac);
|
||||
INIT_WORK(&vif->reset_work, qtnf_vif_reset_handler);
|
||||
vif->cons_tx_timeout_cnt = 0;
|
||||
}
|
||||
|
||||
static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
|
||||
unsigned int macid)
|
||||
{
|
||||
struct wiphy *wiphy;
|
||||
struct qtnf_wmac *mac;
|
||||
unsigned int i;
|
||||
|
||||
wiphy = qtnf_wiphy_allocate(bus);
|
||||
if (!wiphy)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mac = wiphy_priv(wiphy);
|
||||
|
||||
mac->macid = macid;
|
||||
mac->bus = bus;
|
||||
|
||||
for (i = 0; i < QTNF_MAX_INTF; i++) {
|
||||
memset(&mac->iflist[i], 0, sizeof(struct qtnf_vif));
|
||||
mac->iflist[i].wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
mac->iflist[i].mac = mac;
|
||||
mac->iflist[i].vifid = i;
|
||||
qtnf_sta_list_init(&mac->iflist[i].sta_list);
|
||||
}
|
||||
|
||||
qtnf_mac_init_primary_intf(mac);
|
||||
bus->mac[macid] = mac;
|
||||
|
||||
return mac;
|
||||
}
|
||||
|
||||
int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,
|
||||
const char *name, unsigned char name_assign_type,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
struct wiphy *wiphy = priv_to_wiphy(mac);
|
||||
struct net_device *dev;
|
||||
void *qdev_vif;
|
||||
int ret;
|
||||
|
||||
dev = alloc_netdev_mqs(sizeof(struct qtnf_vif *), name,
|
||||
name_assign_type, ether_setup, 1, 1);
|
||||
if (!dev) {
|
||||
memset(&vif->wdev, 0, sizeof(vif->wdev));
|
||||
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vif->netdev = dev;
|
||||
|
||||
dev->netdev_ops = &qtnf_netdev_ops;
|
||||
dev->destructor = free_netdev;
|
||||
dev_net_set(dev, wiphy_net(wiphy));
|
||||
dev->ieee80211_ptr = &vif->wdev;
|
||||
dev->ieee80211_ptr->iftype = iftype;
|
||||
ether_addr_copy(dev->dev_addr, vif->mac_addr);
|
||||
SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
|
||||
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
|
||||
dev->watchdog_timeo = QTNF_DEF_WDOG_TIMEOUT;
|
||||
dev->tx_queue_len = 100;
|
||||
|
||||
qdev_vif = netdev_priv(dev);
|
||||
*((void **)qdev_vif) = vif;
|
||||
|
||||
SET_NETDEV_DEV(dev, mac->bus->dev);
|
||||
|
||||
ret = register_netdevice(dev);
|
||||
if (ret) {
|
||||
free_netdev(dev);
|
||||
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)
|
||||
{
|
||||
struct qtnf_wmac *mac;
|
||||
struct wiphy *wiphy;
|
||||
struct qtnf_vif *vif;
|
||||
unsigned int i;
|
||||
enum nl80211_band band;
|
||||
|
||||
mac = bus->mac[macid];
|
||||
|
||||
if (!mac)
|
||||
return;
|
||||
|
||||
wiphy = priv_to_wiphy(mac);
|
||||
|
||||
for (i = 0; i < QTNF_MAX_INTF; i++) {
|
||||
vif = &mac->iflist[i];
|
||||
rtnl_lock();
|
||||
if (vif->netdev &&
|
||||
vif->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) {
|
||||
qtnf_virtual_intf_cleanup(vif->netdev);
|
||||
qtnf_del_virtual_intf(wiphy, &vif->wdev);
|
||||
}
|
||||
rtnl_unlock();
|
||||
qtnf_sta_list_free(&vif->sta_list);
|
||||
}
|
||||
|
||||
if (mac->wiphy_registered)
|
||||
wiphy_unregister(wiphy);
|
||||
|
||||
for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; ++band) {
|
||||
if (!wiphy->bands[band])
|
||||
continue;
|
||||
|
||||
kfree(wiphy->bands[band]->channels);
|
||||
wiphy->bands[band]->n_channels = 0;
|
||||
|
||||
kfree(wiphy->bands[band]);
|
||||
wiphy->bands[band] = NULL;
|
||||
}
|
||||
|
||||
kfree(mac->macinfo.limits);
|
||||
kfree(wiphy->iface_combinations);
|
||||
wiphy_free(wiphy);
|
||||
bus->mac[macid] = NULL;
|
||||
}
|
||||
|
||||
static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid)
|
||||
{
|
||||
struct qtnf_wmac *mac;
|
||||
struct qtnf_vif *vif;
|
||||
int ret;
|
||||
|
||||
if (!(bus->hw_info.mac_bitmap & BIT(macid))) {
|
||||
pr_info("MAC%u is not active in FW\n", macid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mac = qtnf_core_mac_alloc(bus, macid);
|
||||
if (IS_ERR(mac)) {
|
||||
pr_err("MAC%u allocation failed\n", macid);
|
||||
return PTR_ERR(mac);
|
||||
}
|
||||
|
||||
ret = qtnf_cmd_get_mac_info(mac);
|
||||
if (ret) {
|
||||
pr_err("MAC%u: failed to get info\n", macid);
|
||||
goto error;
|
||||
}
|
||||
|
||||
vif = qtnf_mac_get_base_vif(mac);
|
||||
if (!vif) {
|
||||
pr_err("MAC%u: primary VIF is not ready\n", macid);
|
||||
ret = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = qtnf_cmd_send_add_intf(vif, NL80211_IFTYPE_AP, vif->mac_addr);
|
||||
if (ret) {
|
||||
pr_err("MAC%u: failed to add VIF\n", macid);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = qtnf_cmd_send_get_phy_params(mac);
|
||||
if (ret) {
|
||||
pr_err("MAC%u: failed to get PHY settings\n", macid);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = qtnf_mac_init_bands(mac);
|
||||
if (ret) {
|
||||
pr_err("MAC%u: failed to init bands\n", macid);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = qtnf_wiphy_register(&bus->hw_info, mac);
|
||||
if (ret) {
|
||||
pr_err("MAC%u: wiphy registration failed\n", macid);
|
||||
goto error;
|
||||
}
|
||||
|
||||
mac->wiphy_registered = 1;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
ret = qtnf_core_net_attach(mac, vif, "wlan%d", NET_NAME_ENUM,
|
||||
NL80211_IFTYPE_AP);
|
||||
rtnl_unlock();
|
||||
|
||||
if (ret) {
|
||||
pr_err("MAC%u: failed to attach netdev\n", macid);
|
||||
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
vif->netdev = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pr_debug("MAC%u initialized\n", macid);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
qtnf_core_mac_detach(bus, macid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qtnf_core_attach(struct qtnf_bus *bus)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
qtnf_trans_init(bus);
|
||||
|
||||
bus->fw_state = QTNF_FW_STATE_BOOT_DONE;
|
||||
qtnf_bus_data_rx_start(bus);
|
||||
|
||||
bus->workqueue = alloc_ordered_workqueue("QTNF_BUS", 0);
|
||||
if (!bus->workqueue) {
|
||||
pr_err("failed to alloc main workqueue\n");
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
INIT_WORK(&bus->event_work, qtnf_event_work_handler);
|
||||
|
||||
ret = qtnf_cmd_send_init_fw(bus);
|
||||
if (ret) {
|
||||
pr_err("failed to init FW: %d\n", ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
bus->fw_state = QTNF_FW_STATE_ACTIVE;
|
||||
|
||||
ret = qtnf_cmd_get_hw_info(bus);
|
||||
if (ret) {
|
||||
pr_err("failed to get HW info: %d\n", ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bus->hw_info.ql_proto_ver != QLINK_PROTO_VER) {
|
||||
pr_err("qlink version mismatch %u != %u\n",
|
||||
QLINK_PROTO_VER, bus->hw_info.ql_proto_ver);
|
||||
ret = -EPROTONOSUPPORT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bus->hw_info.num_mac > QTNF_MAX_MAC) {
|
||||
pr_err("no support for number of MACs=%u\n",
|
||||
bus->hw_info.num_mac);
|
||||
ret = -ERANGE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < bus->hw_info.num_mac; i++) {
|
||||
ret = qtnf_core_mac_attach(bus, i);
|
||||
|
||||
if (ret) {
|
||||
pr_err("MAC%u: attach failed: %d\n", i, ret);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
qtnf_core_detach(bus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qtnf_core_attach);
|
||||
|
||||
void qtnf_core_detach(struct qtnf_bus *bus)
|
||||
{
|
||||
unsigned int macid;
|
||||
|
||||
qtnf_bus_data_rx_stop(bus);
|
||||
|
||||
for (macid = 0; macid < QTNF_MAX_MAC; macid++)
|
||||
qtnf_core_mac_detach(bus, macid);
|
||||
|
||||
if (bus->fw_state == QTNF_FW_STATE_ACTIVE)
|
||||
qtnf_cmd_send_deinit_fw(bus);
|
||||
|
||||
bus->fw_state = QTNF_FW_STATE_DEAD;
|
||||
|
||||
if (bus->workqueue) {
|
||||
flush_workqueue(bus->workqueue);
|
||||
destroy_workqueue(bus->workqueue);
|
||||
}
|
||||
|
||||
qtnf_trans_free(bus);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qtnf_core_detach);
|
||||
|
||||
static inline int qtnf_is_frame_meta_magic_valid(struct qtnf_frame_meta_info *m)
|
||||
{
|
||||
return m->magic_s == 0xAB && m->magic_e == 0xBA;
|
||||
}
|
||||
|
||||
struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb)
|
||||
{
|
||||
struct qtnf_frame_meta_info *meta;
|
||||
struct net_device *ndev = NULL;
|
||||
struct qtnf_wmac *mac;
|
||||
struct qtnf_vif *vif;
|
||||
|
||||
meta = (struct qtnf_frame_meta_info *)
|
||||
(skb_tail_pointer(skb) - sizeof(*meta));
|
||||
|
||||
if (unlikely(!qtnf_is_frame_meta_magic_valid(meta))) {
|
||||
pr_err_ratelimited("invalid magic 0x%x:0x%x\n",
|
||||
meta->magic_s, meta->magic_e);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(meta->macid >= QTNF_MAX_MAC)) {
|
||||
pr_err_ratelimited("invalid mac(%u)\n", meta->macid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(meta->ifidx >= QTNF_MAX_INTF)) {
|
||||
pr_err_ratelimited("invalid vif(%u)\n", meta->ifidx);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mac = bus->mac[meta->macid];
|
||||
|
||||
if (unlikely(!mac)) {
|
||||
pr_err_ratelimited("mac(%d) does not exist\n", meta->macid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
vif = &mac->iflist[meta->ifidx];
|
||||
|
||||
if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)) {
|
||||
pr_err_ratelimited("vif(%u) does not exists\n", meta->ifidx);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ndev = vif->netdev;
|
||||
|
||||
if (unlikely(!ndev)) {
|
||||
pr_err_ratelimited("netdev for wlan%u.%u does not exists\n",
|
||||
meta->macid, meta->ifidx);
|
||||
goto out;
|
||||
}
|
||||
|
||||
__skb_trim(skb, skb->len - sizeof(*meta));
|
||||
|
||||
out:
|
||||
return ndev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qtnf_classify_skb);
|
||||
|
||||
MODULE_AUTHOR("Quantenna Communications");
|
||||
MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver.");
|
||||
MODULE_LICENSE("GPL");
|
173
drivers/net/wireless/quantenna/qtnfmac/core.h
Normal file
173
drivers/net/wireless/quantenna/qtnfmac/core.h
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_FMAC_CORE_H_
|
||||
#define _QTN_FMAC_CORE_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/lib80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "qlink.h"
|
||||
#include "trans.h"
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
|
||||
|
||||
#define QTNF_MAX_SSID_LIST_LENGTH 2
|
||||
#define QTNF_MAX_VSIE_LEN 255
|
||||
#define QTNF_MAX_ALPHA_LEN 2
|
||||
#define QTNF_MAX_INTF 8
|
||||
#define QTNF_MAX_EVENT_QUEUE_LEN 255
|
||||
#define QTNF_DEFAULT_BG_SCAN_PERIOD 300
|
||||
#define QTNF_MAX_BG_SCAN_PERIOD 0xffff
|
||||
|
||||
#define QTNF_DEF_BSS_PRIORITY 0
|
||||
#define QTNF_DEF_WDOG_TIMEOUT 5
|
||||
#define QTNF_TX_TIMEOUT_TRSHLD 100
|
||||
|
||||
#define QTNF_STATE_AP_CONFIG BIT(2)
|
||||
#define QTNF_STATE_AP_START BIT(1)
|
||||
|
||||
extern const struct net_device_ops qtnf_netdev_ops;
|
||||
struct qtnf_bus;
|
||||
struct qtnf_vif;
|
||||
|
||||
struct qtnf_bss_config {
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 bssid[ETH_ALEN];
|
||||
size_t ssid_len;
|
||||
u8 dtim;
|
||||
u16 bcn_period;
|
||||
u16 auth_type;
|
||||
bool privacy;
|
||||
enum nl80211_mfp mfp;
|
||||
struct cfg80211_chan_def chandef;
|
||||
struct cfg80211_crypto_settings crypto;
|
||||
u16 bg_scan_period;
|
||||
u32 connect_flags;
|
||||
};
|
||||
|
||||
struct qtnf_sta_node {
|
||||
struct list_head list;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct qtnf_sta_list {
|
||||
struct list_head head;
|
||||
atomic_t size;
|
||||
};
|
||||
|
||||
enum qtnf_sta_state {
|
||||
QTNF_STA_DISCONNECTED,
|
||||
QTNF_STA_CONNECTING,
|
||||
QTNF_STA_CONNECTED
|
||||
};
|
||||
|
||||
struct qtnf_vif {
|
||||
struct wireless_dev wdev;
|
||||
u8 vifid;
|
||||
u8 bss_priority;
|
||||
u8 bss_status;
|
||||
enum qtnf_sta_state sta_state;
|
||||
u16 mgmt_frames_bitmask;
|
||||
struct net_device *netdev;
|
||||
struct qtnf_wmac *mac;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
struct work_struct reset_work;
|
||||
struct qtnf_bss_config bss_cfg;
|
||||
struct qtnf_sta_list sta_list;
|
||||
unsigned long cons_tx_timeout_cnt;
|
||||
};
|
||||
|
||||
struct qtnf_mac_info {
|
||||
u8 bands_cap;
|
||||
u8 phymode_cap;
|
||||
u8 dev_mac[ETH_ALEN];
|
||||
u8 num_tx_chain;
|
||||
u8 num_rx_chain;
|
||||
u16 max_ap_assoc_sta;
|
||||
u32 frag_thr;
|
||||
u32 rts_thr;
|
||||
u8 lretry_limit;
|
||||
u8 sretry_limit;
|
||||
u8 coverage_class;
|
||||
u8 radar_detect_widths;
|
||||
struct ieee80211_ht_cap ht_cap;
|
||||
struct ieee80211_vht_cap vht_cap;
|
||||
struct ieee80211_iface_limit *limits;
|
||||
size_t n_limits;
|
||||
};
|
||||
|
||||
struct qtnf_wmac {
|
||||
u8 macid;
|
||||
u8 wiphy_registered;
|
||||
u8 macaddr[ETH_ALEN];
|
||||
struct qtnf_bus *bus;
|
||||
struct qtnf_mac_info macinfo;
|
||||
struct qtnf_vif iflist[QTNF_MAX_INTF];
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
};
|
||||
|
||||
struct qtnf_hw_info {
|
||||
u8 num_mac;
|
||||
u8 mac_bitmap;
|
||||
u8 alpha2_code[QTNF_MAX_ALPHA_LEN];
|
||||
u32 fw_ver;
|
||||
u16 ql_proto_ver;
|
||||
u8 total_tx_chain;
|
||||
u8 total_rx_chain;
|
||||
u32 hw_capab;
|
||||
};
|
||||
|
||||
struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac);
|
||||
struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac);
|
||||
struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus);
|
||||
int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv,
|
||||
const char *name, unsigned char name_assign_type,
|
||||
enum nl80211_iftype iftype);
|
||||
void qtnf_main_work_queue(struct work_struct *work);
|
||||
int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed);
|
||||
int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac);
|
||||
|
||||
struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid);
|
||||
struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb);
|
||||
struct net_device *qtnf_classify_skb_no_mbss(struct qtnf_bus *bus,
|
||||
struct sk_buff *skb);
|
||||
|
||||
void qtnf_virtual_intf_cleanup(struct net_device *ndev);
|
||||
|
||||
void qtnf_netdev_updown(struct net_device *ndev, bool up);
|
||||
|
||||
static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev)
|
||||
{
|
||||
return *((void **)netdev_priv(dev));
|
||||
}
|
||||
|
||||
#endif /* _QTN_FMAC_CORE_H_ */
|
46
drivers/net/wireless/quantenna/qtnfmac/debug.c
Normal file
46
drivers/net/wireless/quantenna/qtnfmac/debug.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "qtnfmac dbg: %s: " fmt, __func__
|
||||
|
||||
void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name)
|
||||
{
|
||||
bus->dbg_dir = debugfs_create_dir(name, NULL);
|
||||
|
||||
if (IS_ERR_OR_NULL(bus->dbg_dir)) {
|
||||
pr_warn("failed to create debugfs root dir\n");
|
||||
bus->dbg_dir = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void qtnf_debugfs_remove(struct qtnf_bus *bus)
|
||||
{
|
||||
debugfs_remove_recursive(bus->dbg_dir);
|
||||
bus->dbg_dir = NULL;
|
||||
}
|
||||
|
||||
void qtnf_debugfs_add_entry(struct qtnf_bus *bus, const char *name,
|
||||
int (*fn)(struct seq_file *seq, void *data))
|
||||
{
|
||||
struct dentry *entry;
|
||||
|
||||
entry = debugfs_create_devm_seqfile(bus->dev, name, bus->dbg_dir, fn);
|
||||
if (IS_ERR_OR_NULL(entry))
|
||||
pr_warn("failed to add entry (%s)\n", name);
|
||||
}
|
50
drivers/net/wireless/quantenna/qtnfmac/debug.h
Normal file
50
drivers/net/wireless/quantenna/qtnfmac/debug.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_FMAC_DEBUG_H_
|
||||
#define _QTN_FMAC_DEBUG_H_
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "bus.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name);
|
||||
void qtnf_debugfs_remove(struct qtnf_bus *bus);
|
||||
void qtnf_debugfs_add_entry(struct qtnf_bus *bus, const char *name,
|
||||
int (*fn)(struct seq_file *seq, void *data));
|
||||
|
||||
#else
|
||||
|
||||
static inline void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void qtnf_debugfs_remove(struct qtnf_bus *bus)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
qtnf_debugfs_add_entry(struct qtnf_bus *bus, const char *name,
|
||||
int (*fn)(struct seq_file *seq, void *data))
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
#endif /* _QTN_FMAC_DEBUG_H_ */
|
452
drivers/net/wireless/quantenna/qtnfmac/event.c
Normal file
452
drivers/net/wireless/quantenna/qtnfmac/event.c
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "cfg80211.h"
|
||||
#include "core.h"
|
||||
#include "qlink.h"
|
||||
#include "bus.h"
|
||||
#include "trans.h"
|
||||
#include "util.h"
|
||||
#include "event.h"
|
||||
|
||||
static int
|
||||
qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif,
|
||||
const struct qlink_event_sta_assoc *sta_assoc,
|
||||
u16 len)
|
||||
{
|
||||
const u8 *sta_addr;
|
||||
u16 frame_control;
|
||||
struct station_info sinfo = { 0 };
|
||||
size_t payload_len;
|
||||
u16 tlv_type;
|
||||
u16 tlv_value_len;
|
||||
size_t tlv_full_len;
|
||||
const struct qlink_tlv_hdr *tlv;
|
||||
|
||||
if (unlikely(len < sizeof(*sta_assoc))) {
|
||||
pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
|
||||
mac->macid, vif->vifid, len, sizeof(*sta_assoc));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
|
||||
pr_err("VIF%u.%u: STA_ASSOC event when not in AP mode\n",
|
||||
mac->macid, vif->vifid);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (!(vif->bss_status & QTNF_STATE_AP_START)) {
|
||||
pr_err("VIF%u.%u: STA_ASSOC event when AP is not started\n",
|
||||
mac->macid, vif->vifid);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
sta_addr = sta_assoc->sta_addr;
|
||||
frame_control = le16_to_cpu(sta_assoc->frame_control);
|
||||
|
||||
pr_debug("VIF%u.%u: MAC:%pM FC:%x\n", mac->macid, vif->vifid, sta_addr,
|
||||
frame_control);
|
||||
|
||||
qtnf_sta_list_add(&vif->sta_list, sta_addr);
|
||||
|
||||
sinfo.assoc_req_ies = NULL;
|
||||
sinfo.assoc_req_ies_len = 0;
|
||||
|
||||
payload_len = len - sizeof(*sta_assoc);
|
||||
tlv = (struct qlink_tlv_hdr *)sta_assoc->ies;
|
||||
|
||||
while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
|
||||
tlv_type = le16_to_cpu(tlv->type);
|
||||
tlv_value_len = le16_to_cpu(tlv->len);
|
||||
tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
|
||||
|
||||
if (tlv_full_len > payload_len) {
|
||||
pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n",
|
||||
mac->macid, vif->vifid, tlv_type,
|
||||
tlv_value_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tlv_type == QTN_TLV_ID_IE_SET) {
|
||||
sinfo.assoc_req_ies = tlv->val;
|
||||
sinfo.assoc_req_ies_len = tlv_value_len;
|
||||
}
|
||||
|
||||
payload_len -= tlv_full_len;
|
||||
tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
|
||||
}
|
||||
|
||||
if (payload_len) {
|
||||
pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n",
|
||||
mac->macid, vif->vifid, payload_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, &sinfo,
|
||||
GFP_KERNEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_event_handle_sta_deauth(struct qtnf_wmac *mac, struct qtnf_vif *vif,
|
||||
const struct qlink_event_sta_deauth *sta_deauth,
|
||||
u16 len)
|
||||
{
|
||||
const u8 *sta_addr;
|
||||
u16 reason;
|
||||
|
||||
if (unlikely(len < sizeof(*sta_deauth))) {
|
||||
pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
|
||||
mac->macid, vif->vifid, len,
|
||||
sizeof(struct qlink_event_sta_deauth));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
|
||||
pr_err("VIF%u.%u: STA_DEAUTH event when not in AP mode\n",
|
||||
mac->macid, vif->vifid);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (!(vif->bss_status & QTNF_STATE_AP_START)) {
|
||||
pr_err("VIF%u.%u: STA_DEAUTH event when AP is not started\n",
|
||||
mac->macid, vif->vifid);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
sta_addr = sta_deauth->sta_addr;
|
||||
reason = le16_to_cpu(sta_deauth->reason);
|
||||
|
||||
pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid,
|
||||
sta_addr, reason);
|
||||
|
||||
if (qtnf_sta_list_del(&vif->sta_list, sta_addr))
|
||||
cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr,
|
||||
GFP_KERNEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_event_handle_bss_join(struct qtnf_vif *vif,
|
||||
const struct qlink_event_bss_join *join_info,
|
||||
u16 len)
|
||||
{
|
||||
if (unlikely(len < sizeof(*join_info))) {
|
||||
pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
|
||||
vif->mac->macid, vif->vifid, len,
|
||||
sizeof(struct qlink_event_bss_join));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
|
||||
pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n",
|
||||
vif->mac->macid, vif->vifid);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (vif->sta_state != QTNF_STA_CONNECTING) {
|
||||
pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n",
|
||||
vif->mac->macid, vif->vifid);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid,
|
||||
join_info->bssid);
|
||||
|
||||
cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL,
|
||||
0, le16_to_cpu(join_info->status), GFP_KERNEL);
|
||||
|
||||
if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) {
|
||||
vif->sta_state = QTNF_STA_CONNECTED;
|
||||
netif_carrier_on(vif->netdev);
|
||||
} else {
|
||||
vif->sta_state = QTNF_STA_DISCONNECTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_event_handle_bss_leave(struct qtnf_vif *vif,
|
||||
const struct qlink_event_bss_leave *leave_info,
|
||||
u16 len)
|
||||
{
|
||||
if (unlikely(len < sizeof(*leave_info))) {
|
||||
pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
|
||||
vif->mac->macid, vif->vifid, len,
|
||||
sizeof(struct qlink_event_bss_leave));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
|
||||
pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n",
|
||||
vif->mac->macid, vif->vifid);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (vif->sta_state != QTNF_STA_CONNECTED) {
|
||||
pr_err("VIF%u.%u: BSS_LEAVE event when STA is not connected\n",
|
||||
vif->mac->macid, vif->vifid);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);
|
||||
|
||||
cfg80211_disconnected(vif->netdev, leave_info->reason, NULL, 0, 0,
|
||||
GFP_KERNEL);
|
||||
|
||||
vif->sta_state = QTNF_STA_DISCONNECTED;
|
||||
netif_carrier_off(vif->netdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_event_handle_mgmt_received(struct qtnf_vif *vif,
|
||||
const struct qlink_event_rxmgmt *rxmgmt,
|
||||
u16 len)
|
||||
{
|
||||
const size_t min_len = sizeof(*rxmgmt) +
|
||||
sizeof(struct ieee80211_hdr_3addr);
|
||||
const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data;
|
||||
const u16 frame_len = len - sizeof(*rxmgmt);
|
||||
enum nl80211_rxmgmt_flags flags = 0;
|
||||
|
||||
if (unlikely(len < min_len)) {
|
||||
pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
|
||||
vif->mac->macid, vif->vifid, len, min_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED)
|
||||
flags |= NL80211_RXMGMT_FLAG_ANSWERED;
|
||||
|
||||
pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len,
|
||||
le16_to_cpu(frame->frame_control), frame->addr2);
|
||||
|
||||
cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq),
|
||||
le32_to_cpu(rxmgmt->sig_dbm), rxmgmt->frame_data,
|
||||
frame_len, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_event_handle_scan_results(struct qtnf_vif *vif,
|
||||
const struct qlink_event_scan_result *sr,
|
||||
u16 len)
|
||||
{
|
||||
struct cfg80211_bss *bss;
|
||||
struct ieee80211_channel *channel;
|
||||
struct wiphy *wiphy = priv_to_wiphy(vif->mac);
|
||||
enum cfg80211_bss_frame_type frame_type;
|
||||
size_t payload_len;
|
||||
u16 tlv_type;
|
||||
u16 tlv_value_len;
|
||||
size_t tlv_full_len;
|
||||
const struct qlink_tlv_hdr *tlv;
|
||||
|
||||
const u8 *ies = NULL;
|
||||
size_t ies_len = 0;
|
||||
|
||||
if (len < sizeof(*sr)) {
|
||||
pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid,
|
||||
vif->vifid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq));
|
||||
if (!channel) {
|
||||
pr_err("VIF%u.%u: channel at %u MHz not found\n",
|
||||
vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (sr->frame_type) {
|
||||
case QLINK_BSS_FTYPE_BEACON:
|
||||
frame_type = CFG80211_BSS_FTYPE_BEACON;
|
||||
break;
|
||||
case QLINK_BSS_FTYPE_PRESP:
|
||||
frame_type = CFG80211_BSS_FTYPE_PRESP;
|
||||
break;
|
||||
default:
|
||||
frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
payload_len = len - sizeof(*sr);
|
||||
tlv = (struct qlink_tlv_hdr *)sr->payload;
|
||||
|
||||
while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
|
||||
tlv_type = le16_to_cpu(tlv->type);
|
||||
tlv_value_len = le16_to_cpu(tlv->len);
|
||||
tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
|
||||
|
||||
if (tlv_full_len > payload_len) {
|
||||
pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n",
|
||||
vif->mac->macid, vif->vifid, tlv_type,
|
||||
tlv_value_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tlv_type == QTN_TLV_ID_IE_SET) {
|
||||
ies = tlv->val;
|
||||
ies_len = tlv_value_len;
|
||||
}
|
||||
|
||||
payload_len -= tlv_full_len;
|
||||
tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
|
||||
}
|
||||
|
||||
if (payload_len) {
|
||||
pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n",
|
||||
vif->mac->macid, vif->vifid, payload_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bss = cfg80211_inform_bss(wiphy, channel, frame_type,
|
||||
sr->bssid, get_unaligned_le64(&sr->tsf),
|
||||
le16_to_cpu(sr->capab),
|
||||
le16_to_cpu(sr->bintval), ies, ies_len,
|
||||
sr->signal, GFP_KERNEL);
|
||||
if (!bss)
|
||||
return -ENOMEM;
|
||||
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qtnf_event_handle_scan_complete(struct qtnf_wmac *mac,
|
||||
const struct qlink_event_scan_complete *status,
|
||||
u16 len)
|
||||
{
|
||||
if (len < sizeof(*status)) {
|
||||
pr_err("MAC%u: payload is too short\n", mac->macid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qtnf_event_parse(struct qtnf_wmac *mac,
|
||||
const struct sk_buff *event_skb)
|
||||
{
|
||||
const struct qlink_event *event;
|
||||
struct qtnf_vif *vif = NULL;
|
||||
int ret = -1;
|
||||
u16 event_id;
|
||||
u16 event_len;
|
||||
|
||||
event = (const struct qlink_event *)event_skb->data;
|
||||
event_id = le16_to_cpu(event->event_id);
|
||||
event_len = le16_to_cpu(event->mhdr.len);
|
||||
|
||||
if (likely(event->vifid < QTNF_MAX_INTF)) {
|
||||
vif = &mac->iflist[event->vifid];
|
||||
} else {
|
||||
pr_err("invalid vif(%u)\n", event->vifid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (event_id) {
|
||||
case QLINK_EVENT_STA_ASSOCIATED:
|
||||
ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event,
|
||||
event_len);
|
||||
break;
|
||||
case QLINK_EVENT_STA_DEAUTH:
|
||||
ret = qtnf_event_handle_sta_deauth(mac, vif,
|
||||
(const void *)event,
|
||||
event_len);
|
||||
break;
|
||||
case QLINK_EVENT_MGMT_RECEIVED:
|
||||
ret = qtnf_event_handle_mgmt_received(vif, (const void *)event,
|
||||
event_len);
|
||||
break;
|
||||
case QLINK_EVENT_SCAN_RESULTS:
|
||||
ret = qtnf_event_handle_scan_results(vif, (const void *)event,
|
||||
event_len);
|
||||
break;
|
||||
case QLINK_EVENT_SCAN_COMPLETE:
|
||||
ret = qtnf_event_handle_scan_complete(mac, (const void *)event,
|
||||
event_len);
|
||||
break;
|
||||
case QLINK_EVENT_BSS_JOIN:
|
||||
ret = qtnf_event_handle_bss_join(vif, (const void *)event,
|
||||
event_len);
|
||||
break;
|
||||
case QLINK_EVENT_BSS_LEAVE:
|
||||
ret = qtnf_event_handle_bss_leave(vif, (const void *)event,
|
||||
event_len);
|
||||
break;
|
||||
default:
|
||||
pr_warn("unknown event type: %x\n", event_id);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qtnf_event_process_skb(struct qtnf_bus *bus,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
const struct qlink_event *event;
|
||||
struct qtnf_wmac *mac;
|
||||
int res;
|
||||
|
||||
if (unlikely(!skb || skb->len < sizeof(*event))) {
|
||||
pr_err("invalid event buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
event = (struct qlink_event *)skb->data;
|
||||
|
||||
mac = qtnf_core_get_mac(bus, event->macid);
|
||||
|
||||
pr_debug("new event id:%x len:%u mac:%u vif:%u\n",
|
||||
le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len),
|
||||
event->macid, event->vifid);
|
||||
|
||||
if (unlikely(!mac))
|
||||
return -ENXIO;
|
||||
|
||||
qtnf_bus_lock(bus);
|
||||
res = qtnf_event_parse(mac, skb);
|
||||
qtnf_bus_unlock(bus);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void qtnf_event_work_handler(struct work_struct *work)
|
||||
{
|
||||
struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work);
|
||||
struct sk_buff_head *event_queue = &bus->trans.event_queue;
|
||||
struct sk_buff *current_event_skb = skb_dequeue(event_queue);
|
||||
|
||||
while (current_event_skb) {
|
||||
qtnf_event_process_skb(bus, current_event_skb);
|
||||
dev_kfree_skb_any(current_event_skb);
|
||||
current_event_skb = skb_dequeue(event_queue);
|
||||
}
|
||||
}
|
27
drivers/net/wireless/quantenna/qtnfmac/event.h
Normal file
27
drivers/net/wireless/quantenna/qtnfmac/event.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_FMAC_EVENT_H_
|
||||
#define _QTN_FMAC_EVENT_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "qlink.h"
|
||||
|
||||
void qtnf_event_work_handler(struct work_struct *work);
|
||||
|
||||
#endif /* _QTN_FMAC_EVENT_H_ */
|
1378
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c
Normal file
1378
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c
Normal file
File diff suppressed because it is too large
Load Diff
89
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h
Normal file
89
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_FMAC_PCIE_H_
|
||||
#define _QTN_FMAC_PCIE_H_
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "pcie_regs_pearl.h"
|
||||
#include "pcie_ipc.h"
|
||||
#include "shm_ipc.h"
|
||||
|
||||
struct bus;
|
||||
|
||||
struct qtnf_pcie_bus_priv {
|
||||
struct pci_dev *pdev;
|
||||
|
||||
/* lock for irq configuration changes */
|
||||
spinlock_t irq_lock;
|
||||
|
||||
/* lock for tx operations */
|
||||
spinlock_t tx_lock;
|
||||
u8 msi_enabled;
|
||||
int mps;
|
||||
|
||||
struct workqueue_struct *workqueue;
|
||||
struct tasklet_struct reclaim_tq;
|
||||
|
||||
void __iomem *sysctl_bar;
|
||||
void __iomem *epmem_bar;
|
||||
void __iomem *dmareg_bar;
|
||||
|
||||
struct qtnf_shm_ipc shm_ipc_ep_in;
|
||||
struct qtnf_shm_ipc shm_ipc_ep_out;
|
||||
|
||||
struct qtnf_pcie_bda __iomem *bda;
|
||||
void __iomem *pcie_reg_base;
|
||||
|
||||
u16 tx_bd_num;
|
||||
u16 rx_bd_num;
|
||||
|
||||
struct sk_buff **tx_skb;
|
||||
struct sk_buff **rx_skb;
|
||||
|
||||
struct qtnf_tx_bd *tx_bd_vbase;
|
||||
dma_addr_t tx_bd_pbase;
|
||||
|
||||
struct qtnf_rx_bd *rx_bd_vbase;
|
||||
dma_addr_t rx_bd_pbase;
|
||||
|
||||
dma_addr_t bd_table_paddr;
|
||||
void *bd_table_vaddr;
|
||||
u32 bd_table_len;
|
||||
|
||||
u32 hw_txproc_wr_ptr;
|
||||
|
||||
u16 tx_bd_reclaim_start;
|
||||
u16 tx_bd_index;
|
||||
u32 tx_queue_len;
|
||||
|
||||
u16 rx_bd_index;
|
||||
|
||||
u32 pcie_irq_mask;
|
||||
|
||||
/* diagnostics stats */
|
||||
u32 pcie_irq_count;
|
||||
u32 pcie_irq_rx_count;
|
||||
u32 pcie_irq_tx_count;
|
||||
u32 tx_full_count;
|
||||
u32 tx_done_count;
|
||||
u32 tx_reclaim_done;
|
||||
u32 tx_reclaim_req;
|
||||
};
|
||||
|
||||
#endif /* _QTN_FMAC_PCIE_H_ */
|
158
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h
Normal file
158
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_FMAC_PCIE_IPC_H_
|
||||
#define _QTN_FMAC_PCIE_IPC_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "shm_ipc_defs.h"
|
||||
|
||||
/* bitmap for EP status and flags: updated by EP, read by RC */
|
||||
#define QTN_EP_HAS_UBOOT BIT(0)
|
||||
#define QTN_EP_HAS_FIRMWARE BIT(1)
|
||||
#define QTN_EP_REQ_UBOOT BIT(2)
|
||||
#define QTN_EP_REQ_FIRMWARE BIT(3)
|
||||
#define QTN_EP_ERROR_UBOOT BIT(4)
|
||||
#define QTN_EP_ERROR_FIRMWARE BIT(5)
|
||||
|
||||
#define QTN_EP_FW_LOADRDY BIT(8)
|
||||
#define QTN_EP_FW_SYNC BIT(9)
|
||||
#define QTN_EP_FW_RETRY BIT(10)
|
||||
#define QTN_EP_FW_QLINK_DONE BIT(15)
|
||||
#define QTN_EP_FW_DONE BIT(16)
|
||||
|
||||
/* bitmap for RC status and flags: updated by RC, read by EP */
|
||||
#define QTN_RC_PCIE_LINK BIT(0)
|
||||
#define QTN_RC_NET_LINK BIT(1)
|
||||
#define QTN_RC_FW_FLASHBOOT BIT(5)
|
||||
#define QTN_RC_FW_QLINK BIT(7)
|
||||
#define QTN_RC_FW_LOADRDY BIT(8)
|
||||
#define QTN_RC_FW_SYNC BIT(9)
|
||||
|
||||
/* state transition timeouts */
|
||||
#define QTN_FW_DL_TIMEOUT_MS 3000
|
||||
#define QTN_FW_QLINK_TIMEOUT_MS 30000
|
||||
|
||||
#define PCIE_HDP_INT_RX_BITS (0 \
|
||||
| PCIE_HDP_INT_EP_TXDMA \
|
||||
| PCIE_HDP_INT_EP_TXEMPTY \
|
||||
)
|
||||
|
||||
#define PCIE_HDP_INT_TX_BITS (0 \
|
||||
| PCIE_HDP_INT_EP_RXDMA \
|
||||
)
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
#define QTN_HOST_HI32(a) ((u32)(((u64)a) >> 32))
|
||||
#define QTN_HOST_LO32(a) ((u32)(((u64)a) & 0xffffffffUL))
|
||||
#define QTN_HOST_ADDR(h, l) ((((u64)h) << 32) | ((u64)l))
|
||||
#elif BITS_PER_LONG == 32
|
||||
#define QTN_HOST_HI32(a) 0
|
||||
#define QTN_HOST_LO32(a) ((u32)(((u32)a) & 0xffffffffUL))
|
||||
#define QTN_HOST_ADDR(h, l) ((u32)l)
|
||||
#else
|
||||
#error Unexpected BITS_PER_LONG value
|
||||
#endif
|
||||
|
||||
#define QTN_SYSCTL_BAR 0
|
||||
#define QTN_SHMEM_BAR 2
|
||||
#define QTN_DMA_BAR 3
|
||||
|
||||
#define QTN_PCIE_BDA_VERSION 0x1002
|
||||
|
||||
#define PCIE_BDA_NAMELEN 32
|
||||
#define PCIE_HHBM_MAX_SIZE 512
|
||||
|
||||
#define SKB_BUF_SIZE 2048
|
||||
|
||||
#define QTN_PCIE_BOARDFLG "PCIEQTN"
|
||||
#define QTN_PCIE_FW_DLMASK 0xF
|
||||
#define QTN_PCIE_FW_BUFSZ 2048
|
||||
|
||||
#define QTN_ENET_ADDR_LENGTH 6
|
||||
|
||||
#define QTN_TXDONE_MASK ((u32)0x80000000)
|
||||
#define QTN_GET_LEN(x) ((x) & 0xFFFF)
|
||||
|
||||
#define QTN_PCIE_TX_DESC_LEN_MASK 0xFFFF
|
||||
#define QTN_PCIE_TX_DESC_LEN_SHIFT 0
|
||||
#define QTN_PCIE_TX_DESC_PORT_MASK 0xF
|
||||
#define QTN_PCIE_TX_DESC_PORT_SHIFT 16
|
||||
#define QTN_PCIE_TX_DESC_TQE_BIT BIT(24)
|
||||
|
||||
#define QTN_EP_LHOST_TQE_PORT 4
|
||||
|
||||
enum qtnf_pcie_bda_ipc_flags {
|
||||
QTN_PCIE_IPC_FLAG_HBM_MAGIC = BIT(0),
|
||||
QTN_PCIE_IPC_FLAG_SHM_PIO = BIT(1),
|
||||
};
|
||||
|
||||
struct qtnf_pcie_bda {
|
||||
__le16 bda_len;
|
||||
__le16 bda_version;
|
||||
__le32 bda_pci_endian;
|
||||
__le32 bda_ep_state;
|
||||
__le32 bda_rc_state;
|
||||
__le32 bda_dma_mask;
|
||||
__le32 bda_msi_addr;
|
||||
__le32 bda_flashsz;
|
||||
u8 bda_boardname[PCIE_BDA_NAMELEN];
|
||||
__le32 bda_rc_msi_enabled;
|
||||
__le32 bda_hhbm_list[PCIE_HHBM_MAX_SIZE];
|
||||
__le32 bda_dsbw_start_index;
|
||||
__le32 bda_dsbw_end_index;
|
||||
__le32 bda_dsbw_total_bytes;
|
||||
__le32 bda_rc_tx_bd_base;
|
||||
__le32 bda_rc_tx_bd_num;
|
||||
u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH];
|
||||
struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */
|
||||
struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */
|
||||
} __packed;
|
||||
|
||||
struct qtnf_tx_bd {
|
||||
__le32 addr;
|
||||
__le32 addr_h;
|
||||
__le32 info;
|
||||
__le32 info_h;
|
||||
} __packed;
|
||||
|
||||
struct qtnf_rx_bd {
|
||||
__le32 addr;
|
||||
__le32 addr_h;
|
||||
__le32 info;
|
||||
__le32 info_h;
|
||||
__le32 next_ptr;
|
||||
__le32 next_ptr_h;
|
||||
} __packed;
|
||||
|
||||
enum qtnf_fw_loadtype {
|
||||
QTN_FW_DBEGIN,
|
||||
QTN_FW_DSUB,
|
||||
QTN_FW_DEND,
|
||||
QTN_FW_CTRL
|
||||
};
|
||||
|
||||
struct qtnf_pcie_fw_hdr {
|
||||
u8 boardflg[8];
|
||||
__le32 fwsize;
|
||||
__le32 seqnum;
|
||||
__le32 type;
|
||||
__le32 pktlen;
|
||||
__le32 crc;
|
||||
} __packed;
|
||||
|
||||
#endif /* _QTN_FMAC_PCIE_IPC_H_ */
|
353
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h
Normal file
353
drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PEARL_PCIE_H
|
||||
#define __PEARL_PCIE_H
|
||||
|
||||
#define PCIE_GEN2_BASE (0xe9000000)
|
||||
#define PCIE_GEN3_BASE (0xe7000000)
|
||||
|
||||
#define PEARL_CUR_PCIE_BASE (PCIE_GEN2_BASE)
|
||||
#define PCIE_HDP_OFFSET (0x2000)
|
||||
|
||||
#define PCIE_HDP_CTRL(base) ((base) + 0x2c00)
|
||||
#define PCIE_HDP_AXI_CTRL(base) ((base) + 0x2c04)
|
||||
#define PCIE_HDP_HOST_WR_DESC0(base) ((base) + 0x2c10)
|
||||
#define PCIE_HDP_HOST_WR_DESC0_H(base) ((base) + 0x2c14)
|
||||
#define PCIE_HDP_HOST_WR_DESC1(base) ((base) + 0x2c18)
|
||||
#define PCIE_HDP_HOST_WR_DESC1_H(base) ((base) + 0x2c1c)
|
||||
#define PCIE_HDP_HOST_WR_DESC2(base) ((base) + 0x2c20)
|
||||
#define PCIE_HDP_HOST_WR_DESC2_H(base) ((base) + 0x2c24)
|
||||
#define PCIE_HDP_HOST_WR_DESC3(base) ((base) + 0x2c28)
|
||||
#define PCIE_HDP_HOST_WR_DESC4_H(base) ((base) + 0x2c2c)
|
||||
#define PCIE_HDP_RX_INT_CTRL(base) ((base) + 0x2c30)
|
||||
#define PCIE_HDP_TX_INT_CTRL(base) ((base) + 0x2c34)
|
||||
#define PCIE_HDP_INT_STATUS(base) ((base) + 0x2c38)
|
||||
#define PCIE_HDP_INT_EN(base) ((base) + 0x2c3c)
|
||||
#define PCIE_HDP_RX_DESC0_PTR(base) ((base) + 0x2c40)
|
||||
#define PCIE_HDP_RX_DESC0_NOE(base) ((base) + 0x2c44)
|
||||
#define PCIE_HDP_RX_DESC1_PTR(base) ((base) + 0x2c48)
|
||||
#define PCIE_HDP_RX_DESC1_NOE(base) ((base) + 0x2c4c)
|
||||
#define PCIE_HDP_RX_DESC2_PTR(base) ((base) + 0x2c50)
|
||||
#define PCIE_HDP_RX_DESC2_NOE(base) ((base) + 0x2c54)
|
||||
#define PCIE_HDP_RX_DESC3_PTR(base) ((base) + 0x2c58)
|
||||
#define PCIE_HDP_RX_DESC3_NOE(base) ((base) + 0x2c5c)
|
||||
|
||||
#define PCIE_HDP_TX0_BASE_ADDR(base) ((base) + 0x2c60)
|
||||
#define PCIE_HDP_TX1_BASE_ADDR(base) ((base) + 0x2c64)
|
||||
#define PCIE_HDP_TX0_Q_CTRL(base) ((base) + 0x2c70)
|
||||
#define PCIE_HDP_TX1_Q_CTRL(base) ((base) + 0x2c74)
|
||||
#define PCIE_HDP_CFG0(base) ((base) + 0x2c80)
|
||||
#define PCIE_HDP_CFG1(base) ((base) + 0x2c84)
|
||||
#define PCIE_HDP_CFG2(base) ((base) + 0x2c88)
|
||||
#define PCIE_HDP_CFG3(base) ((base) + 0x2c8c)
|
||||
#define PCIE_HDP_CFG4(base) ((base) + 0x2c90)
|
||||
#define PCIE_HDP_CFG5(base) ((base) + 0x2c94)
|
||||
#define PCIE_HDP_CFG6(base) ((base) + 0x2c98)
|
||||
#define PCIE_HDP_CFG7(base) ((base) + 0x2c9c)
|
||||
#define PCIE_HDP_CFG8(base) ((base) + 0x2ca0)
|
||||
#define PCIE_HDP_CFG9(base) ((base) + 0x2ca4)
|
||||
#define PCIE_HDP_CFG10(base) ((base) + 0x2ca8)
|
||||
#define PCIE_HDP_CFG11(base) ((base) + 0x2cac)
|
||||
#define PCIE_INT(base) ((base) + 0x2cb0)
|
||||
#define PCIE_INT_MASK(base) ((base) + 0x2cb4)
|
||||
#define PCIE_MSI_MASK(base) ((base) + 0x2cb8)
|
||||
#define PCIE_MSI_PNDG(base) ((base) + 0x2cbc)
|
||||
#define PCIE_PRI_CFG(base) ((base) + 0x2cc0)
|
||||
#define PCIE_PHY_CR(base) ((base) + 0x2cc4)
|
||||
#define PCIE_HDP_CTAG_CTRL(base) ((base) + 0x2cf4)
|
||||
#define PCIE_HDP_HHBM_BUF_PTR(base) ((base) + 0x2d00)
|
||||
#define PCIE_HDP_HHBM_BUF_PTR_H(base) ((base) + 0x2d04)
|
||||
#define PCIE_HDP_HHBM_BUF_FIFO_NOE(base) ((base) + 0x2d04)
|
||||
#define PCIE_HDP_RX0DMA_CNT(base) ((base) + 0x2d10)
|
||||
#define PCIE_HDP_RX1DMA_CNT(base) ((base) + 0x2d14)
|
||||
#define PCIE_HDP_RX2DMA_CNT(base) ((base) + 0x2d18)
|
||||
#define PCIE_HDP_RX3DMA_CNT(base) ((base) + 0x2d1c)
|
||||
#define PCIE_HDP_TX0DMA_CNT(base) ((base) + 0x2d20)
|
||||
#define PCIE_HDP_TX1DMA_CNT(base) ((base) + 0x2d24)
|
||||
#define PCIE_HDP_RXDMA_CTRL(base) ((base) + 0x2d28)
|
||||
#define PCIE_HDP_TX_HOST_Q_SZ_CTRL(base) ((base) + 0x2d2c)
|
||||
#define PCIE_HDP_TX_HOST_Q_BASE_L(base) ((base) + 0x2d30)
|
||||
#define PCIE_HDP_TX_HOST_Q_BASE_H(base) ((base) + 0x2d34)
|
||||
#define PCIE_HDP_TX_HOST_Q_WR_PTR(base) ((base) + 0x2d38)
|
||||
#define PCIE_HDP_TX_HOST_Q_RD_PTR(base) ((base) + 0x2d3c)
|
||||
#define PCIE_HDP_TX_HOST_Q_STS(base) ((base) + 0x2d40)
|
||||
|
||||
/* Host HBM pool registers */
|
||||
#define PCIE_HHBM_CSR_REG(base) ((base) + 0x2e00)
|
||||
#define PCIE_HHBM_Q_BASE_REG(base) ((base) + 0x2e04)
|
||||
#define PCIE_HHBM_Q_LIMIT_REG(base) ((base) + 0x2e08)
|
||||
#define PCIE_HHBM_Q_WR_REG(base) ((base) + 0x2e0c)
|
||||
#define PCIE_HHBM_Q_RD_REG(base) ((base) + 0x2e10)
|
||||
#define PCIE_HHBM_POOL_DATA_0_H(base) ((base) + 0x2e90)
|
||||
#define PCIE_HHBM_CONFIG(base) ((base) + 0x2f9c)
|
||||
#define PCIE_HHBM_POOL_REQ_0(base) ((base) + 0x2f10)
|
||||
#define PCIE_HHBM_POOL_DATA_0(base) ((base) + 0x2f40)
|
||||
#define PCIE_HHBM_WATERMARK_MASKED_INT(base) ((base) + 0x2f68)
|
||||
#define PCIE_HHBM_WATERMARK_INT(base) ((base) + 0x2f6c)
|
||||
#define PCIE_HHBM_POOL_WATERMARK(base) ((base) + 0x2f70)
|
||||
#define PCIE_HHBM_POOL_OVERFLOW_CNT(base) ((base) + 0x2f90)
|
||||
#define PCIE_HHBM_POOL_UNDERFLOW_CNT(base) ((base) + 0x2f94)
|
||||
#define HBM_INT_STATUS(base) ((base) + 0x2f9c)
|
||||
#define PCIE_HHBM_POOL_CNFIG(base) ((base) + 0x2f9c)
|
||||
|
||||
/* host HBM bit field definition */
|
||||
#define HHBM_CONFIG_SOFT_RESET (BIT(8))
|
||||
#define HHBM_WR_REQ (BIT(0))
|
||||
#define HHBM_RD_REQ (BIT(1))
|
||||
#define HHBM_DONE (BIT(31))
|
||||
|
||||
/* offsets for dual PCIE */
|
||||
#define PCIE_PORT_LINK_CTL(base) ((base) + 0x0710)
|
||||
#define PCIE_GEN2_CTL(base) ((base) + 0x080C)
|
||||
#define PCIE_GEN3_OFF(base) ((base) + 0x0890)
|
||||
#define PCIE_ATU_CTRL1(base) ((base) + 0x0904)
|
||||
#define PCIE_ATU_CTRL2(base) ((base) + 0x0908)
|
||||
#define PCIE_ATU_BASE_LOW(base) ((base) + 0x090C)
|
||||
#define PCIE_ATU_BASE_HIGH(base) ((base) + 0x0910)
|
||||
#define PCIE_ATU_BASE_LIMIT(base) ((base) + 0x0914)
|
||||
#define PCIE_ATU_TGT_LOW(base) ((base) + 0x0918)
|
||||
#define PCIE_ATU_TGT_HIGH(base) ((base) + 0x091C)
|
||||
#define PCIE_DMA_WR_ENABLE(base) ((base) + 0x097C)
|
||||
#define PCIE_DMA_WR_CHWTLOW(base) ((base) + 0x0988)
|
||||
#define PCIE_DMA_WR_CHWTHIG(base) ((base) + 0x098C)
|
||||
#define PCIE_DMA_WR_INTSTS(base) ((base) + 0x09BC)
|
||||
#define PCIE_DMA_WR_INTMASK(base) ((base) + 0x09C4)
|
||||
#define PCIE_DMA_WR_INTCLER(base) ((base) + 0x09C8)
|
||||
#define PCIE_DMA_WR_DONE_IMWR_ADDR_L(base) ((base) + 0x09D0)
|
||||
#define PCIE_DMA_WR_DONE_IMWR_ADDR_H(base) ((base) + 0x09D4)
|
||||
#define PCIE_DMA_WR_ABORT_IMWR_ADDR_L(base) ((base) + 0x09D8)
|
||||
#define PCIE_DMA_WR_ABORT_IMWR_ADDR_H(base) ((base) + 0x09DC)
|
||||
#define PCIE_DMA_WR_IMWR_DATA(base) ((base) + 0x09E0)
|
||||
#define PCIE_DMA_WR_LL_ERR_EN(base) ((base) + 0x0A00)
|
||||
#define PCIE_DMA_WR_DOORBELL(base) ((base) + 0x0980)
|
||||
#define PCIE_DMA_RD_ENABLE(base) ((base) + 0x099C)
|
||||
#define PCIE_DMA_RD_DOORBELL(base) ((base) + 0x09A0)
|
||||
#define PCIE_DMA_RD_CHWTLOW(base) ((base) + 0x09A8)
|
||||
#define PCIE_DMA_RD_CHWTHIG(base) ((base) + 0x09AC)
|
||||
#define PCIE_DMA_RD_INTSTS(base) ((base) + 0x0A10)
|
||||
#define PCIE_DMA_RD_INTMASK(base) ((base) + 0x0A18)
|
||||
#define PCIE_DMA_RD_INTCLER(base) ((base) + 0x0A1C)
|
||||
#define PCIE_DMA_RD_ERR_STS_L(base) ((base) + 0x0A24)
|
||||
#define PCIE_DMA_RD_ERR_STS_H(base) ((base) + 0x0A28)
|
||||
#define PCIE_DMA_RD_LL_ERR_EN(base) ((base) + 0x0A34)
|
||||
#define PCIE_DMA_RD_DONE_IMWR_ADDR_L(base) ((base) + 0x0A3C)
|
||||
#define PCIE_DMA_RD_DONE_IMWR_ADDR_H(base) ((base) + 0x0A40)
|
||||
#define PCIE_DMA_RD_ABORT_IMWR_ADDR_L(base) ((base) + 0x0A44)
|
||||
#define PCIE_DMA_RD_ABORT_IMWR_ADDR_H(base) ((base) + 0x0A48)
|
||||
#define PCIE_DMA_RD_IMWR_DATA(base) ((base) + 0x0A4C)
|
||||
#define PCIE_DMA_CHNL_CONTEXT(base) ((base) + 0x0A6C)
|
||||
#define PCIE_DMA_CHNL_CNTRL(base) ((base) + 0x0A70)
|
||||
#define PCIE_DMA_XFR_SIZE(base) ((base) + 0x0A78)
|
||||
#define PCIE_DMA_SAR_LOW(base) ((base) + 0x0A7C)
|
||||
#define PCIE_DMA_SAR_HIGH(base) ((base) + 0x0A80)
|
||||
#define PCIE_DMA_DAR_LOW(base) ((base) + 0x0A84)
|
||||
#define PCIE_DMA_DAR_HIGH(base) ((base) + 0x0A88)
|
||||
#define PCIE_DMA_LLPTR_LOW(base) ((base) + 0x0A8C)
|
||||
#define PCIE_DMA_LLPTR_HIGH(base) ((base) + 0x0A90)
|
||||
#define PCIE_DMA_WRLL_ERR_ENB(base) ((base) + 0x0A00)
|
||||
#define PCIE_DMA_RDLL_ERR_ENB(base) ((base) + 0x0A34)
|
||||
#define PCIE_DMABD_CHNL_CNTRL(base) ((base) + 0x8000)
|
||||
#define PCIE_DMABD_XFR_SIZE(base) ((base) + 0x8004)
|
||||
#define PCIE_DMABD_SAR_LOW(base) ((base) + 0x8008)
|
||||
#define PCIE_DMABD_SAR_HIGH(base) ((base) + 0x800c)
|
||||
#define PCIE_DMABD_DAR_LOW(base) ((base) + 0x8010)
|
||||
#define PCIE_DMABD_DAR_HIGH(base) ((base) + 0x8014)
|
||||
#define PCIE_DMABD_LLPTR_LOW(base) ((base) + 0x8018)
|
||||
#define PCIE_DMABD_LLPTR_HIGH(base) ((base) + 0x801c)
|
||||
#define PCIE_WRDMA0_CHNL_CNTRL(base) ((base) + 0x8000)
|
||||
#define PCIE_WRDMA0_XFR_SIZE(base) ((base) + 0x8004)
|
||||
#define PCIE_WRDMA0_SAR_LOW(base) ((base) + 0x8008)
|
||||
#define PCIE_WRDMA0_SAR_HIGH(base) ((base) + 0x800c)
|
||||
#define PCIE_WRDMA0_DAR_LOW(base) ((base) + 0x8010)
|
||||
#define PCIE_WRDMA0_DAR_HIGH(base) ((base) + 0x8014)
|
||||
#define PCIE_WRDMA0_LLPTR_LOW(base) ((base) + 0x8018)
|
||||
#define PCIE_WRDMA0_LLPTR_HIGH(base) ((base) + 0x801c)
|
||||
#define PCIE_WRDMA1_CHNL_CNTRL(base) ((base) + 0x8020)
|
||||
#define PCIE_WRDMA1_XFR_SIZE(base) ((base) + 0x8024)
|
||||
#define PCIE_WRDMA1_SAR_LOW(base) ((base) + 0x8028)
|
||||
#define PCIE_WRDMA1_SAR_HIGH(base) ((base) + 0x802c)
|
||||
#define PCIE_WRDMA1_DAR_LOW(base) ((base) + 0x8030)
|
||||
#define PCIE_WRDMA1_DAR_HIGH(base) ((base) + 0x8034)
|
||||
#define PCIE_WRDMA1_LLPTR_LOW(base) ((base) + 0x8038)
|
||||
#define PCIE_WRDMA1_LLPTR_HIGH(base) ((base) + 0x803c)
|
||||
#define PCIE_RDDMA0_CHNL_CNTRL(base) ((base) + 0x8040)
|
||||
#define PCIE_RDDMA0_XFR_SIZE(base) ((base) + 0x8044)
|
||||
#define PCIE_RDDMA0_SAR_LOW(base) ((base) + 0x8048)
|
||||
#define PCIE_RDDMA0_SAR_HIGH(base) ((base) + 0x804c)
|
||||
#define PCIE_RDDMA0_DAR_LOW(base) ((base) + 0x8050)
|
||||
#define PCIE_RDDMA0_DAR_HIGH(base) ((base) + 0x8054)
|
||||
#define PCIE_RDDMA0_LLPTR_LOW(base) ((base) + 0x8058)
|
||||
#define PCIE_RDDMA0_LLPTR_HIGH(base) ((base) + 0x805c)
|
||||
#define PCIE_RDDMA1_CHNL_CNTRL(base) ((base) + 0x8060)
|
||||
#define PCIE_RDDMA1_XFR_SIZE(base) ((base) + 0x8064)
|
||||
#define PCIE_RDDMA1_SAR_LOW(base) ((base) + 0x8068)
|
||||
#define PCIE_RDDMA1_SAR_HIGH(base) ((base) + 0x806c)
|
||||
#define PCIE_RDDMA1_DAR_LOW(base) ((base) + 0x8070)
|
||||
#define PCIE_RDDMA1_DAR_HIGH(base) ((base) + 0x8074)
|
||||
#define PCIE_RDDMA1_LLPTR_LOW(base) ((base) + 0x8078)
|
||||
#define PCIE_RDDMA1_LLPTR_HIGH(base) ((base) + 0x807c)
|
||||
|
||||
#define PCIE_ID(base) ((base) + 0x0000)
|
||||
#define PCIE_CMD(base) ((base) + 0x0004)
|
||||
#define PCIE_BAR(base, n) ((base) + 0x0010 + ((n) << 2))
|
||||
#define PCIE_CAP_PTR(base) ((base) + 0x0034)
|
||||
#define PCIE_MSI_LBAR(base) ((base) + 0x0054)
|
||||
#define PCIE_MSI_CTRL(base) ((base) + 0x0050)
|
||||
#define PCIE_MSI_ADDR_L(base) ((base) + 0x0054)
|
||||
#define PCIE_MSI_ADDR_H(base) ((base) + 0x0058)
|
||||
#define PCIE_MSI_DATA(base) ((base) + 0x005C)
|
||||
#define PCIE_MSI_MASK_BIT(base) ((base) + 0x0060)
|
||||
#define PCIE_MSI_PEND_BIT(base) ((base) + 0x0064)
|
||||
#define PCIE_DEVCAP(base) ((base) + 0x0074)
|
||||
#define PCIE_DEVCTLSTS(base) ((base) + 0x0078)
|
||||
|
||||
#define PCIE_CMDSTS(base) ((base) + 0x0004)
|
||||
#define PCIE_LINK_STAT(base) ((base) + 0x80)
|
||||
#define PCIE_LINK_CTL2(base) ((base) + 0xa0)
|
||||
#define PCIE_ASPM_L1_CTRL(base) ((base) + 0x70c)
|
||||
#define PCIE_ASPM_LINK_CTRL(base) (PCIE_LINK_STAT)
|
||||
#define PCIE_ASPM_L1_SUBSTATE_TIMING(base) ((base) + 0xB44)
|
||||
#define PCIE_L1SUB_CTRL1(base) ((base) + 0x150)
|
||||
#define PCIE_PMCSR(base) ((base) + 0x44)
|
||||
#define PCIE_CFG_SPACE_LIMIT(base) ((base) + 0x100)
|
||||
|
||||
/* PCIe link defines */
|
||||
#define PEARL_PCIE_LINKUP (0x7)
|
||||
#define PEARL_PCIE_DATA_LINK (BIT(0))
|
||||
#define PEARL_PCIE_PHY_LINK (BIT(1))
|
||||
#define PEARL_PCIE_LINK_RST (BIT(3))
|
||||
#define PEARL_PCIE_FATAL_ERR (BIT(5))
|
||||
#define PEARL_PCIE_NONFATAL_ERR (BIT(6))
|
||||
|
||||
/* PCIe Lane defines */
|
||||
#define PCIE_G2_LANE_X1 ((BIT(0)) << 16)
|
||||
#define PCIE_G2_LANE_X2 ((BIT(0) | BIT(1)) << 16)
|
||||
|
||||
/* PCIe DLL link enable */
|
||||
#define PCIE_DLL_LINK_EN ((BIT(0)) << 5)
|
||||
|
||||
#define PCIE_LINK_GEN1 (BIT(0))
|
||||
#define PCIE_LINK_GEN2 (BIT(1))
|
||||
#define PCIE_LINK_GEN3 (BIT(2))
|
||||
#define PCIE_LINK_MODE(x) (((x) >> 16) & 0x7)
|
||||
|
||||
#define MSI_EN (BIT(0))
|
||||
#define MSI_64_EN (BIT(7))
|
||||
#define PCIE_MSI_ADDR_OFFSET(a) ((a) & 0xFFFF)
|
||||
#define PCIE_MSI_ADDR_ALIGN(a) ((a) & (~0xFFFF))
|
||||
|
||||
#define PCIE_BAR_MASK(base, n) ((base) + 0x1010 + ((n) << 2))
|
||||
#define PCIE_MAX_BAR (6)
|
||||
|
||||
#define PCIE_ATU_VIEW(base) ((base) + 0x0900)
|
||||
#define PCIE_ATU_CTL1(base) ((base) + 0x0904)
|
||||
#define PCIE_ATU_CTL2(base) ((base) + 0x0908)
|
||||
#define PCIE_ATU_LBAR(base) ((base) + 0x090c)
|
||||
#define PCIE_ATU_UBAR(base) ((base) + 0x0910)
|
||||
#define PCIE_ATU_LAR(base) ((base) + 0x0914)
|
||||
#define PCIE_ATU_LTAR(base) ((base) + 0x0918)
|
||||
#define PCIE_ATU_UTAR(base) ((base) + 0x091c)
|
||||
|
||||
#define PCIE_MSI_ADDR_LOWER(base) ((base) + 0x0820)
|
||||
#define PCIE_MSI_ADDR_UPPER(base) ((base) + 0x0824)
|
||||
#define PCIE_MSI_ENABLE(base) ((base) + 0x0828)
|
||||
#define PCIE_MSI_MASK_RC(base) ((base) + 0x082c)
|
||||
#define PCIE_MSI_STATUS(base) ((base) + 0x0830)
|
||||
#define PEARL_PCIE_MSI_REGION (0xce000000)
|
||||
#define PEARL_PCIE_MSI_DATA (0)
|
||||
#define PCIE_MSI_GPIO(base) ((base) + 0x0888)
|
||||
|
||||
#define PCIE_HDP_HOST_QUEUE_FULL (BIT(17))
|
||||
#define USE_BAR_MATCH_MODE
|
||||
#define PCIE_ATU_OB_REGION (BIT(0))
|
||||
#define PCIE_ATU_EN_REGION (BIT(31))
|
||||
#define PCIE_ATU_EN_MATCH (BIT(30))
|
||||
#define PCIE_BASE_REGION (0xb0000000)
|
||||
#define PCIE_MEM_MAP_SIZE (512 * 1024)
|
||||
|
||||
#define PCIE_OB_REG_REGION (0xcf000000)
|
||||
#define PCIE_CONFIG_REGION (0xcf000000)
|
||||
#define PCIE_CONFIG_SIZE (4096)
|
||||
#define PCIE_CONFIG_CH (1)
|
||||
|
||||
/* inbound mapping */
|
||||
#define PCIE_IB_BAR0 (0x00000000) /* ddr */
|
||||
#define PCIE_IB_BAR0_CH (0)
|
||||
#define PCIE_IB_BAR3 (0xe0000000) /* sys_reg */
|
||||
#define PCIE_IB_BAR3_CH (1)
|
||||
|
||||
/* outbound mapping */
|
||||
#define PCIE_MEM_CH (0)
|
||||
#define PCIE_REG_CH (1)
|
||||
#define PCIE_MEM_REGION (0xc0000000)
|
||||
#define PCIE_MEM_SIZE (0x000fffff)
|
||||
#define PCIE_MEM_TAR (0x80000000)
|
||||
|
||||
#define PCIE_MSI_REGION (0xce000000)
|
||||
#define PCIE_MSI_SIZE (KBYTE(4) - 1)
|
||||
#define PCIE_MSI_CH (1)
|
||||
|
||||
/* size of config region */
|
||||
#define PCIE_CFG_SIZE (0x0000ffff)
|
||||
|
||||
#define PCIE_ATU_DIR_IB (BIT(31))
|
||||
#define PCIE_ATU_DIR_OB (0)
|
||||
#define PCIE_ATU_DIR_CFG (2)
|
||||
#define PCIE_ATU_DIR_MATCH_IB (BIT(31) | BIT(30))
|
||||
|
||||
#define PCIE_DMA_WR_0 (0)
|
||||
#define PCIE_DMA_WR_1 (1)
|
||||
#define PCIE_DMA_RD_0 (2)
|
||||
#define PCIE_DMA_RD_1 (3)
|
||||
|
||||
#define PCIE_DMA_CHNL_CNTRL_CB (BIT(0))
|
||||
#define PCIE_DMA_CHNL_CNTRL_TCB (BIT(1))
|
||||
#define PCIE_DMA_CHNL_CNTRL_LLP (BIT(2))
|
||||
#define PCIE_DMA_CHNL_CNTRL_LIE (BIT(3))
|
||||
#define PCIE_DMA_CHNL_CNTRL_RIE (BIT(4))
|
||||
#define PCIE_DMA_CHNL_CNTRL_CSS (BIT(8))
|
||||
#define PCIE_DMA_CHNL_CNTRL_LLE (BIT(9))
|
||||
#define PCIE_DMA_CHNL_CNTRL_TLP (BIT(26))
|
||||
|
||||
#define PCIE_DMA_CHNL_CONTEXT_RD (BIT(31))
|
||||
#define PCIE_DMA_CHNL_CONTEXT_WR (0)
|
||||
#define PCIE_MAX_BAR (6)
|
||||
|
||||
/* PCIe HDP interrupt status definition */
|
||||
#define PCIE_HDP_INT_EP_RXDMA (BIT(0))
|
||||
#define PCIE_HDP_INT_HBM_UF (BIT(1))
|
||||
#define PCIE_HDP_INT_RX_LEN_ERR (BIT(2))
|
||||
#define PCIE_HDP_INT_RX_HDR_LEN_ERR (BIT(3))
|
||||
#define PCIE_HDP_INT_EP_TXDMA (BIT(12))
|
||||
#define PCIE_HDP_INT_EP_TXEMPTY (BIT(15))
|
||||
#define PCIE_HDP_INT_IPC (BIT(29))
|
||||
|
||||
/* PCIe interrupt status definition */
|
||||
#define PCIE_INT_MSI (BIT(24))
|
||||
#define PCIE_INT_INTX (BIT(23))
|
||||
|
||||
/* PCIe legacy INTx */
|
||||
#define PEARL_PCIE_CFG0_OFFSET (0x6C)
|
||||
#define PEARL_ASSERT_INTX (BIT(9))
|
||||
|
||||
/* SYS CTL regs */
|
||||
#define QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET (0x001C)
|
||||
|
||||
#define QTN_PEARL_IPC_IRQ_WORD(irq) (BIT(irq) | BIT(irq + 16))
|
||||
#define QTN_PEARL_LHOST_IPC_IRQ (6)
|
||||
|
||||
#endif /* __PEARL_PCIE_H */
|
901
drivers/net/wireless/quantenna/qtnfmac/qlink.h
Normal file
901
drivers/net/wireless/quantenna/qtnfmac/qlink.h
Normal file
@ -0,0 +1,901 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_QLINK_H_
|
||||
#define _QTN_QLINK_H_
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
|
||||
#define QLINK_PROTO_VER 3
|
||||
|
||||
#define QLINK_MACID_RSVD 0xFF
|
||||
#define QLINK_VIFID_RSVD 0xFF
|
||||
|
||||
/* Common QLINK protocol messages definitions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum qlink_msg_type - QLINK message types
|
||||
*
|
||||
* Used to distinguish between message types of QLINK protocol.
|
||||
*
|
||||
* @QLINK_MSG_TYPE_CMD: Message is carrying data of a command sent from
|
||||
* driver to wireless hardware.
|
||||
* @QLINK_MSG_TYPE_CMDRSP: Message is carrying data of a response to a command.
|
||||
* Sent from wireless HW to driver in reply to previously issued command.
|
||||
* @QLINK_MSG_TYPE_EVENT: Data for an event originated in wireless hardware and
|
||||
* sent asynchronously to driver.
|
||||
*/
|
||||
enum qlink_msg_type {
|
||||
QLINK_MSG_TYPE_CMD = 1,
|
||||
QLINK_MSG_TYPE_CMDRSP = 2,
|
||||
QLINK_MSG_TYPE_EVENT = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_msg_header - common QLINK protocol message header
|
||||
*
|
||||
* Portion of QLINK protocol header common for all message types.
|
||||
*
|
||||
* @type: Message type, one of &enum qlink_msg_type.
|
||||
* @len: Total length of message including all headers.
|
||||
*/
|
||||
struct qlink_msg_header {
|
||||
__le16 type;
|
||||
__le16 len;
|
||||
} __packed;
|
||||
|
||||
/* Generic definitions of data and information carried in QLINK messages
|
||||
*/
|
||||
|
||||
enum qlink_hw_capab {
|
||||
QLINK_HW_SUPPORTS_REG_UPDATE = BIT(0),
|
||||
};
|
||||
|
||||
enum qlink_phy_mode {
|
||||
QLINK_PHYMODE_BGN = BIT(0),
|
||||
QLINK_PHYMODE_AN = BIT(1),
|
||||
QLINK_PHYMODE_AC = BIT(2),
|
||||
};
|
||||
|
||||
enum qlink_iface_type {
|
||||
QLINK_IFTYPE_AP = 1,
|
||||
QLINK_IFTYPE_STATION = 2,
|
||||
QLINK_IFTYPE_ADHOC = 3,
|
||||
QLINK_IFTYPE_MONITOR = 4,
|
||||
QLINK_IFTYPE_WDS = 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_intf_info - information on virtual interface.
|
||||
*
|
||||
* Data describing a single virtual interface.
|
||||
*
|
||||
* @if_type: Mode of interface operation, one of &enum qlink_iface_type
|
||||
* @flags: interface flagsmap.
|
||||
* @mac_addr: MAC address of virtual interface.
|
||||
*/
|
||||
struct qlink_intf_info {
|
||||
__le16 if_type;
|
||||
__le16 flags;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 rsvd[2];
|
||||
} __packed;
|
||||
|
||||
enum qlink_sta_flags {
|
||||
QLINK_STA_FLAG_INVALID = 0,
|
||||
QLINK_STA_FLAG_AUTHORIZED = BIT(0),
|
||||
QLINK_STA_FLAG_SHORT_PREAMBLE = BIT(1),
|
||||
QLINK_STA_FLAG_WME = BIT(2),
|
||||
QLINK_STA_FLAG_MFP = BIT(3),
|
||||
QLINK_STA_FLAG_AUTHENTICATED = BIT(4),
|
||||
QLINK_STA_FLAG_TDLS_PEER = BIT(5),
|
||||
QLINK_STA_FLAG_ASSOCIATED = BIT(6),
|
||||
};
|
||||
|
||||
enum qlink_channel_width {
|
||||
QLINK_CHAN_WIDTH_5 = BIT(0),
|
||||
QLINK_CHAN_WIDTH_10 = BIT(1),
|
||||
QLINK_CHAN_WIDTH_20_NOHT = BIT(2),
|
||||
QLINK_CHAN_WIDTH_20 = BIT(3),
|
||||
QLINK_CHAN_WIDTH_40 = BIT(4),
|
||||
QLINK_CHAN_WIDTH_80 = BIT(5),
|
||||
QLINK_CHAN_WIDTH_80P80 = BIT(6),
|
||||
QLINK_CHAN_WIDTH_160 = BIT(7),
|
||||
};
|
||||
|
||||
/* QLINK Command messages related definitions
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum qlink_cmd_type - list of supported commands
|
||||
*
|
||||
* Commands are QLINK messages of type @QLINK_MSG_TYPE_CMD, sent by driver to
|
||||
* wireless network device for processing. Device is expected to send back a
|
||||
* reply message of type &QLINK_MSG_TYPE_CMDRSP, containing at least command
|
||||
* execution status (one of &enum qlink_cmd_result) at least. Reply message
|
||||
* may also contain data payload specific to the command type.
|
||||
*
|
||||
* @QLINK_CMD_CHANS_INFO_GET: for the specified MAC and specified band, get
|
||||
* number of operational channels and information on each of the channel.
|
||||
* This command is generic to a specified MAC, interface index must be set
|
||||
* to QLINK_VIFID_RSVD in command header.
|
||||
*/
|
||||
enum qlink_cmd_type {
|
||||
QLINK_CMD_FW_INIT = 0x0001,
|
||||
QLINK_CMD_FW_DEINIT = 0x0002,
|
||||
QLINK_CMD_REGISTER_MGMT = 0x0003,
|
||||
QLINK_CMD_SEND_MGMT_FRAME = 0x0004,
|
||||
QLINK_CMD_MGMT_SET_APPIE = 0x0005,
|
||||
QLINK_CMD_PHY_PARAMS_GET = 0x0011,
|
||||
QLINK_CMD_PHY_PARAMS_SET = 0x0012,
|
||||
QLINK_CMD_GET_HW_INFO = 0x0013,
|
||||
QLINK_CMD_MAC_INFO = 0x0014,
|
||||
QLINK_CMD_ADD_INTF = 0x0015,
|
||||
QLINK_CMD_DEL_INTF = 0x0016,
|
||||
QLINK_CMD_CHANGE_INTF = 0x0017,
|
||||
QLINK_CMD_UPDOWN_INTF = 0x0018,
|
||||
QLINK_CMD_REG_REGION = 0x0019,
|
||||
QLINK_CMD_CHANS_INFO_GET = 0x001A,
|
||||
QLINK_CMD_CONFIG_AP = 0x0020,
|
||||
QLINK_CMD_START_AP = 0x0021,
|
||||
QLINK_CMD_STOP_AP = 0x0022,
|
||||
QLINK_CMD_GET_STA_INFO = 0x0030,
|
||||
QLINK_CMD_ADD_KEY = 0x0040,
|
||||
QLINK_CMD_DEL_KEY = 0x0041,
|
||||
QLINK_CMD_SET_DEFAULT_KEY = 0x0042,
|
||||
QLINK_CMD_SET_DEFAULT_MGMT_KEY = 0x0043,
|
||||
QLINK_CMD_CHANGE_STA = 0x0051,
|
||||
QLINK_CMD_DEL_STA = 0x0052,
|
||||
QLINK_CMD_SCAN = 0x0053,
|
||||
QLINK_CMD_CONNECT = 0x0060,
|
||||
QLINK_CMD_DISCONNECT = 0x0061,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_cmd - QLINK command message header
|
||||
*
|
||||
* Header used for QLINK messages of QLINK_MSG_TYPE_CMD type.
|
||||
*
|
||||
* @mhdr: Common QLINK message header.
|
||||
* @cmd_id: command id, one of &enum qlink_cmd_type.
|
||||
* @seq_num: sequence number of command message, used for matching with
|
||||
* response message.
|
||||
* @macid: index of physical radio device the command is destined to or
|
||||
* QLINK_MACID_RSVD if not applicable.
|
||||
* @vifid: index of virtual wireless interface on specified @macid the command
|
||||
* is destined to or QLINK_VIFID_RSVD if not applicable.
|
||||
*/
|
||||
struct qlink_cmd {
|
||||
struct qlink_msg_header mhdr;
|
||||
__le16 cmd_id;
|
||||
__le16 seq_num;
|
||||
u8 rsvd[2];
|
||||
u8 macid;
|
||||
u8 vifid;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_manage_intf - interface management command
|
||||
*
|
||||
* Data for interface management commands QLINK_CMD_ADD_INTF, QLINK_CMD_DEL_INTF
|
||||
* and QLINK_CMD_CHANGE_INTF.
|
||||
*
|
||||
* @intf_info: interface description.
|
||||
*/
|
||||
struct qlink_cmd_manage_intf {
|
||||
struct qlink_cmd chdr;
|
||||
struct qlink_intf_info intf_info;
|
||||
} __packed;
|
||||
|
||||
enum qlink_mgmt_frame_type {
|
||||
QLINK_MGMT_FRAME_ASSOC_REQ = 0x00,
|
||||
QLINK_MGMT_FRAME_ASSOC_RESP = 0x01,
|
||||
QLINK_MGMT_FRAME_REASSOC_REQ = 0x02,
|
||||
QLINK_MGMT_FRAME_REASSOC_RESP = 0x03,
|
||||
QLINK_MGMT_FRAME_PROBE_REQ = 0x04,
|
||||
QLINK_MGMT_FRAME_PROBE_RESP = 0x05,
|
||||
QLINK_MGMT_FRAME_BEACON = 0x06,
|
||||
QLINK_MGMT_FRAME_ATIM = 0x07,
|
||||
QLINK_MGMT_FRAME_DISASSOC = 0x08,
|
||||
QLINK_MGMT_FRAME_AUTH = 0x09,
|
||||
QLINK_MGMT_FRAME_DEAUTH = 0x0A,
|
||||
QLINK_MGMT_FRAME_ACTION = 0x0B,
|
||||
|
||||
QLINK_MGMT_FRAME_TYPE_COUNT
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_mgmt_frame_register - data for QLINK_CMD_REGISTER_MGMT
|
||||
*
|
||||
* @frame_type: MGMT frame type the registration request describes, one of
|
||||
* &enum qlink_mgmt_frame_type.
|
||||
* @do_register: 0 - unregister, otherwise register for reception of specified
|
||||
* MGMT frame type.
|
||||
*/
|
||||
struct qlink_cmd_mgmt_frame_register {
|
||||
struct qlink_cmd chdr;
|
||||
__le16 frame_type;
|
||||
u8 do_register;
|
||||
} __packed;
|
||||
|
||||
enum qlink_mgmt_frame_tx_flags {
|
||||
QLINK_MGMT_FRAME_TX_FLAG_NONE = 0,
|
||||
QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN = BIT(0),
|
||||
QLINK_MGMT_FRAME_TX_FLAG_NO_CCK = BIT(1),
|
||||
QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT = BIT(2),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_mgmt_frame_tx - data for QLINK_CMD_SEND_MGMT_FRAME command
|
||||
*
|
||||
* @cookie: opaque request identifier.
|
||||
* @freq: Frequency to use for frame transmission.
|
||||
* @flags: Transmission flags, one of &enum qlink_mgmt_frame_tx_flags.
|
||||
* @frame_data: frame to transmit.
|
||||
*/
|
||||
struct qlink_cmd_mgmt_frame_tx {
|
||||
struct qlink_cmd chdr;
|
||||
__le32 cookie;
|
||||
__le16 freq;
|
||||
__le16 flags;
|
||||
u8 frame_data[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_mgmt_append_ie - data for QLINK_CMD_MGMT_SET_APPIE command
|
||||
*
|
||||
* @type: type of MGMT frame to appent requested IEs to, one of
|
||||
* &enum qlink_mgmt_frame_type.
|
||||
* @flags: for future use.
|
||||
* @ie_data: IEs data to append.
|
||||
*/
|
||||
struct qlink_cmd_mgmt_append_ie {
|
||||
struct qlink_cmd chdr;
|
||||
u8 type;
|
||||
u8 flags;
|
||||
u8 ie_data[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_get_sta_info - data for QLINK_CMD_GET_STA_INFO command
|
||||
*
|
||||
* @sta_addr: MAC address of the STA statistics is requested for.
|
||||
*/
|
||||
struct qlink_cmd_get_sta_info {
|
||||
struct qlink_cmd chdr;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_add_key - data for QLINK_CMD_ADD_KEY command.
|
||||
*
|
||||
* @key_index: index of the key being installed.
|
||||
* @pairwise: whether to use pairwise key.
|
||||
* @addr: MAC address of a STA key is being installed to.
|
||||
* @cipher: cipher suite.
|
||||
* @key_data: key data itself.
|
||||
*/
|
||||
struct qlink_cmd_add_key {
|
||||
struct qlink_cmd chdr;
|
||||
u8 key_index;
|
||||
u8 pairwise;
|
||||
u8 addr[ETH_ALEN];
|
||||
__le32 cipher;
|
||||
u8 key_data[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_del_key_req - data for QLINK_CMD_DEL_KEY command
|
||||
*
|
||||
* @key_index: index of the key being removed.
|
||||
* @pairwise: whether to use pairwise key.
|
||||
* @addr: MAC address of a STA for which a key is removed.
|
||||
*/
|
||||
struct qlink_cmd_del_key {
|
||||
struct qlink_cmd chdr;
|
||||
u8 key_index;
|
||||
u8 pairwise;
|
||||
u8 addr[ETH_ALEN];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_set_def_key - data for QLINK_CMD_SET_DEFAULT_KEY command
|
||||
*
|
||||
* @key_index: index of the key to be set as default one.
|
||||
* @unicast: key is unicast.
|
||||
* @multicast: key is multicast.
|
||||
*/
|
||||
struct qlink_cmd_set_def_key {
|
||||
struct qlink_cmd chdr;
|
||||
u8 key_index;
|
||||
u8 unicast;
|
||||
u8 multicast;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_set_def_mgmt_key - data for QLINK_CMD_SET_DEFAULT_MGMT_KEY
|
||||
*
|
||||
* @key_index: index of the key to be set as default MGMT key.
|
||||
*/
|
||||
struct qlink_cmd_set_def_mgmt_key {
|
||||
struct qlink_cmd chdr;
|
||||
u8 key_index;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_change_sta - data for QLINK_CMD_CHANGE_STA command
|
||||
*
|
||||
* @sta_flags_mask: STA flags mask, bitmap of &enum qlink_sta_flags
|
||||
* @sta_flags_set: STA flags values, bitmap of &enum qlink_sta_flags
|
||||
* @sta_addr: address of the STA for which parameters are set.
|
||||
*/
|
||||
struct qlink_cmd_change_sta {
|
||||
struct qlink_cmd chdr;
|
||||
__le32 sta_flags_mask;
|
||||
__le32 sta_flags_set;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_del_sta - data for QLINK_CMD_DEL_STA command.
|
||||
*
|
||||
* See &struct station_del_parameters
|
||||
*/
|
||||
struct qlink_cmd_del_sta {
|
||||
struct qlink_cmd chdr;
|
||||
__le16 reason_code;
|
||||
u8 subtype;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
} __packed;
|
||||
|
||||
enum qlink_sta_connect_flags {
|
||||
QLINK_STA_CONNECT_DISABLE_HT = BIT(0),
|
||||
QLINK_STA_CONNECT_DISABLE_VHT = BIT(1),
|
||||
QLINK_STA_CONNECT_USE_RRM = BIT(2),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_connect - data for QLINK_CMD_CONNECT command
|
||||
*
|
||||
* @flags: for future use.
|
||||
* @freq: center frequence of a channel which should be used to connect.
|
||||
* @bg_scan_period: period of background scan.
|
||||
* @bssid: BSSID of the BSS to connect to.
|
||||
* @payload: variable portion of connection request.
|
||||
*/
|
||||
struct qlink_cmd_connect {
|
||||
struct qlink_cmd chdr;
|
||||
__le32 flags;
|
||||
__le16 freq;
|
||||
__le16 bg_scan_period;
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 payload[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_disconnect - data for QLINK_CMD_DISCONNECT command
|
||||
*
|
||||
* @reason: code of the reason of disconnect, see &enum ieee80211_reasoncode.
|
||||
*/
|
||||
struct qlink_cmd_disconnect {
|
||||
struct qlink_cmd chdr;
|
||||
__le16 reason;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_updown - data for QLINK_CMD_UPDOWN_INTF command
|
||||
*
|
||||
* @if_up: bring specified interface DOWN (if_up==0) or UP (otherwise).
|
||||
* Interface is specified in common command header @chdr.
|
||||
*/
|
||||
struct qlink_cmd_updown {
|
||||
struct qlink_cmd chdr;
|
||||
u8 if_up;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* enum qlink_band - a list of frequency bands
|
||||
*
|
||||
* @QLINK_BAND_2GHZ: 2.4GHz band
|
||||
* @QLINK_BAND_5GHZ: 5GHz band
|
||||
* @QLINK_BAND_60GHZ: 60GHz band
|
||||
*/
|
||||
enum qlink_band {
|
||||
QLINK_BAND_2GHZ = BIT(0),
|
||||
QLINK_BAND_5GHZ = BIT(1),
|
||||
QLINK_BAND_60GHZ = BIT(2),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_cmd_chans_info_get - data for QLINK_CMD_CHANS_INFO_GET command
|
||||
*
|
||||
* @band: a PHY band for which channels info is needed, one of @enum qlink_band
|
||||
*/
|
||||
struct qlink_cmd_chans_info_get {
|
||||
struct qlink_cmd chdr;
|
||||
u8 band;
|
||||
} __packed;
|
||||
|
||||
/* QLINK Command Responses messages related definitions
|
||||
*/
|
||||
|
||||
enum qlink_cmd_result {
|
||||
QLINK_CMD_RESULT_OK = 0,
|
||||
QLINK_CMD_RESULT_INVALID,
|
||||
QLINK_CMD_RESULT_ENOTSUPP,
|
||||
QLINK_CMD_RESULT_ENOTFOUND,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_resp - QLINK command response message header
|
||||
*
|
||||
* Header used for QLINK messages of QLINK_MSG_TYPE_CMDRSP type.
|
||||
*
|
||||
* @mhdr: see &struct qlink_msg_header.
|
||||
* @cmd_id: command ID the response corresponds to, one of &enum qlink_cmd_type.
|
||||
* @seq_num: sequence number of command message, used for matching with
|
||||
* response message.
|
||||
* @result: result of the command execution, one of &enum qlink_cmd_result.
|
||||
* @macid: index of physical radio device the response is sent from or
|
||||
* QLINK_MACID_RSVD if not applicable.
|
||||
* @vifid: index of virtual wireless interface on specified @macid the response
|
||||
* is sent from or QLINK_VIFID_RSVD if not applicable.
|
||||
*/
|
||||
struct qlink_resp {
|
||||
struct qlink_msg_header mhdr;
|
||||
__le16 cmd_id;
|
||||
__le16 seq_num;
|
||||
__le16 result;
|
||||
u8 macid;
|
||||
u8 vifid;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_resp_get_mac_info - response for QLINK_CMD_MAC_INFO command
|
||||
*
|
||||
* Data describing specific physical device providing wireless MAC
|
||||
* functionality.
|
||||
*
|
||||
* @dev_mac: MAC address of physical WMAC device (used for first BSS on
|
||||
* specified WMAC).
|
||||
* @num_tx_chain: Number of transmit chains used by WMAC.
|
||||
* @num_rx_chain: Number of receive chains used by WMAC.
|
||||
* @vht_cap: VHT capabilities.
|
||||
* @ht_cap: HT capabilities.
|
||||
* @bands_cap: wireless bands WMAC can operate in, bitmap of &enum qlink_band.
|
||||
* @phymode_cap: PHY modes WMAC can operate in, bitmap of &enum qlink_phy_mode.
|
||||
* @max_ap_assoc_sta: Maximum number of associations supported by WMAC.
|
||||
* @radar_detect_widths: bitmask of channels BW for which WMAC can detect radar.
|
||||
* @var_info: variable-length WMAC info data.
|
||||
*/
|
||||
struct qlink_resp_get_mac_info {
|
||||
struct qlink_resp rhdr;
|
||||
u8 dev_mac[ETH_ALEN];
|
||||
u8 num_tx_chain;
|
||||
u8 num_rx_chain;
|
||||
struct ieee80211_vht_cap vht_cap;
|
||||
struct ieee80211_ht_cap ht_cap;
|
||||
u8 bands_cap;
|
||||
u8 phymode_cap;
|
||||
__le16 max_ap_assoc_sta;
|
||||
__le16 radar_detect_widths;
|
||||
u8 var_info[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_resp_get_hw_info - response for QLINK_CMD_GET_HW_INFO command
|
||||
*
|
||||
* Description of wireless hardware capabilities and features.
|
||||
*
|
||||
* @fw_ver: wireless hardware firmware version.
|
||||
* @hw_capab: Bitmap of capabilities supported by firmware.
|
||||
* @ql_proto_ver: Version of QLINK protocol used by firmware.
|
||||
* @country_code: country code ID firmware is configured to.
|
||||
* @num_mac: Number of separate physical radio devices provided by hardware.
|
||||
* @mac_bitmap: Bitmap of MAC IDs that are active and can be used in firmware.
|
||||
* @total_tx_chains: total number of transmit chains used by device.
|
||||
* @total_rx_chains: total number of receive chains.
|
||||
*/
|
||||
struct qlink_resp_get_hw_info {
|
||||
struct qlink_resp rhdr;
|
||||
__le32 fw_ver;
|
||||
__le32 hw_capab;
|
||||
__le16 ql_proto_ver;
|
||||
u8 alpha2_code[2];
|
||||
u8 num_mac;
|
||||
u8 mac_bitmap;
|
||||
u8 total_tx_chain;
|
||||
u8 total_rx_chain;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_resp_manage_intf - response for interface management commands
|
||||
*
|
||||
* Response data for QLINK_CMD_ADD_INTF and QLINK_CMD_CHANGE_INTF commands.
|
||||
*
|
||||
* @rhdr: Common Command Response message header.
|
||||
* @intf_info: interface description.
|
||||
*/
|
||||
struct qlink_resp_manage_intf {
|
||||
struct qlink_resp rhdr;
|
||||
struct qlink_intf_info intf_info;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_resp_get_sta_info - response for QLINK_CMD_GET_STA_INFO command
|
||||
*
|
||||
* Response data containing statistics for specified STA.
|
||||
*
|
||||
* @sta_addr: MAC address of STA the response carries statistic for.
|
||||
* @info: statistics for specified STA.
|
||||
*/
|
||||
struct qlink_resp_get_sta_info {
|
||||
struct qlink_resp rhdr;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
u8 info[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_resp_get_chan_info - response for QLINK_CMD_CHANS_INFO_GET cmd
|
||||
*
|
||||
* @band: frequency band to which channels belong to, one of @enum qlink_band.
|
||||
* @num_chans: total number of channels info data contained in reply data.
|
||||
* @info: variable-length channels info.
|
||||
*/
|
||||
struct qlink_resp_get_chan_info {
|
||||
struct qlink_resp rhdr;
|
||||
u8 band;
|
||||
u8 num_chans;
|
||||
u8 rsvd[2];
|
||||
u8 info[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_resp_phy_params - response for QLINK_CMD_PHY_PARAMS_GET command
|
||||
*
|
||||
* @info: variable-length array of PHY params.
|
||||
*/
|
||||
struct qlink_resp_phy_params {
|
||||
struct qlink_resp rhdr;
|
||||
u8 info[0];
|
||||
} __packed;
|
||||
|
||||
/* QLINK Events messages related definitions
|
||||
*/
|
||||
|
||||
enum qlink_event_type {
|
||||
QLINK_EVENT_STA_ASSOCIATED = 0x0021,
|
||||
QLINK_EVENT_STA_DEAUTH = 0x0022,
|
||||
QLINK_EVENT_MGMT_RECEIVED = 0x0023,
|
||||
QLINK_EVENT_SCAN_RESULTS = 0x0024,
|
||||
QLINK_EVENT_SCAN_COMPLETE = 0x0025,
|
||||
QLINK_EVENT_BSS_JOIN = 0x0026,
|
||||
QLINK_EVENT_BSS_LEAVE = 0x0027,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_event - QLINK event message header
|
||||
*
|
||||
* Header used for QLINK messages of QLINK_MSG_TYPE_EVENT type.
|
||||
*
|
||||
* @mhdr: Common QLINK message header.
|
||||
* @event_id: Specifies specific event ID, one of &enum qlink_event_type.
|
||||
* @macid: index of physical radio device the event was generated on or
|
||||
* QLINK_MACID_RSVD if not applicable.
|
||||
* @vifid: index of virtual wireless interface on specified @macid the event
|
||||
* was generated on or QLINK_VIFID_RSVD if not applicable.
|
||||
*/
|
||||
struct qlink_event {
|
||||
struct qlink_msg_header mhdr;
|
||||
__le16 event_id;
|
||||
u8 macid;
|
||||
u8 vifid;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_event_sta_assoc - data for QLINK_EVENT_STA_ASSOCIATED event
|
||||
*
|
||||
* @sta_addr: Address of a STA for which new association event was generated
|
||||
* @frame_control: control bits from 802.11 ASSOC_REQUEST header.
|
||||
* @payload: IEs from association request.
|
||||
*/
|
||||
struct qlink_event_sta_assoc {
|
||||
struct qlink_event ehdr;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
__le16 frame_control;
|
||||
u8 ies[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_event_sta_deauth - data for QLINK_EVENT_STA_DEAUTH event
|
||||
*
|
||||
* @sta_addr: Address of a deauthenticated STA.
|
||||
* @reason: reason for deauthentication.
|
||||
*/
|
||||
struct qlink_event_sta_deauth {
|
||||
struct qlink_event ehdr;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
__le16 reason;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_event_bss_join - data for QLINK_EVENT_BSS_JOIN event
|
||||
*
|
||||
* @bssid: BSSID of a BSS which interface tried to joined.
|
||||
* @status: status of joining attempt, see &enum ieee80211_statuscode.
|
||||
*/
|
||||
struct qlink_event_bss_join {
|
||||
struct qlink_event ehdr;
|
||||
u8 bssid[ETH_ALEN];
|
||||
__le16 status;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct qlink_event_bss_leave - data for QLINK_EVENT_BSS_LEAVE event
|
||||
*
|
||||
* @reason: reason of disconnecting from BSS.
|
||||
*/
|
||||
struct qlink_event_bss_leave {
|
||||
struct qlink_event ehdr;
|
||||
u16 reason;
|
||||
} __packed;
|
||||
|
||||
enum qlink_rxmgmt_flags {
|
||||
QLINK_RXMGMT_FLAG_ANSWERED = 1 << 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_event_rxmgmt - data for QLINK_EVENT_MGMT_RECEIVED event
|
||||
*
|
||||
* @freq: Frequency on which the frame was received in MHz.
|
||||
* @sig_dbm: signal strength in dBm.
|
||||
* @flags: bitmap of &enum qlink_rxmgmt_flags.
|
||||
* @frame_data: data of Rx'd frame itself.
|
||||
*/
|
||||
struct qlink_event_rxmgmt {
|
||||
struct qlink_event ehdr;
|
||||
__le32 freq;
|
||||
__le32 sig_dbm;
|
||||
__le32 flags;
|
||||
u8 frame_data[0];
|
||||
} __packed;
|
||||
|
||||
enum qlink_frame_type {
|
||||
QLINK_BSS_FTYPE_UNKNOWN,
|
||||
QLINK_BSS_FTYPE_BEACON,
|
||||
QLINK_BSS_FTYPE_PRESP,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_event_scan_result - data for QLINK_EVENT_SCAN_RESULTS event
|
||||
*
|
||||
* @tsf: TSF timestamp indicating when scan results were generated.
|
||||
* @freq: Center frequency of the channel where BSS for which the scan result
|
||||
* event was generated was discovered.
|
||||
* @capab: capabilities field.
|
||||
* @bintval: beacon interval announced by discovered BSS.
|
||||
* @signal: signal strength.
|
||||
* @frame_type: frame type used to get scan result, see &enum qlink_frame_type.
|
||||
* @bssid: BSSID announced by discovered BSS.
|
||||
* @ssid_len: length of SSID announced by BSS.
|
||||
* @ssid: SSID announced by discovered BSS.
|
||||
* @payload: IEs that are announced by discovered BSS in its MGMt frames.
|
||||
*/
|
||||
struct qlink_event_scan_result {
|
||||
struct qlink_event ehdr;
|
||||
__le64 tsf;
|
||||
__le16 freq;
|
||||
__le16 capab;
|
||||
__le16 bintval;
|
||||
s8 signal;
|
||||
u8 frame_type;
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 ssid_len;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 payload[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* enum qlink_scan_complete_flags - indicates result of scan request.
|
||||
*
|
||||
* @QLINK_SCAN_NONE: Scan request was processed.
|
||||
* @QLINK_SCAN_ABORTED: Scan was aborted.
|
||||
*/
|
||||
enum qlink_scan_complete_flags {
|
||||
QLINK_SCAN_NONE = 0,
|
||||
QLINK_SCAN_ABORTED = BIT(0),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_event_scan_complete - data for QLINK_EVENT_SCAN_COMPLETE event
|
||||
*
|
||||
* @flags: flags indicating the status of pending scan request,
|
||||
* see &enum qlink_scan_complete_flags.
|
||||
*/
|
||||
struct qlink_event_scan_complete {
|
||||
struct qlink_event ehdr;
|
||||
__le32 flags;
|
||||
} __packed;
|
||||
|
||||
/* QLINK TLVs (Type-Length Values) definitions
|
||||
*/
|
||||
|
||||
enum qlink_tlv_id {
|
||||
QTN_TLV_ID_FRAG_THRESH = 0x0201,
|
||||
QTN_TLV_ID_RTS_THRESH = 0x0202,
|
||||
QTN_TLV_ID_SRETRY_LIMIT = 0x0203,
|
||||
QTN_TLV_ID_LRETRY_LIMIT = 0x0204,
|
||||
QTN_TLV_ID_BCN_PERIOD = 0x0205,
|
||||
QTN_TLV_ID_DTIM = 0x0206,
|
||||
QTN_TLV_ID_CHANNEL = 0x020F,
|
||||
QTN_TLV_ID_COVERAGE_CLASS = 0x0213,
|
||||
QTN_TLV_ID_IFACE_LIMIT = 0x0214,
|
||||
QTN_TLV_ID_NUM_IFACE_COMB = 0x0215,
|
||||
QTN_TLV_ID_STA_BASIC_COUNTERS = 0x0300,
|
||||
QTN_TLV_ID_STA_GENERIC_INFO = 0x0301,
|
||||
QTN_TLV_ID_KEY = 0x0302,
|
||||
QTN_TLV_ID_SEQ = 0x0303,
|
||||
QTN_TLV_ID_CRYPTO = 0x0304,
|
||||
QTN_TLV_ID_IE_SET = 0x0305,
|
||||
};
|
||||
|
||||
struct qlink_tlv_hdr {
|
||||
__le16 type;
|
||||
__le16 len;
|
||||
u8 val[0];
|
||||
} __packed;
|
||||
|
||||
struct qlink_iface_limit {
|
||||
__le16 max_num;
|
||||
__le16 type_mask;
|
||||
} __packed;
|
||||
|
||||
struct qlink_iface_comb_num {
|
||||
__le16 iface_comb_num;
|
||||
} __packed;
|
||||
|
||||
struct qlink_sta_stat_basic_counters {
|
||||
__le64 rx_bytes;
|
||||
__le64 tx_bytes;
|
||||
__le64 rx_beacons;
|
||||
__le32 rx_packets;
|
||||
__le32 tx_packets;
|
||||
__le32 rx_dropped;
|
||||
__le32 tx_failed;
|
||||
} __packed;
|
||||
|
||||
enum qlink_sta_info_rate_flags {
|
||||
QLINK_STA_INFO_RATE_FLAG_INVALID = 0,
|
||||
QLINK_STA_INFO_RATE_FLAG_HT_MCS = BIT(0),
|
||||
QLINK_STA_INFO_RATE_FLAG_VHT_MCS = BIT(1),
|
||||
QLINK_STA_INFO_RATE_FLAG_SHORT_GI = BIT(2),
|
||||
QLINK_STA_INFO_RATE_FLAG_60G = BIT(3),
|
||||
};
|
||||
|
||||
enum qlink_sta_info_rate_bw {
|
||||
QLINK_STA_INFO_RATE_BW_5 = 0,
|
||||
QLINK_STA_INFO_RATE_BW_10 = 1,
|
||||
QLINK_STA_INFO_RATE_BW_20 = 2,
|
||||
QLINK_STA_INFO_RATE_BW_40 = 3,
|
||||
QLINK_STA_INFO_RATE_BW_80 = 4,
|
||||
QLINK_STA_INFO_RATE_BW_160 = 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qlink_sta_info_rate - STA rate statistics
|
||||
*
|
||||
* @rate: data rate in Mbps.
|
||||
* @flags: bitmap of &enum qlink_sta_flags.
|
||||
* @mcs: 802.11-defined MCS index.
|
||||
* nss: Number of Spatial Streams.
|
||||
* @bw: bandwidth, one of &enum qlink_sta_info_rate_bw.
|
||||
*/
|
||||
struct qlink_sta_info_rate {
|
||||
__le16 rate;
|
||||
u8 flags;
|
||||
u8 mcs;
|
||||
u8 nss;
|
||||
u8 bw;
|
||||
} __packed;
|
||||
|
||||
struct qlink_sta_info_state {
|
||||
__le32 mask;
|
||||
__le32 value;
|
||||
} __packed;
|
||||
|
||||
#define QLINK_RSSI_OFFSET 120
|
||||
|
||||
struct qlink_sta_info_generic {
|
||||
struct qlink_sta_info_state state;
|
||||
__le32 connected_time;
|
||||
__le32 inactive_time;
|
||||
struct qlink_sta_info_rate rx_rate;
|
||||
struct qlink_sta_info_rate tx_rate;
|
||||
u8 rssi;
|
||||
u8 rssi_avg;
|
||||
} __packed;
|
||||
|
||||
struct qlink_tlv_frag_rts_thr {
|
||||
struct qlink_tlv_hdr hdr;
|
||||
__le16 thr;
|
||||
} __packed;
|
||||
|
||||
struct qlink_tlv_rlimit {
|
||||
struct qlink_tlv_hdr hdr;
|
||||
u8 rlimit;
|
||||
} __packed;
|
||||
|
||||
struct qlink_tlv_cclass {
|
||||
struct qlink_tlv_hdr hdr;
|
||||
u8 cclass;
|
||||
} __packed;
|
||||
|
||||
enum qlink_dfs_state {
|
||||
QLINK_DFS_USABLE,
|
||||
QLINK_DFS_UNAVAILABLE,
|
||||
QLINK_DFS_AVAILABLE,
|
||||
};
|
||||
|
||||
enum qlink_channel_flags {
|
||||
QLINK_CHAN_DISABLED = BIT(0),
|
||||
QLINK_CHAN_NO_IR = BIT(1),
|
||||
QLINK_CHAN_RADAR = BIT(3),
|
||||
QLINK_CHAN_NO_HT40PLUS = BIT(4),
|
||||
QLINK_CHAN_NO_HT40MINUS = BIT(5),
|
||||
QLINK_CHAN_NO_OFDM = BIT(6),
|
||||
QLINK_CHAN_NO_80MHZ = BIT(7),
|
||||
QLINK_CHAN_NO_160MHZ = BIT(8),
|
||||
QLINK_CHAN_INDOOR_ONLY = BIT(9),
|
||||
QLINK_CHAN_IR_CONCURRENT = BIT(10),
|
||||
QLINK_CHAN_NO_20MHZ = BIT(11),
|
||||
QLINK_CHAN_NO_10MHZ = BIT(12),
|
||||
};
|
||||
|
||||
struct qlink_tlv_channel {
|
||||
struct qlink_tlv_hdr hdr;
|
||||
__le16 hw_value;
|
||||
__le16 center_freq;
|
||||
__le32 flags;
|
||||
u8 band;
|
||||
u8 max_antenna_gain;
|
||||
u8 max_power;
|
||||
u8 max_reg_power;
|
||||
__le32 dfs_cac_ms;
|
||||
u8 dfs_state;
|
||||
u8 beacon_found;
|
||||
u8 rsvd[2];
|
||||
} __packed;
|
||||
|
||||
#define QLINK_MAX_NR_CIPHER_SUITES 5
|
||||
#define QLINK_MAX_NR_AKM_SUITES 2
|
||||
|
||||
struct qlink_auth_encr {
|
||||
__le32 wpa_versions;
|
||||
__le32 cipher_group;
|
||||
__le32 n_ciphers_pairwise;
|
||||
__le32 ciphers_pairwise[QLINK_MAX_NR_CIPHER_SUITES];
|
||||
__le32 n_akm_suites;
|
||||
__le32 akm_suites[QLINK_MAX_NR_AKM_SUITES];
|
||||
__le16 control_port_ethertype;
|
||||
u8 auth_type;
|
||||
u8 privacy;
|
||||
u8 mfp;
|
||||
u8 control_port;
|
||||
u8 control_port_no_encrypt;
|
||||
} __packed;
|
||||
|
||||
#endif /* _QTN_QLINK_H_ */
|
71
drivers/net/wireless/quantenna/qtnfmac/qlink_util.c
Normal file
71
drivers/net/wireless/quantenna/qtnfmac/qlink_util.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include "qlink_util.h"
|
||||
|
||||
u16 qlink_iface_type_mask_to_nl(u16 qlink_mask)
|
||||
{
|
||||
u16 result = 0;
|
||||
|
||||
if (qlink_mask & QLINK_IFTYPE_AP)
|
||||
result |= BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
if (qlink_mask & QLINK_IFTYPE_STATION)
|
||||
result |= BIT(NL80211_IFTYPE_STATION);
|
||||
|
||||
if (qlink_mask & QLINK_IFTYPE_ADHOC)
|
||||
result |= BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
if (qlink_mask & QLINK_IFTYPE_MONITOR)
|
||||
result |= BIT(NL80211_IFTYPE_MONITOR);
|
||||
|
||||
if (qlink_mask & QLINK_IFTYPE_WDS)
|
||||
result |= BIT(NL80211_IFTYPE_WDS);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u8 qlink_chan_width_mask_to_nl(u16 qlink_mask)
|
||||
{
|
||||
u8 result = 0;
|
||||
|
||||
if (qlink_mask & QLINK_CHAN_WIDTH_5)
|
||||
result |= BIT(NL80211_CHAN_WIDTH_5);
|
||||
|
||||
if (qlink_mask & QLINK_CHAN_WIDTH_10)
|
||||
result |= BIT(NL80211_CHAN_WIDTH_10);
|
||||
|
||||
if (qlink_mask & QLINK_CHAN_WIDTH_20_NOHT)
|
||||
result |= BIT(NL80211_CHAN_WIDTH_20_NOHT);
|
||||
|
||||
if (qlink_mask & QLINK_CHAN_WIDTH_20)
|
||||
result |= BIT(NL80211_CHAN_WIDTH_20);
|
||||
|
||||
if (qlink_mask & QLINK_CHAN_WIDTH_40)
|
||||
result |= BIT(NL80211_CHAN_WIDTH_40);
|
||||
|
||||
if (qlink_mask & QLINK_CHAN_WIDTH_80)
|
||||
result |= BIT(NL80211_CHAN_WIDTH_80);
|
||||
|
||||
if (qlink_mask & QLINK_CHAN_WIDTH_80P80)
|
||||
result |= BIT(NL80211_CHAN_WIDTH_80P80);
|
||||
|
||||
if (qlink_mask & QLINK_CHAN_WIDTH_160)
|
||||
result |= BIT(NL80211_CHAN_WIDTH_160);
|
||||
|
||||
return result;
|
||||
}
|
80
drivers/net/wireless/quantenna/qtnfmac/qlink_util.h
Normal file
80
drivers/net/wireless/quantenna/qtnfmac/qlink_util.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_FMAC_QLINK_UTIL_H_
|
||||
#define _QTN_FMAC_QLINK_UTIL_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include "qlink.h"
|
||||
|
||||
static inline void qtnf_cmd_skb_put_action(struct sk_buff *skb, u16 action)
|
||||
{
|
||||
__le16 *buf_ptr;
|
||||
|
||||
buf_ptr = (__le16 *)skb_put(skb, sizeof(action));
|
||||
*buf_ptr = cpu_to_le16(action);
|
||||
}
|
||||
|
||||
static inline void
|
||||
qtnf_cmd_skb_put_buffer(struct sk_buff *skb, const u8 *buf_src, size_t len)
|
||||
{
|
||||
u8 *buf_dst;
|
||||
|
||||
buf_dst = skb_put(skb, len);
|
||||
memcpy(buf_dst, buf_src, len);
|
||||
}
|
||||
|
||||
static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb,
|
||||
u16 tlv_id, const u8 arr[],
|
||||
size_t arr_len)
|
||||
{
|
||||
struct qlink_tlv_hdr *hdr =
|
||||
(void *)skb_put(skb, sizeof(*hdr) + arr_len);
|
||||
|
||||
hdr->type = cpu_to_le16(tlv_id);
|
||||
hdr->len = cpu_to_le16(arr_len);
|
||||
memcpy(hdr->val, arr, arr_len);
|
||||
}
|
||||
|
||||
static inline void qtnf_cmd_skb_put_tlv_u8(struct sk_buff *skb, u16 tlv_id,
|
||||
u8 value)
|
||||
{
|
||||
struct qlink_tlv_hdr *hdr =
|
||||
(void *)skb_put(skb, sizeof(*hdr) + sizeof(value));
|
||||
|
||||
hdr->type = cpu_to_le16(tlv_id);
|
||||
hdr->len = cpu_to_le16(sizeof(value));
|
||||
*hdr->val = value;
|
||||
}
|
||||
|
||||
static inline void qtnf_cmd_skb_put_tlv_u16(struct sk_buff *skb,
|
||||
u16 tlv_id, u16 value)
|
||||
{
|
||||
struct qlink_tlv_hdr *hdr =
|
||||
(void *)skb_put(skb, sizeof(*hdr) + sizeof(value));
|
||||
__le16 tmp = cpu_to_le16(value);
|
||||
|
||||
hdr->type = cpu_to_le16(tlv_id);
|
||||
hdr->len = cpu_to_le16(sizeof(value));
|
||||
memcpy(hdr->val, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
u16 qlink_iface_type_mask_to_nl(u16 qlink_mask);
|
||||
u8 qlink_chan_width_mask_to_nl(u16 qlink_mask);
|
||||
|
||||
#endif /* _QTN_FMAC_QLINK_UTIL_H_ */
|
32
drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h
Normal file
32
drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_HW_IDS_H_
|
||||
#define _QTN_HW_IDS_H_
|
||||
|
||||
#include <linux/pci_ids.h>
|
||||
|
||||
#define PCIE_VENDOR_ID_QUANTENNA (0x1bb5)
|
||||
|
||||
/* PCIE Device IDs */
|
||||
|
||||
#define PCIE_DEVICE_ID_QTN_PEARL (0x0008)
|
||||
|
||||
/* FW names */
|
||||
|
||||
#define QTN_PCI_PEARL_FW_NAME "qtn/fmac_qsr10g.img"
|
||||
|
||||
#endif /* _QTN_HW_IDS_H_ */
|
176
drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c
Normal file
176
drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "shm_ipc.h"
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "qtnfmac shm_ipc: %s: " fmt, __func__
|
||||
|
||||
static bool qtnf_shm_ipc_has_new_data(struct qtnf_shm_ipc *ipc)
|
||||
{
|
||||
const u32 flags = readl(&ipc->shm_region->headroom.hdr.flags);
|
||||
|
||||
return (flags & QTNF_SHM_IPC_NEW_DATA);
|
||||
}
|
||||
|
||||
static void qtnf_shm_handle_new_data(struct qtnf_shm_ipc *ipc)
|
||||
{
|
||||
size_t size;
|
||||
bool rx_buff_ok = true;
|
||||
struct qtnf_shm_ipc_region_header __iomem *shm_reg_hdr;
|
||||
|
||||
shm_reg_hdr = &ipc->shm_region->headroom.hdr;
|
||||
|
||||
size = readw(&shm_reg_hdr->data_len);
|
||||
|
||||
if (unlikely(size == 0 || size > QTN_IPC_MAX_DATA_SZ)) {
|
||||
pr_err("wrong rx packet size: %zu\n", size);
|
||||
rx_buff_ok = false;
|
||||
} else {
|
||||
memcpy_fromio(ipc->rx_data, ipc->shm_region->data, size);
|
||||
}
|
||||
|
||||
writel(QTNF_SHM_IPC_ACK, &shm_reg_hdr->flags);
|
||||
readl(&shm_reg_hdr->flags); /* flush PCIe write */
|
||||
|
||||
ipc->interrupt.fn(ipc->interrupt.arg);
|
||||
|
||||
if (likely(rx_buff_ok)) {
|
||||
ipc->rx_packet_count++;
|
||||
ipc->rx_callback.fn(ipc->rx_callback.arg, ipc->rx_data, size);
|
||||
}
|
||||
}
|
||||
|
||||
static void qtnf_shm_ipc_irq_work(struct work_struct *work)
|
||||
{
|
||||
struct qtnf_shm_ipc *ipc = container_of(work, struct qtnf_shm_ipc,
|
||||
irq_work);
|
||||
|
||||
while (qtnf_shm_ipc_has_new_data(ipc))
|
||||
qtnf_shm_handle_new_data(ipc);
|
||||
}
|
||||
|
||||
static void qtnf_shm_ipc_irq_inbound_handler(struct qtnf_shm_ipc *ipc)
|
||||
{
|
||||
u32 flags;
|
||||
|
||||
flags = readl(&ipc->shm_region->headroom.hdr.flags);
|
||||
|
||||
if (flags & QTNF_SHM_IPC_NEW_DATA)
|
||||
queue_work(ipc->workqueue, &ipc->irq_work);
|
||||
}
|
||||
|
||||
static void qtnf_shm_ipc_irq_outbound_handler(struct qtnf_shm_ipc *ipc)
|
||||
{
|
||||
u32 flags;
|
||||
|
||||
if (!READ_ONCE(ipc->waiting_for_ack))
|
||||
return;
|
||||
|
||||
flags = readl(&ipc->shm_region->headroom.hdr.flags);
|
||||
|
||||
if (flags & QTNF_SHM_IPC_ACK) {
|
||||
WRITE_ONCE(ipc->waiting_for_ack, 0);
|
||||
complete(&ipc->tx_completion);
|
||||
}
|
||||
}
|
||||
|
||||
int qtnf_shm_ipc_init(struct qtnf_shm_ipc *ipc,
|
||||
enum qtnf_shm_ipc_direction direction,
|
||||
struct qtnf_shm_ipc_region __iomem *shm_region,
|
||||
struct workqueue_struct *workqueue,
|
||||
const struct qtnf_shm_ipc_int *interrupt,
|
||||
const struct qtnf_shm_ipc_rx_callback *rx_callback)
|
||||
{
|
||||
BUILD_BUG_ON(offsetof(struct qtnf_shm_ipc_region, data) !=
|
||||
QTN_IPC_REG_HDR_SZ);
|
||||
BUILD_BUG_ON(sizeof(struct qtnf_shm_ipc_region) > QTN_IPC_REG_SZ);
|
||||
|
||||
ipc->shm_region = shm_region;
|
||||
ipc->direction = direction;
|
||||
ipc->interrupt = *interrupt;
|
||||
ipc->rx_callback = *rx_callback;
|
||||
ipc->tx_packet_count = 0;
|
||||
ipc->rx_packet_count = 0;
|
||||
ipc->workqueue = workqueue;
|
||||
ipc->waiting_for_ack = 0;
|
||||
ipc->tx_timeout_count = 0;
|
||||
|
||||
switch (direction) {
|
||||
case QTNF_SHM_IPC_OUTBOUND:
|
||||
ipc->irq_handler = qtnf_shm_ipc_irq_outbound_handler;
|
||||
break;
|
||||
case QTNF_SHM_IPC_INBOUND:
|
||||
ipc->irq_handler = qtnf_shm_ipc_irq_inbound_handler;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
INIT_WORK(&ipc->irq_work, qtnf_shm_ipc_irq_work);
|
||||
init_completion(&ipc->tx_completion);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qtnf_shm_ipc_free(struct qtnf_shm_ipc *ipc)
|
||||
{
|
||||
complete_all(&ipc->tx_completion);
|
||||
}
|
||||
|
||||
int qtnf_shm_ipc_send(struct qtnf_shm_ipc *ipc, const u8 *buf, size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct qtnf_shm_ipc_region_header __iomem *shm_reg_hdr;
|
||||
|
||||
shm_reg_hdr = &ipc->shm_region->headroom.hdr;
|
||||
|
||||
if (unlikely(size > QTN_IPC_MAX_DATA_SZ))
|
||||
return -E2BIG;
|
||||
|
||||
ipc->tx_packet_count++;
|
||||
|
||||
writew(size, &shm_reg_hdr->data_len);
|
||||
memcpy_toio(ipc->shm_region->data, buf, size);
|
||||
|
||||
/* sync previous writes before proceeding */
|
||||
dma_wmb();
|
||||
|
||||
WRITE_ONCE(ipc->waiting_for_ack, 1);
|
||||
|
||||
/* sync previous memory write before announcing new data ready */
|
||||
wmb();
|
||||
|
||||
writel(QTNF_SHM_IPC_NEW_DATA, &shm_reg_hdr->flags);
|
||||
readl(&shm_reg_hdr->flags); /* flush PCIe write */
|
||||
|
||||
ipc->interrupt.fn(ipc->interrupt.arg);
|
||||
|
||||
if (!wait_for_completion_timeout(&ipc->tx_completion,
|
||||
QTN_SHM_IPC_ACK_TIMEOUT)) {
|
||||
ret = -ETIMEDOUT;
|
||||
ipc->tx_timeout_count++;
|
||||
pr_err("TX ACK timeout\n");
|
||||
}
|
||||
|
||||
/* now we're not waiting for ACK even in case of timeout */
|
||||
WRITE_ONCE(ipc->waiting_for_ack, 0);
|
||||
|
||||
return ret;
|
||||
}
|
80
drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h
Normal file
80
drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_FMAC_SHM_IPC_H_
|
||||
#define _QTN_FMAC_SHM_IPC_H_
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "shm_ipc_defs.h"
|
||||
|
||||
#define QTN_SHM_IPC_ACK_TIMEOUT (2 * HZ)
|
||||
|
||||
struct qtnf_shm_ipc_int {
|
||||
void (*fn)(void *arg);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
struct qtnf_shm_ipc_rx_callback {
|
||||
void (*fn)(void *arg, const u8 *buf, size_t len);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
enum qtnf_shm_ipc_direction {
|
||||
QTNF_SHM_IPC_OUTBOUND = BIT(0),
|
||||
QTNF_SHM_IPC_INBOUND = BIT(1),
|
||||
};
|
||||
|
||||
struct qtnf_shm_ipc {
|
||||
struct qtnf_shm_ipc_region __iomem *shm_region;
|
||||
enum qtnf_shm_ipc_direction direction;
|
||||
size_t tx_packet_count;
|
||||
size_t rx_packet_count;
|
||||
|
||||
size_t tx_timeout_count;
|
||||
|
||||
u8 waiting_for_ack;
|
||||
|
||||
u8 rx_data[QTN_IPC_MAX_DATA_SZ] __aligned(sizeof(u32));
|
||||
|
||||
struct qtnf_shm_ipc_int interrupt;
|
||||
struct qtnf_shm_ipc_rx_callback rx_callback;
|
||||
|
||||
void (*irq_handler)(struct qtnf_shm_ipc *ipc);
|
||||
|
||||
struct workqueue_struct *workqueue;
|
||||
struct work_struct irq_work;
|
||||
struct completion tx_completion;
|
||||
};
|
||||
|
||||
int qtnf_shm_ipc_init(struct qtnf_shm_ipc *ipc,
|
||||
enum qtnf_shm_ipc_direction direction,
|
||||
struct qtnf_shm_ipc_region __iomem *shm_region,
|
||||
struct workqueue_struct *workqueue,
|
||||
const struct qtnf_shm_ipc_int *interrupt,
|
||||
const struct qtnf_shm_ipc_rx_callback *rx_callback);
|
||||
void qtnf_shm_ipc_free(struct qtnf_shm_ipc *ipc);
|
||||
int qtnf_shm_ipc_send(struct qtnf_shm_ipc *ipc, const u8 *buf, size_t size);
|
||||
|
||||
static inline void qtnf_shm_ipc_irq_handler(struct qtnf_shm_ipc *ipc)
|
||||
{
|
||||
ipc->irq_handler(ipc);
|
||||
}
|
||||
|
||||
#endif /* _QTN_FMAC_SHM_IPC_H_ */
|
46
drivers/net/wireless/quantenna/qtnfmac/shm_ipc_defs.h
Normal file
46
drivers/net/wireless/quantenna/qtnfmac/shm_ipc_defs.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Quantenna Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _QTN_FMAC_SHM_IPC_DEFS_H_
|
||||
#define _QTN_FMAC_SHM_IPC_DEFS_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define QTN_IPC_REG_HDR_SZ (32)
|
||||
#define QTN_IPC_REG_SZ (4096)
|
||||
#define QTN_IPC_MAX_DATA_SZ (QTN_IPC_REG_SZ - QTN_IPC_REG_HDR_SZ)
|
||||
|
||||
enum qtnf_shm_ipc_region_flags {
|
||||
QTNF_SHM_IPC_NEW_DATA = BIT(0),
|
||||
QTNF_SHM_IPC_ACK = BIT(1),
|
||||
};
|
||||
|
||||
struct qtnf_shm_ipc_region_header {
|
||||
__le32 flags;
|
||||
__le16 data_len;
|
||||
} __packed;
|
||||
|
||||
union qtnf_shm_ipc_region_headroom {
|
||||
struct qtnf_shm_ipc_region_header hdr;
|
||||
u8 headroom[QTN_IPC_REG_HDR_SZ];
|
||||
} __packed;
|
||||
|
||||
struct qtnf_shm_ipc_region {
|
||||
union qtnf_shm_ipc_region_headroom headroom;
|
||||
u8 data[QTN_IPC_MAX_DATA_SZ];
|
||||
} __packed;
|
||||
|
||||
#endif /* _QTN_FMAC_SHM_IPC_DEFS_H_ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user