mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
John W. Linville says: ==================== pull request: wireless-next 2014-06-02 Please pull this remaining batch of updates intended for the 3.16 stream... For the mac80211 bits, Johannes says: "The remainder for -next right now is mostly fixes, and a handful of small new things like some CSA infrastructure, the regdb script mW/dBm conversion change and sending wiphy notifications." For the bluetooth bits, Gustavo says: "Some more patches for 3.16. There is nothing really special here, just a bunch of clean ups, fixes plus some small improvements. Please pull." For the nfc bits, Samuel says: "We have: - Felica (Type3) tags support for trf7970a - Type 4b tags support for port100 - st21nfca DTS typo fix - A few sparse warning fixes" For the atheros bits, Kalle says: "Ben added support for setting antenna configurations. Michal improved warm reset so that we would not need to fall back to cold reset that often, an issue where ath10k stripped protected flag while in monitor mode and made module initialisation asynchronous to fix the problems with firmware loading when the driver is linked to the kernel. Luca removed unused channel_switch_beacon callbacks both from ath9k and ath10k. Marek fixed Protected Management Frames (PMF) when using Action Frames. Also we had other small fixes everywhere in the driver." Along with that, there are a handful of updates to a variety of drivers. This includes updates to at76c50x-usb, ath9k, b43, brcmfmac, mwifiex, rsi, rtlwifi, and wil6210. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
* STMicroelectronics SAS. ST21NFCA NFC Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "st,st21nfca-i2c".
|
||||
- compatible: Should be "st,st21nfca_i2c".
|
||||
- clock-frequency: I²C work frequency.
|
||||
- reg: address on the bus
|
||||
- interrupt-parent: phandle for the interrupt gpio controller
|
||||
|
||||
@@ -49,6 +49,7 @@ static struct usb_driver btusb_driver;
|
||||
#define BTUSB_WRONG_SCO_MTU 0x40
|
||||
#define BTUSB_ATH3012 0x80
|
||||
#define BTUSB_INTEL 0x100
|
||||
#define BTUSB_BCM_PATCHRAM 0x200
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
@@ -111,7 +112,8 @@ static const struct usb_device_id btusb_table[] = {
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
|
||||
|
||||
/* Broadcom devices with vendor specific id */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01),
|
||||
.driver_info = BTUSB_BCM_PATCHRAM },
|
||||
|
||||
/* Belkin F8065bf - Broadcom based */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
|
||||
@@ -1381,6 +1383,154 @@ exit_mfg_deactivate:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct usb_device *udev = data->udev;
|
||||
char fw_name[64];
|
||||
const struct firmware *fw;
|
||||
const u8 *fw_ptr;
|
||||
size_t fw_size;
|
||||
const struct hci_command_hdr *cmd;
|
||||
const u8 *cmd_param;
|
||||
u16 opcode;
|
||||
struct sk_buff *skb;
|
||||
struct hci_rp_read_local_version *ver;
|
||||
long ret;
|
||||
|
||||
snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd",
|
||||
udev->product ? udev->product : "BCM",
|
||||
le16_to_cpu(udev->descriptor.idVendor),
|
||||
le16_to_cpu(udev->descriptor.idProduct));
|
||||
|
||||
ret = request_firmware(&fw, fw_name, &hdev->dev);
|
||||
if (ret < 0) {
|
||||
BT_INFO("%s: BCM: patch %s not found", hdev->name,
|
||||
fw_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret);
|
||||
goto done;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
/* Read Local Version Info */
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
|
||||
hdev->name, ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (skb->len != sizeof(*ver)) {
|
||||
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
|
||||
hdev->name);
|
||||
kfree_skb(skb);
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ver = (struct hci_rp_read_local_version *) skb->data;
|
||||
BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
|
||||
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
|
||||
ver->lmp_ver, ver->lmp_subver);
|
||||
kfree_skb(skb);
|
||||
|
||||
/* Start Download */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: BCM: Download Minidrv command failed (%ld)",
|
||||
hdev->name, ret);
|
||||
goto reset_fw;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
/* 50 msec delay after Download Minidrv completes */
|
||||
msleep(50);
|
||||
|
||||
fw_ptr = fw->data;
|
||||
fw_size = fw->size;
|
||||
|
||||
while (fw_size >= sizeof(*cmd)) {
|
||||
cmd = (struct hci_command_hdr *) fw_ptr;
|
||||
fw_ptr += sizeof(*cmd);
|
||||
fw_size -= sizeof(*cmd);
|
||||
|
||||
if (fw_size < cmd->plen) {
|
||||
BT_ERR("%s: BCM: patch %s is corrupted",
|
||||
hdev->name, fw_name);
|
||||
ret = -EINVAL;
|
||||
goto reset_fw;
|
||||
}
|
||||
|
||||
cmd_param = fw_ptr;
|
||||
fw_ptr += cmd->plen;
|
||||
fw_size -= cmd->plen;
|
||||
|
||||
opcode = le16_to_cpu(cmd->opcode);
|
||||
|
||||
skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: BCM: patch command %04x failed (%ld)",
|
||||
hdev->name, opcode, ret);
|
||||
goto reset_fw;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* 250 msec delay after Launch Ram completes */
|
||||
msleep(250);
|
||||
|
||||
reset_fw:
|
||||
/* Reset */
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret);
|
||||
goto done;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
/* Read Local Version Info */
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
|
||||
hdev->name, ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (skb->len != sizeof(*ver)) {
|
||||
BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
|
||||
hdev->name);
|
||||
kfree_skb(skb);
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ver = (struct hci_rp_read_local_version *) skb->data;
|
||||
BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
|
||||
"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
|
||||
ver->lmp_ver, ver->lmp_subver);
|
||||
kfree_skb(skb);
|
||||
|
||||
done:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
@@ -1486,6 +1636,9 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
if (id->driver_info & BTUSB_BCM92035)
|
||||
hdev->setup = btusb_setup_bcm92035;
|
||||
|
||||
if (id->driver_info & BTUSB_BCM_PATCHRAM)
|
||||
hdev->setup = btusb_setup_bcm_patchram;
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL)
|
||||
hdev->setup = btusb_setup_intel;
|
||||
|
||||
|
||||
@@ -365,15 +365,15 @@ static inline unsigned long at76_get_timeout(struct dfu_status *s)
|
||||
static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
|
||||
int manifest_sync_timeout)
|
||||
{
|
||||
u8 *block;
|
||||
struct dfu_status dfu_stat_buf;
|
||||
int ret = 0;
|
||||
int need_dfu_state = 1;
|
||||
int is_done = 0;
|
||||
u8 dfu_state = 0;
|
||||
u32 dfu_timeout = 0;
|
||||
int bsize = 0;
|
||||
int blockno = 0;
|
||||
struct dfu_status *dfu_stat_buf = NULL;
|
||||
u8 *dfu_state = NULL;
|
||||
u8 *block = NULL;
|
||||
|
||||
at76_dbg(DBG_DFU, "%s( %p, %u, %d)", __func__, buf, size,
|
||||
manifest_sync_timeout);
|
||||
@@ -383,13 +383,28 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dfu_stat_buf = kmalloc(sizeof(struct dfu_status), GFP_KERNEL);
|
||||
if (!dfu_stat_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);
|
||||
if (!block)
|
||||
return -ENOMEM;
|
||||
if (!block) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dfu_state = kmalloc(sizeof(u8), GFP_KERNEL);
|
||||
if (!dfu_state) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
*dfu_state = 0;
|
||||
|
||||
do {
|
||||
if (need_dfu_state) {
|
||||
ret = at76_dfu_get_state(udev, &dfu_state);
|
||||
ret = at76_dfu_get_state(udev, dfu_state);
|
||||
if (ret < 0) {
|
||||
dev_err(&udev->dev,
|
||||
"cannot get DFU state: %d\n", ret);
|
||||
@@ -398,13 +413,13 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
|
||||
need_dfu_state = 0;
|
||||
}
|
||||
|
||||
switch (dfu_state) {
|
||||
switch (*dfu_state) {
|
||||
case STATE_DFU_DOWNLOAD_SYNC:
|
||||
at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC");
|
||||
ret = at76_dfu_get_status(udev, &dfu_stat_buf);
|
||||
ret = at76_dfu_get_status(udev, dfu_stat_buf);
|
||||
if (ret >= 0) {
|
||||
dfu_state = dfu_stat_buf.state;
|
||||
dfu_timeout = at76_get_timeout(&dfu_stat_buf);
|
||||
*dfu_state = dfu_stat_buf->state;
|
||||
dfu_timeout = at76_get_timeout(dfu_stat_buf);
|
||||
need_dfu_state = 0;
|
||||
} else
|
||||
dev_err(&udev->dev,
|
||||
@@ -447,12 +462,12 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
|
||||
case STATE_DFU_MANIFEST_SYNC:
|
||||
at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC");
|
||||
|
||||
ret = at76_dfu_get_status(udev, &dfu_stat_buf);
|
||||
ret = at76_dfu_get_status(udev, dfu_stat_buf);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
dfu_state = dfu_stat_buf.state;
|
||||
dfu_timeout = at76_get_timeout(&dfu_stat_buf);
|
||||
*dfu_state = dfu_stat_buf->state;
|
||||
dfu_timeout = at76_get_timeout(dfu_stat_buf);
|
||||
need_dfu_state = 0;
|
||||
|
||||
/* override the timeout from the status response,
|
||||
@@ -484,14 +499,17 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
|
||||
break;
|
||||
|
||||
default:
|
||||
at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state);
|
||||
at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", *dfu_state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} while (!is_done && (ret >= 0));
|
||||
|
||||
exit:
|
||||
kfree(dfu_state);
|
||||
kfree(block);
|
||||
kfree(dfu_stat_buf);
|
||||
|
||||
if (ret >= 0)
|
||||
ret = 0;
|
||||
|
||||
@@ -1277,6 +1295,7 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
|
||||
dev_err(&udev->dev,
|
||||
"loading %dth firmware block failed: %d\n",
|
||||
blockno, ret);
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
buf += bsize;
|
||||
@@ -2020,6 +2039,44 @@ static void at76_configure_filter(struct ieee80211_hw *hw,
|
||||
ieee80211_queue_work(hw, &priv->work_set_promisc);
|
||||
}
|
||||
|
||||
static int at76_set_wep(struct at76_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mib_mac_wep *mib_data = &priv->mib_buf.data.wep_mib;
|
||||
|
||||
priv->mib_buf.type = MIB_MAC_WEP;
|
||||
priv->mib_buf.size = sizeof(struct mib_mac_wep);
|
||||
priv->mib_buf.index = 0;
|
||||
|
||||
memset(mib_data, 0, sizeof(*mib_data));
|
||||
|
||||
if (priv->wep_enabled) {
|
||||
if (priv->wep_keys_len[priv->wep_key_id] > WEP_SMALL_KEY_LEN)
|
||||
mib_data->encryption_level = 2;
|
||||
else
|
||||
mib_data->encryption_level = 1;
|
||||
|
||||
/* always exclude unencrypted if WEP is active */
|
||||
mib_data->exclude_unencrypted = 1;
|
||||
} else {
|
||||
mib_data->exclude_unencrypted = 0;
|
||||
mib_data->encryption_level = 0;
|
||||
}
|
||||
|
||||
mib_data->privacy_invoked = priv->wep_enabled;
|
||||
mib_data->wep_default_key_id = priv->wep_key_id;
|
||||
memcpy(mib_data->wep_default_keyvalue, priv->wep_keys,
|
||||
sizeof(priv->wep_keys));
|
||||
|
||||
ret = at76_set_mib(priv, &priv->mib_buf);
|
||||
|
||||
if (ret < 0)
|
||||
wiphy_err(priv->hw->wiphy,
|
||||
"set_mib (wep) failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
@@ -2062,7 +2119,7 @@ static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
priv->wep_enabled = 1;
|
||||
}
|
||||
|
||||
at76_startup_device(priv);
|
||||
at76_set_wep(priv);
|
||||
|
||||
mutex_unlock(&priv->mtx);
|
||||
|
||||
@@ -2330,16 +2387,22 @@ static int at76_probe(struct usb_interface *interface,
|
||||
struct usb_device *udev;
|
||||
int op_mode;
|
||||
int need_ext_fw = 0;
|
||||
struct mib_fw_version fwv;
|
||||
struct mib_fw_version *fwv = NULL;
|
||||
int board_type = (int)id->driver_info;
|
||||
|
||||
udev = usb_get_dev(interface_to_usbdev(interface));
|
||||
|
||||
fwv = kmalloc(sizeof(*fwv), GFP_KERNEL);
|
||||
if (!fwv) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Load firmware into kernel memory */
|
||||
fwe = at76_load_firmware(udev, board_type);
|
||||
if (!fwe) {
|
||||
ret = -ENOENT;
|
||||
goto error;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
op_mode = at76_get_op_mode(udev);
|
||||
@@ -2353,7 +2416,7 @@ static int at76_probe(struct usb_interface *interface,
|
||||
dev_err(&interface->dev,
|
||||
"cannot handle a device in HW_CONFIG_MODE\n");
|
||||
ret = -EBUSY;
|
||||
goto error;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH
|
||||
@@ -2366,10 +2429,10 @@ static int at76_probe(struct usb_interface *interface,
|
||||
dev_err(&interface->dev,
|
||||
"error %d downloading internal firmware\n",
|
||||
ret);
|
||||
goto error;
|
||||
goto exit;
|
||||
}
|
||||
usb_put_dev(udev);
|
||||
return ret;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Internal firmware already inside the device. Get firmware
|
||||
@@ -2382,8 +2445,8 @@ static int at76_probe(struct usb_interface *interface,
|
||||
* query the device for the fw version */
|
||||
if ((fwe->fw_version.major > 0 || fwe->fw_version.minor >= 100)
|
||||
|| (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) {
|
||||
ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
|
||||
if (ret < 0 || (fwv.major | fwv.minor) == 0)
|
||||
ret = at76_get_mib(udev, MIB_FW_VERSION, fwv, sizeof(*fwv));
|
||||
if (ret < 0 || (fwv->major | fwv->minor) == 0)
|
||||
need_ext_fw = 1;
|
||||
} else
|
||||
/* No way to check firmware version, reload to be sure */
|
||||
@@ -2394,37 +2457,37 @@ static int at76_probe(struct usb_interface *interface,
|
||||
"downloading external firmware\n");
|
||||
|
||||
ret = at76_load_external_fw(udev, fwe);
|
||||
if (ret)
|
||||
goto error;
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
/* Re-check firmware version */
|
||||
ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
|
||||
ret = at76_get_mib(udev, MIB_FW_VERSION, fwv, sizeof(*fwv));
|
||||
if (ret < 0) {
|
||||
dev_err(&interface->dev,
|
||||
"error %d getting firmware version\n", ret);
|
||||
goto error;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
priv = at76_alloc_new_device(udev);
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
usb_set_intfdata(interface, priv);
|
||||
|
||||
memcpy(&priv->fw_version, &fwv, sizeof(struct mib_fw_version));
|
||||
memcpy(&priv->fw_version, fwv, sizeof(struct mib_fw_version));
|
||||
priv->board_type = board_type;
|
||||
|
||||
ret = at76_init_new_device(priv, interface);
|
||||
if (ret < 0)
|
||||
at76_delete_device(priv);
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
usb_put_dev(udev);
|
||||
exit:
|
||||
kfree(fwv);
|
||||
if (ret < 0)
|
||||
usb_put_dev(udev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -219,18 +219,6 @@ struct at76_req_join {
|
||||
u8 reserved;
|
||||
} __packed;
|
||||
|
||||
struct set_mib_buffer {
|
||||
u8 type;
|
||||
u8 size;
|
||||
u8 index;
|
||||
u8 reserved;
|
||||
union {
|
||||
u8 byte;
|
||||
__le16 word;
|
||||
u8 addr[ETH_ALEN];
|
||||
} data;
|
||||
} __packed;
|
||||
|
||||
struct mib_local {
|
||||
u16 reserved0;
|
||||
u8 beacon_enable;
|
||||
@@ -334,6 +322,19 @@ struct mib_mdomain {
|
||||
u8 channel_list[14]; /* 0 for invalid channels */
|
||||
} __packed;
|
||||
|
||||
struct set_mib_buffer {
|
||||
u8 type;
|
||||
u8 size;
|
||||
u8 index;
|
||||
u8 reserved;
|
||||
union {
|
||||
u8 byte;
|
||||
__le16 word;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct mib_mac_wep wep_mib;
|
||||
} data;
|
||||
} __packed;
|
||||
|
||||
struct at76_fw_header {
|
||||
__le32 crc; /* CRC32 of the whole image */
|
||||
__le32 board_type; /* firmware compatibility code */
|
||||
|
||||
@@ -201,7 +201,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
|
||||
\
|
||||
addr = host_interest_item_address(HI_ITEM(item)); \
|
||||
ret = ath10k_bmi_read_memory(ar, addr, (u8 *)&tmp, 4); \
|
||||
*val = __le32_to_cpu(tmp); \
|
||||
if (!ret) \
|
||||
*val = __le32_to_cpu(tmp); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
|
||||
@@ -329,6 +329,33 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe)
|
||||
{
|
||||
struct ath10k *ar = pipe->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_ring *src_ring = pipe->src_ring;
|
||||
u32 ctrl_addr = pipe->ctrl_addr;
|
||||
|
||||
lockdep_assert_held(&ar_pci->ce_lock);
|
||||
|
||||
/*
|
||||
* This function must be called only if there is an incomplete
|
||||
* scatter-gather transfer (before index register is updated)
|
||||
* that needs to be cleaned up.
|
||||
*/
|
||||
if (WARN_ON_ONCE(src_ring->write_index == src_ring->sw_index))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(src_ring->write_index ==
|
||||
ath10k_ce_src_ring_write_index_get(ar, ctrl_addr)))
|
||||
return;
|
||||
|
||||
src_ring->write_index--;
|
||||
src_ring->write_index &= src_ring->nentries_mask;
|
||||
|
||||
src_ring->per_transfer_context[src_ring->write_index] = NULL;
|
||||
}
|
||||
|
||||
int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_context,
|
||||
u32 buffer,
|
||||
|
||||
@@ -160,6 +160,8 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
unsigned int transfer_id,
|
||||
unsigned int flags);
|
||||
|
||||
void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe);
|
||||
|
||||
void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
|
||||
void (*send_cb)(struct ath10k_ce_pipe *),
|
||||
int disable_interrupts);
|
||||
|
||||
@@ -58,36 +58,6 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
|
||||
complete(&ar->target_suspend);
|
||||
}
|
||||
|
||||
static int ath10k_init_connect_htc(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = ath10k_wmi_connect_htc_service(ar);
|
||||
if (status)
|
||||
goto conn_fail;
|
||||
|
||||
/* Start HTC */
|
||||
status = ath10k_htc_start(&ar->htc);
|
||||
if (status)
|
||||
goto conn_fail;
|
||||
|
||||
/* Wait for WMI event to be ready */
|
||||
status = ath10k_wmi_wait_for_service_ready(ar);
|
||||
if (status <= 0) {
|
||||
ath10k_warn("wmi service ready event not received");
|
||||
status = -ETIMEDOUT;
|
||||
goto timeout;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot wmi ready\n");
|
||||
return 0;
|
||||
|
||||
timeout:
|
||||
ath10k_htc_stop(&ar->htc);
|
||||
conn_fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath10k_init_configure_target(struct ath10k *ar)
|
||||
{
|
||||
u32 param_host;
|
||||
@@ -681,7 +651,8 @@ static void ath10k_core_restart(struct work_struct *work)
|
||||
switch (ar->state) {
|
||||
case ATH10K_STATE_ON:
|
||||
ar->state = ATH10K_STATE_RESTARTING;
|
||||
ath10k_halt(ar);
|
||||
del_timer_sync(&ar->scan.timeout);
|
||||
ath10k_reset_scan((unsigned long)ar);
|
||||
ieee80211_restart_hw(ar->hw);
|
||||
break;
|
||||
case ATH10K_STATE_OFF:
|
||||
@@ -690,6 +661,8 @@ static void ath10k_core_restart(struct work_struct *work)
|
||||
ath10k_warn("cannot restart a device that hasn't been started\n");
|
||||
break;
|
||||
case ATH10K_STATE_RESTARTING:
|
||||
/* hw restart might be requested from multiple places */
|
||||
break;
|
||||
case ATH10K_STATE_RESTARTED:
|
||||
ar->state = ATH10K_STATE_WEDGED;
|
||||
/* fall through */
|
||||
@@ -701,70 +674,6 @@ static void ath10k_core_restart(struct work_struct *work)
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
||||
|
||||
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
||||
const struct ath10k_hif_ops *hif_ops)
|
||||
{
|
||||
struct ath10k *ar;
|
||||
|
||||
ar = ath10k_mac_create();
|
||||
if (!ar)
|
||||
return NULL;
|
||||
|
||||
ar->ath_common.priv = ar;
|
||||
ar->ath_common.hw = ar->hw;
|
||||
|
||||
ar->p2p = !!ath10k_p2p;
|
||||
ar->dev = dev;
|
||||
|
||||
ar->hif.priv = hif_priv;
|
||||
ar->hif.ops = hif_ops;
|
||||
|
||||
init_completion(&ar->scan.started);
|
||||
init_completion(&ar->scan.completed);
|
||||
init_completion(&ar->scan.on_channel);
|
||||
init_completion(&ar->target_suspend);
|
||||
|
||||
init_completion(&ar->install_key_done);
|
||||
init_completion(&ar->vdev_setup_done);
|
||||
|
||||
setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
|
||||
|
||||
ar->workqueue = create_singlethread_workqueue("ath10k_wq");
|
||||
if (!ar->workqueue)
|
||||
goto err_wq;
|
||||
|
||||
mutex_init(&ar->conf_mutex);
|
||||
spin_lock_init(&ar->data_lock);
|
||||
|
||||
INIT_LIST_HEAD(&ar->peers);
|
||||
init_waitqueue_head(&ar->peer_mapping_wq);
|
||||
|
||||
init_completion(&ar->offchan_tx_completed);
|
||||
INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
|
||||
skb_queue_head_init(&ar->offchan_tx_queue);
|
||||
|
||||
INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
|
||||
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
|
||||
|
||||
INIT_WORK(&ar->restart_work, ath10k_core_restart);
|
||||
|
||||
return ar;
|
||||
|
||||
err_wq:
|
||||
ath10k_mac_destroy(ar);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_create);
|
||||
|
||||
void ath10k_core_destroy(struct ath10k *ar)
|
||||
{
|
||||
flush_workqueue(ar->workqueue);
|
||||
destroy_workqueue(ar->workqueue);
|
||||
|
||||
ath10k_mac_destroy(ar);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_destroy);
|
||||
|
||||
int ath10k_core_start(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
@@ -805,10 +714,28 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = ath10k_htt_init(ar);
|
||||
if (status) {
|
||||
ath10k_err("failed to init htt: %d\n", status);
|
||||
goto err_wmi_detach;
|
||||
}
|
||||
|
||||
status = ath10k_htt_tx_alloc(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err("failed to alloc htt tx: %d\n", status);
|
||||
goto err_wmi_detach;
|
||||
}
|
||||
|
||||
status = ath10k_htt_rx_alloc(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err("failed to alloc htt rx: %d\n", status);
|
||||
goto err_htt_tx_detach;
|
||||
}
|
||||
|
||||
status = ath10k_hif_start(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not start HIF: %d\n", status);
|
||||
goto err_wmi_detach;
|
||||
goto err_htt_rx_detach;
|
||||
}
|
||||
|
||||
status = ath10k_htc_wait_target(&ar->htc);
|
||||
@@ -817,15 +744,30 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
status = ath10k_htt_attach(ar);
|
||||
status = ath10k_htt_connect(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err("could not attach htt (%d)\n", status);
|
||||
ath10k_err("failed to connect htt (%d)\n", status);
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
status = ath10k_init_connect_htc(ar);
|
||||
if (status)
|
||||
goto err_htt_detach;
|
||||
status = ath10k_wmi_connect(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not connect wmi: %d\n", status);
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
status = ath10k_htc_start(&ar->htc);
|
||||
if (status) {
|
||||
ath10k_err("failed to start htc: %d\n", status);
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
status = ath10k_wmi_wait_for_service_ready(ar);
|
||||
if (status <= 0) {
|
||||
ath10k_warn("wmi service ready event not received");
|
||||
status = -ETIMEDOUT;
|
||||
goto err_htc_stop;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n",
|
||||
ar->hw->wiphy->fw_version);
|
||||
@@ -833,23 +775,25 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
status = ath10k_wmi_cmd_init(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not send WMI init command (%d)\n", status);
|
||||
goto err_disconnect_htc;
|
||||
goto err_htc_stop;
|
||||
}
|
||||
|
||||
status = ath10k_wmi_wait_for_unified_ready(ar);
|
||||
if (status <= 0) {
|
||||
ath10k_err("wmi unified ready event not received\n");
|
||||
status = -ETIMEDOUT;
|
||||
goto err_disconnect_htc;
|
||||
goto err_htc_stop;
|
||||
}
|
||||
|
||||
status = ath10k_htt_attach_target(&ar->htt);
|
||||
if (status)
|
||||
goto err_disconnect_htc;
|
||||
status = ath10k_htt_setup(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err("failed to setup htt: %d\n", status);
|
||||
goto err_htc_stop;
|
||||
}
|
||||
|
||||
status = ath10k_debug_start(ar);
|
||||
if (status)
|
||||
goto err_disconnect_htc;
|
||||
goto err_htc_stop;
|
||||
|
||||
ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
|
||||
INIT_LIST_HEAD(&ar->arvifs);
|
||||
@@ -868,12 +812,14 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
|
||||
return 0;
|
||||
|
||||
err_disconnect_htc:
|
||||
err_htc_stop:
|
||||
ath10k_htc_stop(&ar->htc);
|
||||
err_htt_detach:
|
||||
ath10k_htt_detach(&ar->htt);
|
||||
err_hif_stop:
|
||||
ath10k_hif_stop(ar);
|
||||
err_htt_rx_detach:
|
||||
ath10k_htt_rx_free(&ar->htt);
|
||||
err_htt_tx_detach:
|
||||
ath10k_htt_tx_free(&ar->htt);
|
||||
err_wmi_detach:
|
||||
ath10k_wmi_detach(ar);
|
||||
err:
|
||||
@@ -913,7 +859,9 @@ void ath10k_core_stop(struct ath10k *ar)
|
||||
|
||||
ath10k_debug_stop(ar);
|
||||
ath10k_htc_stop(&ar->htc);
|
||||
ath10k_htt_detach(&ar->htt);
|
||||
ath10k_hif_stop(ar);
|
||||
ath10k_htt_tx_free(&ar->htt);
|
||||
ath10k_htt_rx_free(&ar->htt);
|
||||
ath10k_wmi_detach(ar);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_stop);
|
||||
@@ -1005,22 +953,15 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_core_register(struct ath10k *ar, u32 chip_id)
|
||||
static void ath10k_core_register_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k *ar = container_of(work, struct ath10k, register_work);
|
||||
int status;
|
||||
|
||||
ar->chip_id = chip_id;
|
||||
|
||||
status = ath10k_core_check_chip_id(ar);
|
||||
if (status) {
|
||||
ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = ath10k_core_probe_fw(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not probe fw (%d)\n", status);
|
||||
return status;
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = ath10k_mac_register(ar);
|
||||
@@ -1035,18 +976,43 @@ int ath10k_core_register(struct ath10k *ar, u32 chip_id)
|
||||
goto err_unregister_mac;
|
||||
}
|
||||
|
||||
return 0;
|
||||
set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);
|
||||
return;
|
||||
|
||||
err_unregister_mac:
|
||||
ath10k_mac_unregister(ar);
|
||||
err_release_fw:
|
||||
ath10k_core_free_firmware_files(ar);
|
||||
return status;
|
||||
err:
|
||||
device_release_driver(ar->dev);
|
||||
return;
|
||||
}
|
||||
|
||||
int ath10k_core_register(struct ath10k *ar, u32 chip_id)
|
||||
{
|
||||
int status;
|
||||
|
||||
ar->chip_id = chip_id;
|
||||
|
||||
status = ath10k_core_check_chip_id(ar);
|
||||
if (status) {
|
||||
ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
|
||||
return status;
|
||||
}
|
||||
|
||||
queue_work(ar->workqueue, &ar->register_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_register);
|
||||
|
||||
void ath10k_core_unregister(struct ath10k *ar)
|
||||
{
|
||||
cancel_work_sync(&ar->register_work);
|
||||
|
||||
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
|
||||
return;
|
||||
|
||||
/* We must unregister from mac80211 before we stop HTC and HIF.
|
||||
* Otherwise we will fail to submit commands to FW and mac80211 will be
|
||||
* unhappy about callback failures. */
|
||||
@@ -1058,6 +1024,71 @@ void ath10k_core_unregister(struct ath10k *ar)
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_unregister);
|
||||
|
||||
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
||||
const struct ath10k_hif_ops *hif_ops)
|
||||
{
|
||||
struct ath10k *ar;
|
||||
|
||||
ar = ath10k_mac_create();
|
||||
if (!ar)
|
||||
return NULL;
|
||||
|
||||
ar->ath_common.priv = ar;
|
||||
ar->ath_common.hw = ar->hw;
|
||||
|
||||
ar->p2p = !!ath10k_p2p;
|
||||
ar->dev = dev;
|
||||
|
||||
ar->hif.priv = hif_priv;
|
||||
ar->hif.ops = hif_ops;
|
||||
|
||||
init_completion(&ar->scan.started);
|
||||
init_completion(&ar->scan.completed);
|
||||
init_completion(&ar->scan.on_channel);
|
||||
init_completion(&ar->target_suspend);
|
||||
|
||||
init_completion(&ar->install_key_done);
|
||||
init_completion(&ar->vdev_setup_done);
|
||||
|
||||
setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
|
||||
|
||||
ar->workqueue = create_singlethread_workqueue("ath10k_wq");
|
||||
if (!ar->workqueue)
|
||||
goto err_wq;
|
||||
|
||||
mutex_init(&ar->conf_mutex);
|
||||
spin_lock_init(&ar->data_lock);
|
||||
|
||||
INIT_LIST_HEAD(&ar->peers);
|
||||
init_waitqueue_head(&ar->peer_mapping_wq);
|
||||
|
||||
init_completion(&ar->offchan_tx_completed);
|
||||
INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
|
||||
skb_queue_head_init(&ar->offchan_tx_queue);
|
||||
|
||||
INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
|
||||
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
|
||||
|
||||
INIT_WORK(&ar->register_work, ath10k_core_register_work);
|
||||
INIT_WORK(&ar->restart_work, ath10k_core_restart);
|
||||
|
||||
return ar;
|
||||
|
||||
err_wq:
|
||||
ath10k_mac_destroy(ar);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_create);
|
||||
|
||||
void ath10k_core_destroy(struct ath10k *ar)
|
||||
{
|
||||
flush_workqueue(ar->workqueue);
|
||||
destroy_workqueue(ar->workqueue);
|
||||
|
||||
ath10k_mac_destroy(ar);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_destroy);
|
||||
|
||||
MODULE_AUTHOR("Qualcomm Atheros");
|
||||
MODULE_DESCRIPTION("Core module for QCA988X PCIe devices.");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
@@ -335,6 +335,7 @@ enum ath10k_dev_flags {
|
||||
/* Indicates that ath10k device is during CAC phase of DFS */
|
||||
ATH10K_CAC_RUNNING,
|
||||
ATH10K_FLAG_FIRST_BOOT_DONE,
|
||||
ATH10K_FLAG_CORE_REGISTERED,
|
||||
};
|
||||
|
||||
struct ath10k {
|
||||
@@ -440,6 +441,12 @@ struct ath10k {
|
||||
bool radar_enabled;
|
||||
int num_started_vdevs;
|
||||
|
||||
/* Protected by conf-mutex */
|
||||
u8 supp_tx_chainmask;
|
||||
u8 supp_rx_chainmask;
|
||||
u8 cfg_tx_chainmask;
|
||||
u8 cfg_rx_chainmask;
|
||||
|
||||
struct wmi_pdev_set_wmm_params_arg wmm_params;
|
||||
struct completion install_key_done;
|
||||
|
||||
@@ -470,6 +477,7 @@ struct ath10k {
|
||||
|
||||
enum ath10k_state state;
|
||||
|
||||
struct work_struct register_work;
|
||||
struct work_struct restart_work;
|
||||
|
||||
/* cycle count is reported twice for each visited channel during scan.
|
||||
|
||||
@@ -830,17 +830,11 @@ int ath10k_htc_start(struct ath10k_htc *htc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* stop HTC communications, i.e. stop interrupt reception, and flush all
|
||||
* queued buffers
|
||||
*/
|
||||
void ath10k_htc_stop(struct ath10k_htc *htc)
|
||||
{
|
||||
spin_lock_bh(&htc->tx_lock);
|
||||
htc->stopped = true;
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
|
||||
ath10k_hif_stop(htc->ar);
|
||||
}
|
||||
|
||||
/* registered target arrival callback from the HIF layer */
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
|
||||
int ath10k_htt_connect(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
struct ath10k_htc_svc_conn_resp conn_resp;
|
||||
@@ -48,38 +48,13 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_attach(struct ath10k *ar)
|
||||
int ath10k_htt_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
int ret;
|
||||
|
||||
htt->ar = ar;
|
||||
htt->max_throughput_mbps = 800;
|
||||
|
||||
/*
|
||||
* Connect to HTC service.
|
||||
* This has to be done before calling ath10k_htt_rx_attach,
|
||||
* since ath10k_htt_rx_attach involves sending a rx ring configure
|
||||
* message to the target.
|
||||
*/
|
||||
ret = ath10k_htt_htc_attach(htt);
|
||||
if (ret) {
|
||||
ath10k_err("could not attach htt htc (%d)\n", ret);
|
||||
goto err_htc_attach;
|
||||
}
|
||||
|
||||
ret = ath10k_htt_tx_attach(htt);
|
||||
if (ret) {
|
||||
ath10k_err("could not attach htt tx (%d)\n", ret);
|
||||
goto err_htc_attach;
|
||||
}
|
||||
|
||||
ret = ath10k_htt_rx_attach(htt);
|
||||
if (ret) {
|
||||
ath10k_err("could not attach htt rx (%d)\n", ret);
|
||||
goto err_rx_attach;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prefetch enough data to satisfy target
|
||||
* classification engine.
|
||||
@@ -93,11 +68,6 @@ int ath10k_htt_attach(struct ath10k *ar)
|
||||
2; /* ip4 dscp or ip6 priority */
|
||||
|
||||
return 0;
|
||||
|
||||
err_rx_attach:
|
||||
ath10k_htt_tx_detach(htt);
|
||||
err_htc_attach:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ)
|
||||
@@ -117,7 +87,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_attach_target(struct ath10k_htt *htt)
|
||||
int ath10k_htt_setup(struct ath10k_htt *htt)
|
||||
{
|
||||
int status;
|
||||
|
||||
@@ -140,9 +110,3 @@ int ath10k_htt_attach_target(struct ath10k_htt *htt)
|
||||
|
||||
return ath10k_htt_send_rx_ring_cfg_ll(htt);
|
||||
}
|
||||
|
||||
void ath10k_htt_detach(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_htt_rx_detach(htt);
|
||||
ath10k_htt_tx_detach(htt);
|
||||
}
|
||||
|
||||
@@ -1328,14 +1328,16 @@ struct htt_rx_desc {
|
||||
#define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */
|
||||
#define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1)
|
||||
|
||||
int ath10k_htt_attach(struct ath10k *ar);
|
||||
int ath10k_htt_attach_target(struct ath10k_htt *htt);
|
||||
void ath10k_htt_detach(struct ath10k_htt *htt);
|
||||
int ath10k_htt_connect(struct ath10k_htt *htt);
|
||||
int ath10k_htt_init(struct ath10k *ar);
|
||||
int ath10k_htt_setup(struct ath10k_htt *htt);
|
||||
|
||||
int ath10k_htt_tx_alloc(struct ath10k_htt *htt);
|
||||
void ath10k_htt_tx_free(struct ath10k_htt *htt);
|
||||
|
||||
int ath10k_htt_rx_alloc(struct ath10k_htt *htt);
|
||||
void ath10k_htt_rx_free(struct ath10k_htt *htt);
|
||||
|
||||
int ath10k_htt_tx_attach(struct ath10k_htt *htt);
|
||||
void ath10k_htt_tx_detach(struct ath10k_htt *htt);
|
||||
int ath10k_htt_rx_attach(struct ath10k_htt *htt);
|
||||
void ath10k_htt_rx_detach(struct ath10k_htt *htt);
|
||||
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
|
||||
|
||||
@@ -225,10 +225,26 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg)
|
||||
ath10k_htt_rx_msdu_buff_replenish(htt);
|
||||
}
|
||||
|
||||
void ath10k_htt_rx_detach(struct ath10k_htt *htt)
|
||||
static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt)
|
||||
{
|
||||
int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld;
|
||||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < htt->rx_ring.size; i++) {
|
||||
skb = htt->rx_ring.netbufs_ring[i];
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
dma_unmap_single(htt->ar->dev, ATH10K_SKB_CB(skb)->paddr,
|
||||
skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
htt->rx_ring.netbufs_ring[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_htt_rx_free(struct ath10k_htt *htt)
|
||||
{
|
||||
del_timer_sync(&htt->rx_ring.refill_retry_timer);
|
||||
tasklet_kill(&htt->rx_replenish_task);
|
||||
tasklet_kill(&htt->txrx_compl_task);
|
||||
@@ -236,18 +252,7 @@ void ath10k_htt_rx_detach(struct ath10k_htt *htt)
|
||||
skb_queue_purge(&htt->tx_compl_q);
|
||||
skb_queue_purge(&htt->rx_compl_q);
|
||||
|
||||
while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) {
|
||||
struct sk_buff *skb =
|
||||
htt->rx_ring.netbufs_ring[sw_rd_idx];
|
||||
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
|
||||
|
||||
dma_unmap_single(htt->ar->dev, cb->paddr,
|
||||
skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(htt->rx_ring.netbufs_ring[sw_rd_idx]);
|
||||
sw_rd_idx++;
|
||||
sw_rd_idx &= htt->rx_ring.size_mask;
|
||||
}
|
||||
ath10k_htt_rx_ring_clean_up(htt);
|
||||
|
||||
dma_free_coherent(htt->ar->dev,
|
||||
(htt->rx_ring.size *
|
||||
@@ -277,6 +282,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
|
||||
|
||||
idx = htt->rx_ring.sw_rd_idx.msdu_payld;
|
||||
msdu = htt->rx_ring.netbufs_ring[idx];
|
||||
htt->rx_ring.netbufs_ring[idx] = NULL;
|
||||
|
||||
idx++;
|
||||
idx &= htt->rx_ring.size_mask;
|
||||
@@ -306,6 +312,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
int msdu_len, msdu_chaining = 0;
|
||||
struct sk_buff *msdu;
|
||||
struct htt_rx_desc *rx_desc;
|
||||
bool corrupted = false;
|
||||
|
||||
lockdep_assert_held(&htt->rx_ring.lock);
|
||||
|
||||
@@ -399,7 +406,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0),
|
||||
RX_MSDU_START_INFO0_MSDU_LENGTH);
|
||||
msdu_chained = rx_desc->frag_info.ring2_more_count;
|
||||
msdu_chaining = msdu_chained;
|
||||
|
||||
if (msdu_len_invalid)
|
||||
msdu_len = 0;
|
||||
@@ -427,11 +433,15 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
|
||||
msdu->next = next;
|
||||
msdu = next;
|
||||
msdu_chaining = 1;
|
||||
}
|
||||
|
||||
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
|
||||
RX_MSDU_END_INFO0_LAST_MSDU;
|
||||
|
||||
if (msdu_chaining && !last_msdu)
|
||||
corrupted = true;
|
||||
|
||||
if (last_msdu) {
|
||||
msdu->next = NULL;
|
||||
break;
|
||||
@@ -446,6 +456,20 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
if (*head_msdu == NULL)
|
||||
msdu_chaining = -1;
|
||||
|
||||
/*
|
||||
* Apparently FW sometimes reports weird chained MSDU sequences with
|
||||
* more than one rx descriptor. This seems like a bug but needs more
|
||||
* analyzing. For the time being fix it by dropping such sequences to
|
||||
* avoid blowing up the host system.
|
||||
*/
|
||||
if (corrupted) {
|
||||
ath10k_warn("failed to pop chained msdus, dropping\n");
|
||||
ath10k_htt_rx_free_msdu_chain(*head_msdu);
|
||||
*head_msdu = NULL;
|
||||
*tail_msdu = NULL;
|
||||
msdu_chaining = -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't refill the ring yet.
|
||||
*
|
||||
@@ -468,7 +492,7 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr)
|
||||
ath10k_htt_rx_msdu_buff_replenish(htt);
|
||||
}
|
||||
|
||||
int ath10k_htt_rx_attach(struct ath10k_htt *htt)
|
||||
int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
|
||||
{
|
||||
dma_addr_t paddr;
|
||||
void *vaddr;
|
||||
@@ -494,7 +518,7 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)
|
||||
htt->rx_ring.fill_level = ath10k_htt_rx_ring_fill_level(htt);
|
||||
|
||||
htt->rx_ring.netbufs_ring =
|
||||
kmalloc(htt->rx_ring.size * sizeof(struct sk_buff *),
|
||||
kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *),
|
||||
GFP_KERNEL);
|
||||
if (!htt->rx_ring.netbufs_ring)
|
||||
goto err_netbuf;
|
||||
@@ -754,17 +778,30 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
|
||||
static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct sk_buff *skb,
|
||||
enum htt_rx_mpdu_encrypt_type enctype)
|
||||
enum htt_rx_mpdu_encrypt_type enctype,
|
||||
enum rx_msdu_decap_format fmt,
|
||||
bool dot11frag)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
rx_status->flag &= ~(RX_FLAG_DECRYPTED |
|
||||
RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED);
|
||||
|
||||
if (enctype == HTT_RX_MPDU_ENCRYPT_NONE) {
|
||||
rx_status->flag &= ~(RX_FLAG_DECRYPTED |
|
||||
RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED);
|
||||
if (enctype == HTT_RX_MPDU_ENCRYPT_NONE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* There's no explicit rx descriptor flag to indicate whether a given
|
||||
* frame has been decrypted or not. We're forced to use the decap
|
||||
* format as an implicit indication. However fragmentation rx is always
|
||||
* raw and it probably never reports undecrypted raws.
|
||||
*
|
||||
* This makes sure sniffed frames are reported as-is without stripping
|
||||
* the protected flag.
|
||||
*/
|
||||
if (fmt == RX_MSDU_DECAP_RAW && !dot11frag)
|
||||
return;
|
||||
}
|
||||
|
||||
rx_status->flag |= RX_FLAG_DECRYPTED |
|
||||
RX_FLAG_IV_STRIPPED |
|
||||
@@ -918,7 +955,8 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
|
||||
}
|
||||
|
||||
skb_in = skb;
|
||||
ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype);
|
||||
ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype, fmt,
|
||||
false);
|
||||
skb = skb->next;
|
||||
skb_in->next = NULL;
|
||||
|
||||
@@ -1000,7 +1038,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
|
||||
break;
|
||||
}
|
||||
|
||||
ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype);
|
||||
ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype, fmt, false);
|
||||
|
||||
ath10k_process_rx(htt->ar, rx_status, skb);
|
||||
}
|
||||
@@ -1288,6 +1326,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
||||
}
|
||||
|
||||
/* FIXME: implement signal strength */
|
||||
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)msdu_head->data;
|
||||
rxd = (void *)msdu_head->data - sizeof(*rxd);
|
||||
@@ -1306,7 +1345,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
||||
|
||||
enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
|
||||
RX_MPDU_START_INFO0_ENCRYPT_TYPE);
|
||||
ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype);
|
||||
ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype, fmt,
|
||||
true);
|
||||
msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
|
||||
|
||||
if (tkip_mic_err)
|
||||
|
||||
@@ -83,7 +83,7 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
|
||||
__clear_bit(msdu_id, htt->used_msdu_ids);
|
||||
}
|
||||
|
||||
int ath10k_htt_tx_attach(struct ath10k_htt *htt)
|
||||
int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
|
||||
{
|
||||
spin_lock_init(&htt->tx_lock);
|
||||
init_waitqueue_head(&htt->empty_tx_wq);
|
||||
@@ -120,7 +120,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
|
||||
static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
struct htt_tx_done tx_done = {0};
|
||||
int msdu_id;
|
||||
@@ -141,9 +141,9 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_detach(struct ath10k_htt *htt)
|
||||
void ath10k_htt_tx_free(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_htt_tx_cleanup_pending(htt);
|
||||
ath10k_htt_tx_free_pending(htt);
|
||||
kfree(htt->pending_tx);
|
||||
kfree(htt->used_msdu_ids);
|
||||
dma_pool_destroy(htt->tx_pool);
|
||||
|
||||
@@ -54,7 +54,10 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
arg.key_cipher = WMI_CIPHER_AES_CCM;
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP)
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT;
|
||||
else
|
||||
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
arg.key_cipher = WMI_CIPHER_TKIP;
|
||||
@@ -1888,8 +1891,13 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
|
||||
wep_key_work);
|
||||
int ret, keyidx = arvif->def_wep_key_newidx;
|
||||
|
||||
mutex_lock(&arvif->ar->conf_mutex);
|
||||
|
||||
if (arvif->ar->state != ATH10K_STATE_ON)
|
||||
goto unlock;
|
||||
|
||||
if (arvif->def_wep_key_idx == keyidx)
|
||||
return;
|
||||
goto unlock;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
|
||||
arvif->vdev_id, keyidx);
|
||||
@@ -1902,10 +1910,13 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
|
||||
ath10k_warn("failed to update wep key index for vdev %d: %d\n",
|
||||
arvif->vdev_id,
|
||||
ret);
|
||||
return;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
arvif->def_wep_key_idx = keyidx;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&arvif->ar->conf_mutex);
|
||||
}
|
||||
|
||||
static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
||||
@@ -2286,9 +2297,19 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
||||
ath10k_tx_htt(ar, skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize various parameters with default vaules.
|
||||
*/
|
||||
/* Must not be called with conf_mutex held as workers can use that also. */
|
||||
static void ath10k_drain_tx(struct ath10k *ar)
|
||||
{
|
||||
/* make sure rcu-protected mac80211 tx path itself is drained */
|
||||
synchronize_net();
|
||||
|
||||
ath10k_offchan_tx_purge(ar);
|
||||
ath10k_mgmt_over_wmi_tx_purge(ar);
|
||||
|
||||
cancel_work_sync(&ar->offchan_tx_work);
|
||||
cancel_work_sync(&ar->wmi_mgmt_tx_work);
|
||||
}
|
||||
|
||||
void ath10k_halt(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
@@ -2303,19 +2324,12 @@ void ath10k_halt(struct ath10k *ar)
|
||||
}
|
||||
|
||||
del_timer_sync(&ar->scan.timeout);
|
||||
ath10k_offchan_tx_purge(ar);
|
||||
ath10k_mgmt_over_wmi_tx_purge(ar);
|
||||
ath10k_reset_scan((unsigned long)ar);
|
||||
ath10k_peer_cleanup_all(ar);
|
||||
ath10k_core_stop(ar);
|
||||
ath10k_hif_power_down(ar);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
if (ar->scan.in_progress) {
|
||||
del_timer(&ar->scan.timeout);
|
||||
ar->scan.in_progress = false;
|
||||
ieee80211_scan_completed(ar->hw, true);
|
||||
}
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
if (!arvif->beacon)
|
||||
continue;
|
||||
@@ -2329,46 +2343,125 @@ void ath10k_halt(struct ath10k *ar)
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->cfg_tx_chainmask) {
|
||||
*tx_ant = ar->cfg_tx_chainmask;
|
||||
*rx_ant = ar->cfg_rx_chainmask;
|
||||
} else {
|
||||
*tx_ant = ar->supp_tx_chainmask;
|
||||
*rx_ant = ar->supp_rx_chainmask;
|
||||
}
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
ar->cfg_tx_chainmask = tx_ant;
|
||||
ar->cfg_rx_chainmask = rx_ant;
|
||||
|
||||
if ((ar->state != ATH10K_STATE_ON) &&
|
||||
(ar->state != ATH10K_STATE_RESTARTED))
|
||||
return 0;
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask,
|
||||
tx_ant);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to set tx-chainmask: %d, req 0x%x\n",
|
||||
ret, tx_ant);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask,
|
||||
rx_ant);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to set rx-chainmask: %d, req 0x%x\n",
|
||||
ret, rx_ant);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
ret = __ath10k_set_antenna(ar, tx_ant, rx_ant);
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* This makes sense only when restarting hw. It is harmless to call
|
||||
* uncoditionally. This is necessary to make sure no HTT/WMI tx
|
||||
* commands will be submitted while restarting.
|
||||
*/
|
||||
ath10k_drain_tx(ar);
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_OFF &&
|
||||
ar->state != ATH10K_STATE_RESTARTING) {
|
||||
switch (ar->state) {
|
||||
case ATH10K_STATE_OFF:
|
||||
ar->state = ATH10K_STATE_ON;
|
||||
break;
|
||||
case ATH10K_STATE_RESTARTING:
|
||||
ath10k_halt(ar);
|
||||
ar->state = ATH10K_STATE_RESTARTED;
|
||||
break;
|
||||
case ATH10K_STATE_ON:
|
||||
case ATH10K_STATE_RESTARTED:
|
||||
case ATH10K_STATE_WEDGED:
|
||||
WARN_ON(1);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = ath10k_hif_power_up(ar);
|
||||
if (ret) {
|
||||
ath10k_err("Could not init hif: %d\n", ret);
|
||||
ar->state = ATH10K_STATE_OFF;
|
||||
goto exit;
|
||||
goto err_off;
|
||||
}
|
||||
|
||||
ret = ath10k_core_start(ar);
|
||||
if (ret) {
|
||||
ath10k_err("Could not init core: %d\n", ret);
|
||||
ath10k_hif_power_down(ar);
|
||||
ar->state = ATH10K_STATE_OFF;
|
||||
goto exit;
|
||||
goto err_power_down;
|
||||
}
|
||||
|
||||
if (ar->state == ATH10K_STATE_OFF)
|
||||
ar->state = ATH10K_STATE_ON;
|
||||
else if (ar->state == ATH10K_STATE_RESTARTING)
|
||||
ar->state = ATH10K_STATE_RESTARTED;
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_warn("failed to enable PMF QOS: %d\n", ret);
|
||||
goto err_core_stop;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_warn("failed to enable dynamic BW: %d\n", ret);
|
||||
goto err_core_stop;
|
||||
}
|
||||
|
||||
if (ar->cfg_tx_chainmask)
|
||||
__ath10k_set_antenna(ar, ar->cfg_tx_chainmask,
|
||||
ar->cfg_rx_chainmask);
|
||||
|
||||
/*
|
||||
* By default FW set ARP frames ac to voice (6). In that case ARP
|
||||
@@ -2384,14 +2477,25 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
||||
if (ret) {
|
||||
ath10k_warn("failed to set arp ac override parameter: %d\n",
|
||||
ret);
|
||||
goto exit;
|
||||
goto err_core_stop;
|
||||
}
|
||||
|
||||
ar->num_started_vdevs = 0;
|
||||
ath10k_regd_update(ar);
|
||||
ret = 0;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return 0;
|
||||
|
||||
err_core_stop:
|
||||
ath10k_core_stop(ar);
|
||||
|
||||
err_power_down:
|
||||
ath10k_hif_power_down(ar);
|
||||
|
||||
err_off:
|
||||
ar->state = ATH10K_STATE_OFF;
|
||||
|
||||
err:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
@@ -2400,19 +2504,15 @@ static void ath10k_stop(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
if (ar->state == ATH10K_STATE_ON ||
|
||||
ar->state == ATH10K_STATE_RESTARTED ||
|
||||
ar->state == ATH10K_STATE_WEDGED)
|
||||
ath10k_halt(ar);
|
||||
ath10k_drain_tx(ar);
|
||||
|
||||
ar->state = ATH10K_STATE_OFF;
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
if (ar->state != ATH10K_STATE_OFF) {
|
||||
ath10k_halt(ar);
|
||||
ar->state = ATH10K_STATE_OFF;
|
||||
}
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
ath10k_mgmt_over_wmi_tx_purge(ar);
|
||||
|
||||
cancel_work_sync(&ar->offchan_tx_work);
|
||||
cancel_work_sync(&ar->wmi_mgmt_tx_work);
|
||||
cancel_work_sync(&ar->restart_work);
|
||||
}
|
||||
|
||||
@@ -2925,7 +3025,12 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
arvif->u.ap.hidden_ssid = info->hidden_ssid;
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BSSID) {
|
||||
/*
|
||||
* Firmware manages AP self-peer internally so make sure to not create
|
||||
* it in driver. Otherwise AP self-peer deletion may timeout later.
|
||||
*/
|
||||
if (changed & BSS_CHANGED_BSSID &&
|
||||
vif->type != NL80211_IFTYPE_AP) {
|
||||
if (!is_zero_ether_addr(info->bssid)) {
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac vdev %d create peer %pM\n",
|
||||
@@ -4142,14 +4247,6 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
|
||||
fixed_nss, force_sgi);
|
||||
}
|
||||
|
||||
static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
/* there's no need to do anything here. vif->csa_active is enough */
|
||||
return;
|
||||
}
|
||||
|
||||
static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
@@ -4253,10 +4350,11 @@ static const struct ieee80211_ops ath10k_ops = {
|
||||
.set_frag_threshold = ath10k_set_frag_threshold,
|
||||
.flush = ath10k_flush,
|
||||
.tx_last_beacon = ath10k_tx_last_beacon,
|
||||
.set_antenna = ath10k_set_antenna,
|
||||
.get_antenna = ath10k_get_antenna,
|
||||
.restart_complete = ath10k_restart_complete,
|
||||
.get_survey = ath10k_get_survey,
|
||||
.set_bitrate_mask = ath10k_set_bitrate_mask,
|
||||
.channel_switch_beacon = ath10k_channel_switch_beacon,
|
||||
.sta_rc_update = ath10k_sta_rc_update,
|
||||
.get_tsf = ath10k_get_tsf,
|
||||
#ifdef CONFIG_PM
|
||||
@@ -4602,6 +4700,18 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
|
||||
/* TODO: Have to deal with 2x2 chips if/when the come out. */
|
||||
ar->supp_tx_chainmask = TARGET_10X_TX_CHAIN_MASK;
|
||||
ar->supp_rx_chainmask = TARGET_10X_RX_CHAIN_MASK;
|
||||
} else {
|
||||
ar->supp_tx_chainmask = TARGET_TX_CHAIN_MASK;
|
||||
ar->supp_rx_chainmask = TARGET_RX_CHAIN_MASK;
|
||||
}
|
||||
|
||||
ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
|
||||
ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;
|
||||
|
||||
if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features))
|
||||
ar->hw->wiphy->interface_modes |=
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
|
||||
@@ -59,6 +59,7 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
|
||||
|
||||
/* how long wait to wait for target to initialise, in ms */
|
||||
#define ATH10K_PCI_TARGET_WAIT 3000
|
||||
#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3
|
||||
|
||||
#define QCA988X_2_0_DEVICE_ID (0x003c)
|
||||
|
||||
@@ -761,17 +762,21 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
|
||||
struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl;
|
||||
struct ath10k_ce_ring *src_ring = ce_pipe->src_ring;
|
||||
unsigned int nentries_mask = src_ring->nentries_mask;
|
||||
unsigned int sw_index = src_ring->sw_index;
|
||||
unsigned int write_index = src_ring->write_index;
|
||||
int err, i;
|
||||
unsigned int nentries_mask;
|
||||
unsigned int sw_index;
|
||||
unsigned int write_index;
|
||||
int err, i = 0;
|
||||
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
|
||||
nentries_mask = src_ring->nentries_mask;
|
||||
sw_index = src_ring->sw_index;
|
||||
write_index = src_ring->write_index;
|
||||
|
||||
if (unlikely(CE_RING_DELTA(nentries_mask,
|
||||
write_index, sw_index - 1) < n_items)) {
|
||||
err = -ENOBUFS;
|
||||
goto unlock;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_items - 1; i++) {
|
||||
@@ -788,7 +793,7 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
items[i].transfer_id,
|
||||
CE_SEND_FLAG_GATHER);
|
||||
if (err)
|
||||
goto unlock;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* `i` is equal to `n_items -1` after for() */
|
||||
@@ -806,10 +811,15 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
items[i].transfer_id,
|
||||
0);
|
||||
if (err)
|
||||
goto unlock;
|
||||
goto err;
|
||||
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
for (; i > 0; i--)
|
||||
__ath10k_ce_send_revert(ce_pipe);
|
||||
|
||||
err = 0;
|
||||
unlock:
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
return err;
|
||||
}
|
||||
@@ -1271,6 +1281,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n");
|
||||
|
||||
if (WARN_ON(!ar_pci->started))
|
||||
return;
|
||||
|
||||
ret = ath10k_ce_disable_interrupts(ar);
|
||||
if (ret)
|
||||
ath10k_warn("failed to disable CE interrupts: %d\n", ret);
|
||||
@@ -1802,6 +1815,26 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
|
||||
ath10k_pci_sleep(ar);
|
||||
}
|
||||
|
||||
/* this function effectively clears target memory controller assert line */
|
||||
static void ath10k_pci_warm_reset_si0(struct ath10k *ar)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
|
||||
ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
|
||||
val | SOC_RESET_CONTROL_SI0_RST_MASK);
|
||||
val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
|
||||
|
||||
msleep(10);
|
||||
|
||||
val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
|
||||
ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
|
||||
val & ~SOC_RESET_CONTROL_SI0_RST_MASK);
|
||||
val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
|
||||
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static int ath10k_pci_warm_reset(struct ath10k *ar)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1860,6 +1893,8 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
|
||||
SOC_RESET_CONTROL_ADDRESS);
|
||||
msleep(10);
|
||||
|
||||
ath10k_pci_warm_reset_si0(ar);
|
||||
|
||||
/* debug */
|
||||
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
|
||||
PCIE_INTR_CAUSE_ADDRESS);
|
||||
@@ -1988,6 +2023,28 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_pci_hif_power_up_warm(struct ath10k *ar)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
/*
|
||||
* Sometime warm reset succeeds after retries.
|
||||
*
|
||||
* FIXME: It might be possible to tune ath10k_pci_warm_reset() to work
|
||||
* at first try.
|
||||
*/
|
||||
for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) {
|
||||
ret = __ath10k_pci_hif_power_up(ar, false);
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n",
|
||||
i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_pci_hif_power_up(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
@@ -1999,10 +2056,10 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
|
||||
* preferred (and safer) way to perform a device reset is through a
|
||||
* warm reset.
|
||||
*
|
||||
* Warm reset doesn't always work though (notably after a firmware
|
||||
* crash) so fall back to cold reset if necessary.
|
||||
* Warm reset doesn't always work though so fall back to cold reset may
|
||||
* be necessary.
|
||||
*/
|
||||
ret = __ath10k_pci_hif_power_up(ar, false);
|
||||
ret = ath10k_pci_hif_power_up_warm(ar);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to power up target using warm reset: %d\n",
|
||||
ret);
|
||||
@@ -2196,10 +2253,7 @@ static void ath10k_pci_early_irq_tasklet(unsigned long data)
|
||||
if (fw_ind & FW_IND_EVENT_PENDING) {
|
||||
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
|
||||
fw_ind & ~FW_IND_EVENT_PENDING);
|
||||
|
||||
/* Some structures are unavailable during early boot or at
|
||||
* driver teardown so just print that the device has crashed. */
|
||||
ath10k_warn("device crashed - no diagnostics available\n");
|
||||
ath10k_pci_hif_dump_area(ar);
|
||||
}
|
||||
|
||||
ath10k_pci_sleep(ar);
|
||||
@@ -2476,6 +2530,9 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
|
||||
|
||||
if (val & FW_IND_EVENT_PENDING) {
|
||||
ath10k_warn("device has crashed during init\n");
|
||||
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
|
||||
val & ~FW_IND_EVENT_PENDING);
|
||||
ath10k_pci_hif_dump_area(ar);
|
||||
ret = -ECOMM;
|
||||
goto out;
|
||||
}
|
||||
@@ -2602,18 +2659,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
|
||||
pci_set_drvdata(pdev, ar);
|
||||
|
||||
/*
|
||||
* Without any knowledge of the Host, the Target may have been reset or
|
||||
* power cycled and its Config Space may no longer reflect the PCI
|
||||
* address space that was assigned earlier by the PCI infrastructure.
|
||||
* Refresh it now.
|
||||
*/
|
||||
ret = pci_assign_resource(pdev, BAR_NUM);
|
||||
if (ret) {
|
||||
ath10k_err("failed to assign PCI space: %d\n", ret);
|
||||
goto err_ar;
|
||||
}
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
ath10k_err("failed to enable PCI device: %d\n", ret);
|
||||
@@ -2725,8 +2770,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
|
||||
if (!ar_pci)
|
||||
return;
|
||||
|
||||
tasklet_kill(&ar_pci->msi_fw_err);
|
||||
|
||||
ath10k_core_unregister(ar);
|
||||
ath10k_pci_free_ce(ar);
|
||||
|
||||
|
||||
@@ -639,6 +639,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
|
||||
struct sk_buff *wmi_skb;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
int len;
|
||||
u32 buf_len = skb->len;
|
||||
u16 fc;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
@@ -648,6 +649,15 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
|
||||
return -EINVAL;
|
||||
|
||||
len = sizeof(cmd->hdr) + skb->len;
|
||||
|
||||
if ((ieee80211_is_action(hdr->frame_control) ||
|
||||
ieee80211_is_deauth(hdr->frame_control) ||
|
||||
ieee80211_is_disassoc(hdr->frame_control)) &&
|
||||
ieee80211_has_protected(hdr->frame_control)) {
|
||||
len += IEEE80211_CCMP_MIC_LEN;
|
||||
buf_len += IEEE80211_CCMP_MIC_LEN;
|
||||
}
|
||||
|
||||
len = round_up(len, 4);
|
||||
|
||||
wmi_skb = ath10k_wmi_alloc_skb(len);
|
||||
@@ -659,7 +669,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
|
||||
cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id);
|
||||
cmd->hdr.tx_rate = 0;
|
||||
cmd->hdr.tx_power = 0;
|
||||
cmd->hdr.buf_len = __cpu_to_le32((u32)(skb->len));
|
||||
cmd->hdr.buf_len = __cpu_to_le32(buf_len);
|
||||
|
||||
memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN);
|
||||
memcpy(cmd->buf, skb->data, skb->len);
|
||||
@@ -957,10 +967,16 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
* frames with Protected Bit set. */
|
||||
if (ieee80211_has_protected(hdr->frame_control) &&
|
||||
!ieee80211_is_auth(hdr->frame_control)) {
|
||||
status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
hdr->frame_control = __cpu_to_le16(fc &
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
|
||||
if (!ieee80211_is_action(hdr->frame_control) &&
|
||||
!ieee80211_is_deauth(hdr->frame_control) &&
|
||||
!ieee80211_is_disassoc(hdr->frame_control)) {
|
||||
status->flag |= RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
hdr->frame_control = __cpu_to_le16(fc &
|
||||
~IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MGMT,
|
||||
@@ -2359,7 +2375,7 @@ void ath10k_wmi_detach(struct ath10k *ar)
|
||||
ar->wmi.num_mem_chunks = 0;
|
||||
}
|
||||
|
||||
int ath10k_wmi_connect_htc_service(struct ath10k *ar)
|
||||
int ath10k_wmi_connect(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
|
||||
@@ -2323,9 +2323,9 @@ struct wmi_pdev_param_map {
|
||||
#define WMI_PDEV_PARAM_UNSUPPORTED 0
|
||||
|
||||
enum wmi_pdev_param {
|
||||
/* TX chian mask */
|
||||
/* TX chain mask */
|
||||
WMI_PDEV_PARAM_TX_CHAIN_MASK = 0x1,
|
||||
/* RX chian mask */
|
||||
/* RX chain mask */
|
||||
WMI_PDEV_PARAM_RX_CHAIN_MASK,
|
||||
/* TX power limit for 2G Radio */
|
||||
WMI_PDEV_PARAM_TXPOWER_LIMIT2G,
|
||||
@@ -4259,7 +4259,7 @@ void ath10k_wmi_detach(struct ath10k *ar);
|
||||
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);
|
||||
int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
|
||||
|
||||
int ath10k_wmi_connect_htc_service(struct ath10k *ar);
|
||||
int ath10k_wmi_connect(struct ath10k *ar);
|
||||
int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
|
||||
const struct wmi_channel_arg *);
|
||||
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
|
||||
|
||||
@@ -770,6 +770,7 @@ struct ath_softc {
|
||||
struct ath_ant_comb ant_comb;
|
||||
u8 ant_tx, ant_rx;
|
||||
struct dfs_pattern_detector *dfs_detector;
|
||||
u64 dfs_prev_pulse_ts;
|
||||
u32 wow_enabled;
|
||||
/* relay(fs) channel for spectral scan */
|
||||
struct rchan *rfs_chan_spec_scan;
|
||||
|
||||
@@ -178,14 +178,12 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
|
||||
pe.ts = mactime;
|
||||
if (ath9k_postprocess_radar_event(sc, &ard, &pe)) {
|
||||
struct dfs_pattern_detector *pd = sc->dfs_detector;
|
||||
#ifdef CONFIG_ATH9K_DEBUGFS
|
||||
ath_dbg(common, DFS,
|
||||
"ath9k_dfs_process_phyerr: channel=%d, ts=%llu, "
|
||||
"width=%d, rssi=%d, delta_ts=%llu\n",
|
||||
pe.freq, pe.ts, pe.width, pe.rssi,
|
||||
pe.ts - sc->debug.stats.dfs_stats.last_ts);
|
||||
sc->debug.stats.dfs_stats.last_ts = pe.ts;
|
||||
#endif
|
||||
pe.ts - sc->dfs_prev_pulse_ts);
|
||||
sc->dfs_prev_pulse_ts = pe.ts;
|
||||
DFS_STAT_INC(sc, pulses_processed);
|
||||
if (pd != NULL && pd->add_pulse(pd, &pe)) {
|
||||
DFS_STAT_INC(sc, radar_detected);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user